Wiksiyonaryo tlwiktionary https://tl.wiktionary.org/wiki/Wiksiyonaryo:Unang_Pahina MediaWiki 1.47.0-wmf.24 case-sensitive Midya Natatangi Usapan Tagagamit Usapang tagagamit Wiksiyonaryo Usapang Wiksiyonaryo Talaksan Usapang talaksan MediaWiki Usapang MediaWiki Padron Usapang padron Tulong Usapang tulong Kategorya Usapang kategorya TimedText TimedText talk Module Module talk Event Event talk Wiksiyonaryo:Main Page 4 31580 178447 157242 2026-10-26T23:36:48Z ᜏᜒᜃᜈᜒᜄᜐᜒᜈᜃ᜕ 5686 Ikinakarga sa [[Wiksiyonaryo:Unang Pahina]] 178447 wikitext text/x-wiki #REDIRECT [[Wiksiyonaryo:Unang Pahina]] 4ywjtseuo5xvtxrzubeg12hfhbjs9yg Module:languages/data/3/m 828 32628 178459 175590 2026-10-27T01:50:45Z GinawaSaHapon 3989 178459 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["maa"] = { "San Jerónimo Tecóatl Mazatec", 7692927, "omq-maz", "Latn", } m["mab"] = { "Yutanduchi Mixtec", 12645448, "omq-mxt", "Latn", } m["mad"] = { "Madurese", 36213, "poz-msa", "Latn, Java", } m["mae"] = { "Bo-Rukul", 34967, "nic-ple", "Latn", } m["maf"] = { "Mafa", 35819, "cdc-cbm", "Latn", } m["mag"] = { "Magahi", -- Not to be confused with Magadhi Prakrit (pra-mag) 33728, "inc-bih", "Deva, Kthi", translit = { Deva = "bho-translit", Kthi = "bho-Kthi-translit", }, } m["mai"] = { "Maithili", 36109, "inc-bih", "Deva, Tirh, Kthi, Newa", translit = { Deva = "mai-translit", Tirh = "mai-Tirh-translit", Kthi = "bho-Kthi-translit", }, } m["maj"] = { "Jalapa de Díaz Mazatec", 3915999, "omq-maz", "Latn", } m["mak"] = { "Makasar", 33643, "poz-ssw", "Latn, Bugi, Maka", } m["mam"] = { "Mam", 33467, "myn", "Latn", } m["man"] = { "Mandingo", 35772, "dmn-man", "Latn", } m["maq"] = { "Chiquihuitlán Mazatec", 5101757, "omq-maz", "Latn", } m["mas"] = { "Maasai", 35787, "sdv-lma", "Latn", } m["mat"] = { "Matlatzinca", 12953704, "omq", "Latn", } m["mau"] = { "Huautla Mazatec", 36230, "omq-maz", "Latn", } m["mav"] = { "Sateré-Mawé", 6794475, "tup", "Latn", } m["maw"] = { "Mampruli", 35804, "nic-wov", "Latn", } m["max"] = { "North Moluccan Malay", 7056136, "crp", "Latn", ancestors = "ms", } m["maz"] = { "Central Mazahua", 36228, "oto", "Latn", } m["mba"] = { "Higaunon", --"Higaonon", 5753411, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/higaunon/", --TLCHANGE english_name = "Higaonon", --TLCHANGE } m["mbb"] = { "Menuvu", --"Western Bukidnon Manobo", 7987643, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/menuvu/", --TLCHANGE english_name = "Western Bukidnon Manobo", --TLCHANGE } m["mbc"] = { "Macushi", 56633, "sai-pem", "Latn", } m["mbd"] = { "Manobo Dibabawon", --"Dibabawon Manobo", 18755523, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-dibabawon/", --TLCHANGE english_name = "Dibabawon Manobo", --TLCHANGE } m["mbe"] = { "Molale", 3319444, "nai-plp", "Latn", } m["mbf"] = { "Baba Malay", 18642798, "crp", "Latn", ancestors = "ms", } m["mbh"] = { "Mangseng", 6749147, "poz-ocw", "Latn", } m["mbi"] = { "Manobo Ilyanen", --"Ilianen Manobo", 14916911, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-ilyanen/", --TLCHANGE english_name = "Ilianen Manobo", --TLCHANGE } m["mbj"] = { "Nadëb", 3335011, "sai-nad", "Latn", } m["mbk"] = { "Malol", 6744477, "poz-ocw", "Latn", } m["mbl"] = { "Maxakalí", 3029682, "sai-mje", "Latn", } m["mbm"] = { "Ombamba", 36407, "bnt-mbt", "Latn", } m["mbn"] = { "Macaguán", 3273980, "sai-guh", "Latn", } m["mbo"] = { -- is, like 'bqz', 'bsi' and 'bss', a dialect of Manenguba "Mbo (Cameroon)", 36011, "bnt-mne", "Latn", } m["mbp"] = { "Wiwa", 3012604, "cba", "Latn", } m["mbq"] = { "Maisin", 3448149, nil, "Latn", } m["mbr"] = { "Nukak Makú", 3346228, "sai-nad", "Latn", } m["mbs"] = { "Manobo Saranggani", --"Sarangani Manobo", 7423093, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-saranggani/", --TLCHANGE english_name = "Sarangani Manobo", --TLCHANGE } m["mbt"] = { "Manobo Matigsalug", --"Matigsalug Manobo", 6787447, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-matigsalug/", --TLCHANGE english_name = "Matigsalug Manobo", --TLCHANGE } m["mbu"] = { "Mbula-Bwazza", 3913324, "nic-jrn", "Latn", } m["mbv"] = { "Mbulungish", 36003, "alv-nal", "Latn", } m["mbw"] = { "Maring", 3293280, "ngf-jim", "Latn", } m["mbx"] = { "Mari (Sepik)", 6760942, "paa-sep", "Latn", } m["mby"] = { "Memoni", 4180871, "inc-snd", "Gujr, ur-Arab", } m["mbz"] = { "Amoltepec Mixtec", 13583504, "omq-mxt", "Latn", } m["mca"] = { "Maca", 3281043, "sai-mtc", "Latn", } m["mcb"] = { "Machiguenga", 3915441, "awd", "Latn", } m["mcc"] = { "Bitur", 4919173, "paa-tir", "Latn", } m["mcd"] = { "Sharanahua", 12953881, "sai-pan", "Latn", } m["mce"] = { "Itundujia Mixtec", 12953727, "omq-mxt", "Latn", } m["mcf"] = { "Matsés", 2981620, "sai-pan", "Latn", } m["mcg"] = { "Mapoyo", 56946, "sai-map", "Latn", } m["mch"] = { "Ye'kwana", 3082027, "sai-car", "Latn", sort_key = { remove_diacritics = "%-%s", from = {"'", "ñ", "ö", "sh", "ü"}, to = {"’", "n" .. p[1], "o" .. p[1], "s" .. p[1], "u" .. p[1]} } } m["mci"] = { "Mese", 6821190, "ngf-san", "Latn", } m["mcj"] = { "Mvanip", 3913281, "nic-mmb", "Latn", } m["mck"] = { "Mbunda", 34170, "bnt-clu", "Latn", } m["mcl"] = { "Macaguaje", 6722435, "sai-tuc", "Latn", } m["mcm"] = { "Kristang", 2669169, "crp", "Latn", ancestors = "pt", } m["mcn"] = { "Masana", 56668, "cdc-mas", } m["mco"] = { "Coatlán Mixe", 25559716, "nai-miz", "Latn", } m["mcp"] = { "Makaa", 35803, "bnt-mka", } m["mcq"] = { "Ese", 5397551, "ngf-koi", "Latn", } m["mcr"] = { "Menya", 11732444, "ngf-kme", "Latn", } m["mcs"] = { "Mambai", 6748872, "alv-mbm", } m["mcu"] = { "Cameroon Mambila", 19359039, "nic-mmb", "Latn", } -- mcv (Minanibai) merged into ffi (Foia Foia) per Glottolog m["mcw"] = { "Mawa", 3441333, "cdc-est", "Latn", } m["mcx"] = { "Mpiemo", 35908, "bnt-bek", } m["mcy"] = { "South Watut", 12953293, "poz-ocw", "Latn", } m["mcz"] = { "Mawan", 11732429, "ngf-han", "Latn", } m["mda"] = { "Mada (Nigeria)", 3915843, "nic-nin", "Latn", } m["mdb"] = { "Morigi", 6912195, "paa-kiw", "Latn", } m["mdc"] = { "Male", 6742927, "ngf-min", "Latn", } m["mdd"] = { "Mbum", 36170, "alv-mbm", } m["mde"] = { "Bura Mabang", 35860, "ssa", "Arab, Latn", } m["mdf"] = { "Moksha", 13343, "urj-mdv", "Cyrl", translit = "mdf-translit", strip_diacritics = {remove_diacritics = c.acute}, override_translit = true, sort_key = "mdf-sortkey", } m["mdg"] = { "Massalat", 759984, } m["mdh"] = { "Magindanawon", --"Maguindanao", 33717, "phi", "Latn, Arab", is_official_kwf_name = "https://kwfwikaatkultura.ph/magindanawon/", --TLCHANGE english_name = "Maguindanao", --TLCHANGE } m["mdi"] = { "Mamvu", 3033594, "csu-mle", } m["mdj"] = { "Mangbetu", 56327, "csu-maa", "Latn", } m["mdk"] = { "Mangbutu", 6748877, "csu-mle", } m["mdl"] = { "Maltese Sign Language", 6744816, "sgn", } m["mdm"] = { "Mayogo", 6797580, "nic-nke", "Latn", } m["mdn"] = { "Mbati", 36165, "bnt-ngn", } m["mdp"] = { "Mbala", 6799583, "bnt-pen", } m["mdq"] = { "Mbole", 6799727, "bnt-mbe", } m["mdr"] = { "Mandar", 35995, "poz-ssw", "Bugi, Latn", } m["mds"] = { "Maria", 3448673, "paa-man", "Latn", } m["mdt"] = { "Mbere", 36062, "bnt-mbt", } m["mdu"] = { "Mboko", 36058, "bnt-mbo", } m["mdv"] = { "Santa Lucía Monteverde Mixtec", 12953722, "omq-mxt", "Latn", } m["mdw"] = { "Mbosi", 36035, "bnt-mbo", } m["mdx"] = { "Dizin", 35313, "omv-diz", "Ethi, Latn", } m["mdy"] = { "Maale", 795327, "omv-ome", } m["mdz"] = { "Suruí Do Pará", 10322149, "tup-gua", "Latn", } m["mea"] = { "Menka", 36078, "nic-grs", "Latn", } m["meb"] = { "Ikobi-Mena", 11732241, "paa-tki", "Latn", } m["mec"] = { "Mara", 6772774, } m["med"] = { "Melpa", 36166, "ngf-hag", "Latn", } m["mee"] = { "Mengen", 3305831, "poz-ocw", "Latn", } m["mef"] = { "Megam", 6808589, } m["meh"] = { "Southwestern Tlaxiaco Mixtec", 7070686, "omq-mxt", "Latn", } m["mei"] = { "Midob", 36007, "nub", "Latn", } m["mej"] = { "Meyah", 11732436, "paa-ebh", "Latn", } m["mek"] = { "Mekeo", 3304803, "poz-ocw", "Latn", } m["mel"] = { "Central Melanau", 18638319, "poz-swa", "Latn", } m["mem"] = { "Mangala", 6748664, } m["men"] = { "Mende (Sierra Leone)", 1478672, "dmn-msw", "Latn, Mend", } m["meo"] = { "Kedah Malay", 4925684, "poz-mly", "Latn, ms-Arab, Thai", strip_diacritics = { from = {u(0xF70F)}, to = {"ญ"} }, sort_key = {Thai = "Thai-sortkey"}, } m["mep"] = { "Miriwoong", 3111847, "aus-jar", "Latn", } m["meq"] = { "Merey", 3502314, "cdc-cbm", "Latn", } m["mer"] = { "Meru", 13313, "bnt-kka", "Latn", } m["mes"] = { "Masmaje", 3440448, } m["met"] = { "Mato", 3299190, "poz-ocw", "Latn", } m["meu"] = { "Motu", 33516, "poz-ocw", "Latn", } m["mev"] = { "Mano", 3913286, "dmn-mda", "Latn", } m["mew"] = { "Maaka", 3438764, "cdc-wst", "Latn", } m["mey"] = { "Hassaniya Arabic", 56231, "sem-arb", "Arab", } m["mez"] = { "Menominee", 13363, "alg", "Latn", sort_key = {remove_diacritics = "·"}, } m["mfa"] = { "Pattani Malay", 1199751, "poz-mly", "Latn, ms-Arab, Thai", strip_diacritics = { from = {u(0xF70F)}, to = {"ญ"} }, sort_key = {Thai = "Thai-sortkey"}, } m["mfb"] = { "Bangka", 3258818, "poz-mly", "Latn, Arab", } m["mfc"] = { "Mba", 4286464, "nic-mbc", "Latn", } m["mfd"] = { "Mendankwe-Nkwen", 11129537, "nic-nge", "Latn", } m["mfe"] = { "Mauritian Creole", 33661, "crp", "Latn", ancestors = "fr", sort_key = s["roa-oil-sortkey"], } m["mff"] = { "Naki", 36083, "nic-bbe", "Latn", } m["mfg"] = { "Mixifore", 3914478, "dmn-mok", } m["mfh"] = { "Matal", 3501751, "cdc-cbm", "Latn", } m["mfi"] = { "Wandala", 3441249, "cdc-cbm", "Latn", } m["mfj"] = { "Mefele", 3501871, "cdc-cbm", } m["mfk"] = { "North Mofu", 56303, "cdc-cbm", "Latn", } m["mfl"] = { "Putai", 56291, } m["mfm"] = { "Marghi South", 56248, } m["mfn"] = { "Cross River Mbembe", 3915395, "nic-uce", "Latn", } m["mfo"] = { "Mbe", 36075, "nic-eko", "Latn", } m["mfp"] = { "Makassar Malay", 12952776, "qfa-mix", "Latn", ancestors = "ms, mak" } m["mfq"] = { "Moba", 19921578, "nic-grm", "Latn", } m["mfr"] = { "Marrithiyel", 6773014, "aus-dal", "Latn", } m["mfs"] = { "Mexican Sign Language", 3915511, "sgn", "Latn", -- when documented } m["mft"] = { "Mokerang", 3319387, "poz-aay", "Latn", } m["mfu"] = { "Mbwela", 11004988, "bnt-clu", ancestors = "lch", } m["mfv"] = { "Mandjak", 35822, "alv-pap", } m["mfw"] = { "Mulaha", 6933720, "paa-kwa", "Latn", } m["mfx"] = { "Melo", 6813268, "omv-nom", } m["mfy"] = { "Mayo", 56729, "azc-trc", "Latn", sort_key = {remove_diacritics = c.acute}, } m["mfz"] = { "Mabaan", 20526385, "sdv", "Latn", } m["mga"] = { "Middle Irish", 36116, "cel-gae", "Latn", ancestors = "sga", strip_diacritics = {remove_diacritics = c.dotabove .. c.diaer .. "·"}, sort_key = "mga-sortkey", } m["mgb"] = { "Mararit", 56359, "sdv-tmn", } m["mgc"] = { "Morokodo", 6913216, "csu-bbk", "Latn", } m["mgd"] = { "Moru", 6915014, "csu-mma", "Latn, Arab", } m["mge"] = { "Mango", 713659, "csu-sar", "Latn", } m["mgf"] = { "Maklew", 6739816, "paa-bul", "Latn", } m["mgg"] = { "Mpongmpong", 35924, "bnt-bek", } m["mgh"] = { "Makhuwa-Meetto", 33604, "bnt-mak", "Latn", ancestors = "vmw", } m["mgi"] = { "Jili", 3914497, "nic-pls", } m["mgj"] = { "Abureni", 3441256, "nic-cde", "Latn", } m["mgk"] = { "Mawes", 6794395, "qfa-dis", -- Papuan; isolate in Glottolog, Foley (2018) and Hammarström (2010); in the Tor-Kwerba languages per -- Usher (2020) "Latn", } m["mgl"] = { "Maleu-Kilenge", 3281884, } m["mgm"] = { "Mambae", 35774, "poz-tim", "Latn", } m["mgn"] = { "Mbangi", 11017443, "nic-ngd", "Latn", } m["mgo"] = { "Meta'", 36054, "nic-mom", "Latn", } m["mgp"] = { "Eastern Magar", 12952758, "sit-gma", "Deva, Latn", } m["mgq"] = { "Malila", 6743679, "bnt-mby", "Latn", } m["mgr"] = { "Mambwe-Lungu", 626210, "bnt-mwi", "Latn", } m["mgs"] = { "Manda (Tanzania)", 16939267, "bnt-bki", } m["mgt"] = { "Mwakai", 11260674, "paa-wke", "Latn", } m["mgu"] = { "Mailu", 3278246, "paa-mal", "Latn", } m["mgv"] = { "Matengo", 6786446, "bnt-mbi", "Latn", } m["mgw"] = { "Matumbi", 6791974, "bnt-mbi", "Latn", } m["mgy"] = { "Mbunga", 6799817, "bnt-kil", } m["mgz"] = { "Mbugwe", 3426367, "bnt-mra", } m["mha"] = { "Manda (India)", 56760, "dra-kki", "Orya", translit = "kxv-translit", } m["mhb"] = { "Mahongwe", 35816, "bnt-kel", } m["mhc"] = { "Mocho", 1941682, "myn", } m["mhd"] = { "Mbugu", 36152, "qfa-mix", "Latn", ancestors = "asa", } m["mhe"] = { "Besisi", 2742262, "mkh-asl", "Latn", } m["mhf"] = { "Mamaa", 6745346, "ngf-era", "Latn", } m["mhg"] = { "Marrgu", 6772812, } m["mhi"] = { "Ma'di", 56670, "csu-mma", "Latn", strip_diacritics = {remove_diacritics = c.acute .. c.grave .. c.tilde .. c.dotbelow}, } m["mhj"] = { "Mogholi", 13336, "xgn", "fa-Arab, Latn", translit = "fa-cls-translit", strip_diacritics = { ["fa-Arab"] = "ar-stripdiacritics", }, } m["mhk"] = { "Mungaka", 36068, "nic-nun", } m["mhl"] = { "Mauwake", 6794095, "ngf-kum", "Latn", } m["mhm"] = { "Makhuwa-Moniga", 6900145, "bnt-mak", } m["mhn"] = { "Mòcheno", 268130, "gmw-hgm", "Latn", ancestors = "bar", sort_key = {remove_diacritics = c.grave}, } m["mho"] = { "Mashi", 10962737, "bnt-kav", "Latn", } m["mhp"] = { "Balinese Malay", 12473441, "crp", "Latn, Bali, ms-Arab", } m["mhq"] = { "Mandan", 1957120, "sio", "Latn", } m["mhr"] = { "Eastern Mari", 3906614, "chm", "Cyrl", translit = "chm-translit", override_translit = true, strip_diacritics = {remove_diacritics = c.grave .. c.acute}, sort_key = { from = {"ё", "ҥ", "ӧ", "ӱ"}, to = {"е" .. p[1], "н" .. p[1], "о" .. p[1], "у" .. p[1]} } } m["mhs"] = { "Buru (Indonesia)", 2928650, "poz-cma", "Latn", } m["mht"] = { "Mandahuaca", 6747924, "awd-nwk", } m["mhu"] = { "Taraon", 56400, "sit-gsi", "Latn", } m["mhw"] = { "Mbukushu", 2691548, "bnt", "Latn", } m["mhx"] = { "Lhao Vo", 11149315, "tbq-brm", "Latn", } m["mhy"] = { "Ma'anyan", 2328761, "poz-bre", "Latn", } m["mhz"] = { "Mor (Austronesian)", 2122792, "poz-hce", "Latn", } m["mia"] = { "Miami", 56523, "alg", "Latn", } m["mib"] = { "Atatláhuca Mixtec", 32093046, "omq-mxt", "Latn", } m["mic"] = { "Mi'kmaq", 13321, "alg-eas", "Latn", } m["mid"] = { "Mandaic", 6991742, "sem-ase", "Mand", ancestors = "myz", translit = { Mand = "Mand-translit", }, strip_diacritics = { Mand = "Mand-stripdiacritics", } } m["mie"] = { "Ocotepec Mixtec", 25559575, "omq-mxt", "Latn", } m["mif"] = { "Mofu-Gudur", 1365132, "cdc-cbm", "Latn", } m["mig"] = { "San Miguel el Grande Mixtec", 12953719, "omq-mxt", "Latn", } m["mih"] = { "Chayuco Mixtec", 13583510, "omq-mxt", "Latn", } m["mii"] = { "Chigmecatitlán Mixtec", 12953724, "omq-mxt", "Latn", } m["mij"] = { "Mungbam", 34725, "nic-beb", "Latn", } m["mik"] = { "Mikasuki", 13316, "nai-mus", "Latn", } m["mil"] = { "Peñoles Mixtec", 42411307, "omq-mxt", "Latn", } m["mim"] = { "Alacatlatzala Mixtec", 14697894, "omq-mxt", "Latn", } m["min"] = { "Minangkabau", 13324, "poz-mly", "Latn, Arab", } m["mio"] = { "Pinotepa Nacional Mixtec", 7196415, "omq-mxt", "Latn", } m["mip"] = { "Apasco-Apoala Mixtec", 13583505, "omq-mxt", "Latn", } m["miq"] = { "Miskito", 1516803, "nai-min", "Latn", strip_diacritics = {remove_diacritics = c.circ}, } m["mir"] = { "Isthmus Mixe", 6088873, "nai-miz", "Latn", } m["mit"] = { "Southern Puebla Mixtec", 7570345, "omq-mxt", "Latn", } m["miu"] = { "Cacaloxtepec Mixtec", 12953723, "omq-mxt", "Latn", } m["miw"] = { "Akoye", 3327462, "ngf-taa", "Latn", } m["mix"] = { "Mixtepec Mixtec", 6884125, "omq-mxt", "Latn", } m["miy"] = { "Ayutla Mixtec", 13583508, "omq-mxt", "Latn", } m["miz"] = { "Coatzospan Mixtec", 3317290, "omq-mxt", "Latn", } m["mjb"] = { "Makalero", 35729, "paa-alp", "Latn", } m["mjc"] = { "San Juan Colorado Mixtec", 12953718, "omq-mxt", "Latn", } m["mjd"] = { "Northwest Maidu", 3198700, "nai-mdu", "Latn", } m["mje"] = { "Muskum", 3913334, } -- mjg "Monguor" is not recognized as a language, but it is a family code m["mji"] = { "Kim Mun", 1115317, "hmx-mie", "Latn", } m["mjj"] = { "Mawak", 11732427, "ngf-tib", "Latn", } m["mjk"] = { "Matukar", 6791963, "poz-ocw", "Latn", } m["mjl"] = { "Mandeali", 6747931, "him", "Deva, Takr", translit = "hi-translit", } m["mjm"] = { "Medebur", 6805227, "poz-ocw", "Latn", } m["mjn"] = { "Mebu", 6804364, "ngf-yup", "Latn", } m["mjo"] = { "Malankuravan", 14916887, "dra-mal", } m["mjp"] = { "Malapandaram", 10575729, "dra-tam", } m["mjq"] = { "Malaryan", 12952773, "dra-mal", } m["mjr"] = { "Malavedan", 12952775, "dra-mal", "Mlym", -- Mlym translit in [[Module:scripts/data]] } m["mjs"] = { "Miship", 3441264, "cdc-wst", "Latn", } m["mjt"] = { "Sawriya Paharia", 33907, "dra-mlo", "Beng, Deva", } m["mju"] = { "Manna-Dora", 10576453, "dra-tel", } m["mjv"] = { "Mannan", 3286037, "dra-tam", "Mlym, Taml", translit = { Taml = "ta-translit", }, -- Mlym translit in [[Module:scripts/data]] } m["mjw"] = { "Karbi", 56591, "tbq-kuk", "Latn", } m["mjx"] = { "Mahali", 12953686, "mun", } m["mjy"] = { "Mahican", 3182562, "alg-eas", "Latn", } m["mjz"] = { "Majhi", 6737786, "inc-bih", } m["mka"] = { "Mbre", 3450154, "nic", --unclassified within niger-congo tho } m["mkb"] = { "Mal Paharia", 6583595, "inc-eas", "Deva", } m["mkc"] = { "Siliput", 7515090, "paa-mam", "Latn", } m["mke"] = { "Mawchi", 21403317, } m["mkf"] = { "Miya", 43328, "cdc-wst", "Latn", } m["mkg"] = { "Mak (China)", 3280623, "qfa-kms", } m["mki"] = { "Dhatki", 32480, "raj", "Deva, Mahj, Arab", } m["mkj"] = { "Mokilese", 2335528, "poz-mic", "Latn", } m["mkk"] = { "Byep", 35052, "bnt-mka", } m["mkl"] = { "Mokole", 36047, "alv-yor", "Latn", } m["mkm"] = { "Moklen", 3319380, } m["mkn"] = { "Kupang Malay", 18458203, "crp", "Latn", } m["mko"] = { "Mingang Doso", 3915382, "alv-bwj", } m["mkp"] = { "Moikodi", 6894594, "ngf-yar", "Latn", } m["mkq"] = { "Bay Miwok", 3460957, "nai-utn", "Latn", } m["mkr"] = { "Malas", 11732402, "ngf-nad", "Latn", } m["mks"] = { "Silacayoapan Mixtec", 7514027, "omq-mxt", "Latn", } m["mkt"] = { "Vamale", 14916907, "poz-cln", "Latn", } m["mku"] = { "Konyanka Maninka", 11163298, "dmn-mnk", } m["mkv"] = { "Mav̋ea", 3073532, "poz-vnn", "Latn", } m["mkx"] = { "Kinamiging", --"Cinamiguin Manobo", 12953697, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/kinamiging/", --TLCHANGE english_name = "Cinamiguin Manobo", --TLCHANGE } m["mky"] = { "Taba", 3512690, "poz-hce", "Latn", } m["mkz"] = { "Makasae", 35782, "paa-eti", "Latn", } m["mla"] = { "Tamambo", 1153276, "poz-vnn", "Latn", } m["mlb"] = { "Mbule", 35843, "nic-ymb", "Latn", } m["mlc"] = { "Caolan", 3446682, "tai-cho", "Latn, Hani", sort_key = {Hani = "Hani-sortkey"}, } m["mle"] = { "Manambu", 11732406, "paa-nnd", "Latn", } m["mlf"] = { "Mal", 3281057, "mkh-khm", } m["mlh"] = { "Mape", 6753787, "ngf-kma", "Latn", } m["mli"] = { "Malimpung", 12473435, } m["mlj"] = { "Miltu", 3441310, } m["mlk"] = { "Ilwana", 6001357, "bnt-sab", } m["mll"] = { "Malua Bay", 6744946, "poz-vnc", "Latn", } m["mlm"] = { "Mulam", 3092284, "qfa-kms", "Latn", } m["mln"] = { "Malango", 3281522, "poz-sls", "Latn", } m["mlo"] = { "Mlomp", 36009, "alv-bak", } m["mlp"] = { "Bargam", 4860543, "ngf-mad", "Latn", } m["mlq"] = { "Western Maninkakan", 11028033, "dmn-wmn", } m["mlr"] = { "Vame", 3515088, "cdc-cbm", "Latn", } m["mls"] = { "Masalit", 56557, "ssa", } m["mlu"] = { "To'abaita", 36645, "poz-sls", "Latn", } m["mlv"] = { "Mwotlap", 2475538, "poz-vnn", "Latn", } m["mlw"] = { "Moloko", 1965222, "cdc-cbm", "Latn", } m["mlx"] = { "Malfaxal", 2157421, "poz-vnc", "Latn", } m["mlz"] = { "Malaynon", 18755512, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/malaynon/", --TLCHANGE english_name = "Malaynon", --TLCHANGE } m["mma"] = { "Mama", 3913963, "nic-jrn", } m["mmb"] = { "Momina", 6897297, } m["mmc"] = { "Michoacán Mazahua", 12953705, "oto", "Latn", } m["mmd"] = { "Maonan", 3092293, "qfa-kms", "Latn", } m["mme"] = { "Tirax", 3276286, "poz-vnc", "Latn", } m["mmf"] = { "Mundat", 56263, "cdc-wst", "Latn", } m["mmg"] = { "North Ambrym", 2842468, "poz-vnc", "Latn", } m["mmh"] = { "Mehináku", 3501838, "awd", "Latn", } m["mmi"] = { "Hember Avu", 6940113, "ngf-tib", "Latn", } m["mmj"] = { "Majhwar", 6737795, } m["mmk"] = { "Mukha-Dora", 6933447, } m["mml"] = { "Man Met", 3194984, "mkh-pal", } m["mmm"] = { "Maii", 6735599, "poz-vnc", "Latn", } m["mmn"] = { "Mamanwa", --"Mamanwa", 3206623, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/mamanwa/", --TLCHANGE english_name = "Mamanwa", --TLCHANGE } m["mmo"] = { "Mangga Buang", 12952294, "poz-ocw", "Latn", } m["mmp"] = { "Musan", 2605703, "paa-amu", "Latn", } m["mmq"] = { "Aisi", 6940074, "ngf-ais", "Latn", } m["mmr"] = { "Western Xiangxi Miao", 3307901, "hmn", "Latn", } m["mmt"] = { "Malalamai", 3281496, "poz-ocw", "Latn", } m["mmu"] = { "Mmaala", 13123461, "nic-ymb", "Latn", } m["mmv"] = { "Miriti", 6873567, "sai-tuc", "Latn", } m["mmw"] = { "Emae", 3051961, "poz-pnp", "Latn", } m["mmx"] = { "Madak", 3275205, "poz-ocw", "Latn", } m["mmy"] = { "Migaama", 56259, "cdc-est", "Latn", } m["mmz"] = { "Mabaale", 11003249, "bnt-ngn", } m["mna"] = { "Mbula", 3303572, "poz-ocw", "Latn", } m["mnb"] = { "Muna", 6935584, "poz-mun", "Latn", } m["mnc"] = { "Manchu", 33638, "tuw-jrc", "mnc-Mong, Latn", ancestors = "juc", -- mnc-Mong translit in [[Module:scripts/data]] } m["mnd"] = { "Mondé", 6898840, "tup", "Latn", } m["mne"] = { "Naba", 760732, "csu-bgr", } m["mnf"] = { "Mundani", 35839, "nic-mom", "Latn", } m["mng"] = { "Eastern Mnong", 12953747, "mkh-ban", "Latn, Khmr", } m["mnh"] = { "Mono (Congo)", 33501, "bad-cnt", "Latn", } m["mni"] = { "Manipuri", 33868, "sit", "Mtei, Beng", ancestors = "omp", translit = {Mtei = "Mtei-translit"}, } m["mnj"] = { "Munji", 33639, "ira-mny", "Arab", } m["mnk"] = { "Mandinka", 33678, "dmn-wmn", "Latn, Arab, Nkoo", } m["mnl"] = { "Tiale", 6744350, "poz-vnn", "Latn", } m["mnm"] = { "Mapena", 11732415, "ngf-dag", "Latn", } m["mnn"] = { "Southern Mnong", 23857582, "mkh-ban", } m["mnp"] = { "Northern Min", 36457, "zhx-inm", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", } m["mnq"] = { "Minriq", 2742268, "mkh-asl", "Latn", } m["mnr"] = { "Mono (California)", 33591, "azc-num", "Latn", } m["mnt"] = { "Maykulan", 3915696, "aus-pam", "Latn", } m["mnu"] = { "Mer", 6817854, "paa-mai", "Latn", } m["mnv"] = { "Rennellese", 3397346, "poz-pnp", "Latn", } m["mnw"] = { "Mon", 13349, "mkh-mnc", "Mymr", ancestors = "mkh-mmn", sort_key = { from = {"ျ", "ြ", "ွ", "ှ", "ၞ", "ၟ", "ၠ", "ၚ", "ဿ"}, to = {"္ယ", "္ရ", "္ဝ", "္ဟ", "္န", "္မ", "္လ", "င", "သ္သ"} }, } m["mnx"] = { "Sougb", 3507964, "paa-ebh", "Latn", } m["mny"] = { "Manyawa", 11002622, "bnt-mak", ancestors = "vmw", } m["mnz"] = { "Moni", 6899857, "ngf-pan", "Latn", } m["moa"] = { "Mwan", 3320111, "dmn-nbe", "Latn", } m["moc"] = { "Mocoví", 3027906, "sai-guc", "Latn", } m["mod"] = { "Mobilian", 13333, "crp", "Latn", ancestors = "cho, cic", } m["moe"] = { "Montagnais", 13351, "alg", "Latn", ancestors = "cr", strip_diacritics = {remove_diacritics = c.macron}, } m["mog"] = { "Mongondow", 3058458, "phi", "Latn", } m["moh"] = { "Mohawk", 13339, "iro-nor", "Latn", ancestors = "iro-omo", } m["moi"] = { "Mboi", 3914417, "alv-yun", } m["moj"] = { "Monzombo", 11154772, "nic-nkk", "Latn", } m["mok"] = { "Morori", 6913275, } m["mom"] = { "Monimbo", 56542, } m["moo"] = { "Monom", 6901726, "mkh-ban", } m["mop"] = { "Mopan Maya", 36183, "myn", "Latn", } m["moq"] = { "Mor (Papuan)", 11732468, "qfa-dis", -- Papuan; isolate in Glottolog and Palmer (2018); top-level TNG in Ross (2005), in Berau Gulf (under -- TNG) in Usher (2020) } m["mor"] = { "Moro", 36172, "alv-hei", "Latn", } m["mos"] = { "Moore", 36096, "nic-mre", "Latn", } m["mot"] = { "Barí", 2886281, "cba", "Latn", } m["mou"] = { "Mogum", 3440473, "cdc-est", "Latn", } m["mov"] = { "Mojave", 56510, "nai-yuc", "Latn", } m["mow"] = { "Moi (Congo)", 11124792, "bnt-bmo", "Latn", } m["mox"] = { "Molima", 3319495, "poz-ocw", "Latn", } m["moy"] = { "Shekkacho", 56827, "omv-gon", } m["moz"] = { "Mukulu", 3440403, "cdc-est", } m["mpa"] = { "Mpoto", 6928303, "bnt-mbi", "Latn", } m["mpb"] = { "Mullukmulluk", 6741120, } m["mpc"] = { "Mangarayi", 6748829, } m["mpd"] = { "Machinere", 12953681, "awd", "Latn", } m["mpe"] = { "Majang", 56724, "sdv", } m["mpg"] = { "Marba", 56614, "cdc-mas", } m["mph"] = { "Maung", 6792550, "aus-wdj", "Latn", } m["mpi"] = { "Mpade", 3280670, "cdc-cbm", "Latn", } m["mpj"] = { "Martu Wangka", 3295916, "aus-pam", "Latn", } m["mpk"] = { "Mbara (Chad)", 3912770, "cdc-cbm", } m["mpl"] = { "Middle Watut", 15887910, "poz-ocw", "Latn", } m["mpm"] = { "Yosondúa Mixtec", 12953741, "omq-mxt", "Latn", } m["mpn"] = { "Mindiri", 6863842, "poz-ocw", "Latn", } m["mpo"] = { "Miu", 6883668, "poz-ocw", "Latn", } m["mpp"] = { "Migabac", 11732448, "ngf-sop", "Latn", } m["mpq"] = { "Matís", 3299145, "sai-pan", "Latn", } m["mpr"] = { "Vangunu", 3554582, "poz-ocw", "Latn", } m["mps"] = { "Dadibi", 5208077, "paa-teb", "Latn", } m["mpt"] = { "Mian", 12952846, "ngf-msu", "Latn", } m["mpu"] = { "Makuráp", 3281037, "tup", "Latn", } m["mpv"] = { "Mungkip", 11732485, "ngf-boa", "Latn", } m["mpw"] = { "Mapidian", 6753812, "awd", "Latn", } m["mpx"] = { "Misima-Paneati", 6875666, "poz-ocw", "Latn", } m["mpy"] = { "Mapia", 3287224, "poz-mic", "Latn", } m["mpz"] = { "Mpi", 6928276, "tbq-bka", } m["mqa"] = { "Maba", 3273750, } m["mqb"] = { "Mbuko", 3502213, "cdc-cbm", "Latn", } m["mqc"] = { "Mangole", 6749097, "poz-cma", "Latn", } m["mqe"] = { "Matepi", 11732426, "ngf-han", "Latn", } m["mqf"] = { "Momuna", 6897518, } m["mqg"] = { "Kota Bangun Kutai Malay", 12952778, } m["mqh"] = { "Tlazoyaltepec Mixtec", 12953740, "omq-mxt", "Latn", } m["mqi"] = { "Mariri", 6765544, } m["mqj"] = { "Mamasa", 6745452, "poz-ssw", "Latn", } m["mqk"] = { "Rajah Kabunsuwan Manobo", 12953700, "mno", } m["mql"] = { "Mbelime", 4286473, "nic-eov", "Latn", } m["mqm"] = { "South Marquesan", 19694214, "poz-pep", "Latn", } m["mqn"] = { "Moronene", 642581, "poz-btk", "Latn", } m["mqo"] = { "Modole", 11732457, "paa-gto", "Latn", } m["mqp"] = { "Manipa", 6749799, "poz-cma", "Latn", } m["mqq"] = { "Minokok", 18642293, "poz-san", "Latn", } m["mqr"] = { "Mander", 6747979, "paa-tor", "Latn", } m["mqs"] = { "West Makian", 3033575, "paa-nha", "Latn", } m["mqt"] = { "Mok", 13018559, "mkh-pal", } m["mqu"] = { "Mandari", 3285426, "sdv-bri", } m["mqv"] = { "Mosimo", 11732478, "ngf-nwh", "Latn", } m["mqw"] = { "Murupi", 11732486, "ngf-nwh", "Latn", } m["mqx"] = { "Mamuju", 6746004, "poz-ssw", "Latn", } m["mqy"] = { "Manggarai", 3285748, "poz-cet", "Latn", } m["mqz"] = { "Malasanga", 14916889, "poz-ocw", "Latn", } m["mra"] = { "Mlabri", 3073465, "mkh", } m["mrb"] = { "Sungwadia", 3293299, "poz-vnn", "Latn", } m["mrc"] = { "Maricopa", 56386, "nai-yuc", "Latn", } m["mrd"] = { "Western Magar", 22303263, "sit-gma", "Deva", } m["mre"] = { "Martha's Vineyard Sign Language", 33494, "sgn", "Latn, Sgnw", } m["mrf"] = { "Elseng", 3915667, "qfa-unc", -- "Border or language isolate"; unclassifiable due to paucity of data "Latn", } m["mrg"] = { "Mising", 3316328, "sit-tan", "Latn, Beng, Deva", ancestors = "adi", } m["mrh"] = { "Mara Chin", 4175893, "tbq-kuk", "Latn", } m["mrj"] = { "Western Mari", 1776032, "chm", "Cyrl", translit = "chm-translit", sort_key = "mrj-sortkey", } m["mrk"] = { "Hmwaveke", 5873712, "poz-cln", "Latn", } m["mrl"] = { "Mortlockese", 3324598, "poz-mic", "Latn", } m["mrm"] = { "Mwerlap", 3331115, "poz-vnn", "Latn", } m["mrn"] = { "Cheke Holo", 2962165, "poz-ocw", "Latn", } m["mro"] = { "Mru", 1951521, "sit-mru", "Latn, Mroo", } m["mrp"] = { "Morouas", 6913299, "poz-vnn", "Latn", } m["mrq"] = { "North Marquesan", 2603808, "poz-pep", "Latn", } m["mrr"] = { "Hill Maria", 27602, "dra-mdy", "Deva", } m["mrs"] = { "Maragus", 6754640, "poz-vnc", "Latn", } m["mrt"] = { "Margi", 56241, "cdc-cbm", "Latn", } m["mru"] = { "Mono (Cameroon)", 11031964, "alv-mbm", "Latn", } m["mrv"] = { "Mangarevan", 36237, "poz-pep", "Latn", } m["mrw"] = { "Mëranaw", --"Maranao", 33800, "phi", "Latn, Arab", is_official_kwf_name = "https://kwfwikaatkultura.ph/meranaw/", --TLCHANGE english_name = "Maranao", --TLCHANGE } m["mrx"] = { "Dineor", 5278044, "paa-tor", "Latn", } m["mry"] = { "Mandaya", --"Karaga Mandaya", 6747925, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/mandaya/", --TLCHANGE english_name = "Karaga Mandaya", --TLCHANGE } m["mrz"] = { "Marind", 6763970, "paa-mri", "Latn", } m["msb"] = { "Masbatenyo", --"Masbatenyo" 33948, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/masbatenyo/", --TLCHANGE english_name = "Masbatenyo", --TLCHANGE } m["msc"] = { "Sankaran Maninka", 11155812, "dmn-mnk", } m["msd"] = { "Yucatec Maya Sign Language", 34281, "sgn", "Latn", -- when documented } m["mse"] = { "Musey", 56328, "cdc-mas", } m["msf"] = { "Mekwei", 4544752, "paa-nim", "Latn", } m["msg"] = { "Moraid", 6909020, "paa-wbh", "Latn", } m["msi"] = { "Sabah Malay", 10867404, "crp", "Latn, Arab", } m["msj"] = { "Ma", 6720909, "nic-mbc", "Latn", } m["msk"] = { "Mansaka", --"Mansaka" 12952800, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/mansaka/", --TLCHANGE english_name = "Mansaka", --TLCHANGE } m["msl"] = { "Molof", 4300950, } m["msm"] = { "Manobo Agusan", --"Agusan Manobo", 12953696, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-agusan/", --TLCHANGE english_name = "Agusan Manobo", --TLCHANGE } m["msn"] = { "Vurës", 3563857, "poz-vnn", "Latn", } m["mso"] = { "Mombum", 6897079, "ngf-mom", "Latn", } m["msp"] = { "Maritsauá", 6765915, "tup", "Latn", } m["msq"] = { "Caac", 2932212, "poz-cln", "Latn", } m["msr"] = { "Mongolian Sign Language", 3915499, "sgn", } m["mss"] = { "West Masela", 12952816, "poz-tim", } m["msu"] = { "Musom", 6943041, "poz-ocw", "Latn", } m["msv"] = { "Maslam", 3502273, } m["msw"] = { "Mansoanka", 35814, } m["msx"] = { "Moresada", 11732475, "ngf-pom", "Latn", } m["msy"] = { "Aruamu", 3501809, "paa-rub", "Latn", } m["msz"] = { "Momare", 6897030, "ngf-sop", "Latn", } m["mta"] = { "Manobo Dulangan", --"Cotabato Manobo", 12953698, "mno", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/manobo-dulangan/", --TLCHANGE english_name = "Cotabato Manobo", --TLCHANGE } m["mtb"] = { "Anyin Morofo", 3502338, "alv-ctn", "Latn", ancestors = "any", } m["mtc"] = { "Munit", 11732482, "ngf-kok", "Latn", } m["mtd"] = { "Mualang", 3073458, "poz-mly", "Latn", } m["mte"] = { "Alu", 33503, "poz-ocw", "Latn", } m["mtf"] = { "Murik (New Guinea)", 7050035, "paa-lse", "Latn", } m["mtg"] = { "Una", 5580728, "ngf-mek", "Latn", } m["mth"] = { "Munggui", 6936018, "poz-hce", "Latn", } m["mti"] = { "Maiwa (New Guinea)", 6737223, "ngf-dag", "Latn", } m["mtj"] = { "Moskona", 11288953, "paa-ebh", "Latn", } m["mtk"] = { "Mbe'", 10964025, "nic-nka", "Latn", } m["mtl"] = { "Montol", 3440457, "cdc-wst", "Latn", } m["mtm"] = { "Mator", 20669419, "syd", "Cyrl", } m["mtn"] = { "Matagalpa", 3490756, "nai-min", } m["mto"] = { "Totontepec Mixe", 7828400, "nai-miz", "Latn", } m["mtp"] = { "Wichí Lhamtés Nocten", 5908756, "sai-wic", "Latn", } m["mtq"] = { "Muong", 3236789, "mkh-vie", "Latn", sort_key = "vi-sortkey", } m["mtr"] = { "Mewari", 2992857, "raj", "Deva", translit = "hi-translit", -- for now } m["mts"] = { "Yora", 3572572, "sai-pan", "Latn", } m["mtt"] = { "Mota", 3325052, "poz-vnn", "Latn", } m["mtu"] = { "Tututepec Mixtec", 7857069, "omq-mxt", "Latn", } m["mtv"] = { "Asaro'o", 3503684, "ngf-war", -- ngf-moa if we split out Molet from Asaro'o "Latn", } m["mtw"] = { "Bukidnon Magahat", --"Magahat", 6729600, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/bukidnon-magahat/", --TLCHANGE english_name = "Magahat", --TLCHANGE } m["mtx"] = { "Tidaá Mixtec", 7800805, "omq-mxt", "Latn", } m["mty"] = { "Nabi", 6956858, "paa-tor", "Latn", } m["mua"] = { "Mundang", 36032, "alv-mbm", } m["mub"] = { "Mubi", 3440518, "cdc-est", "Latn", } m["muc"] = { "Mbu'", 35868, "nic-beb", "Latn", } m["mud"] = { "Mednyj Aleut", 1977419, "qfa-mix", ancestors = "ale, ru" } m["mue"] = { "Media Lengua", 36066, "qfa-mix", "Latn", ancestors = "es, qu", } m["mug"] = { "Musgu", 3123545, "cdc-cbm", "Latn", } m["muh"] = { "Mündü", 35981, "nic-nke", "Latn", } m["mui"] = { "Musi", 615660, "poz-mly", "Latn", } m["muj"] = { "Mabire", 3440437, } m["mul"] = { "Maramihang wika", -- "Translingual", 7834564, "qfa-not", "All", -- NOTE: The following sort keys are used in process_page() in [[Module:headword/page]], which generates -- the default sort key for the page (corresponding to {{DEFAULTSORT:...}}) by generating a sort key for -- the pagename using `makeSortKey()` called on language object "mul". Currently this just handles -- Japanese sort keys. -- -- FIXME: This should be smarter and use the language of the page if there's only one. sort_key = { Hani = "Hani-sortkey", Jpan = "Jpan-sortkey", Hrkt = "Hira-sortkey", -- Sort all kana as Hira. Hira = "Hira-sortkey", Kana = "Hira-sortkey", }, standard_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" .. c.punc, } m["mum"] = { "Maiwala", 12952764, "poz-ocw", "Latn", } m["muo"] = { "Nyong", 36373, "alv-lek", } m["mup"] = { "Malvi", 33413, "raj", "Deva", translit = "hi-translit" } m["muq"] = { "Eastern Xiangxi Miao", 27431376, "hmn", } m["mur"] = { "Murle", 56727, "sdv", } m["mus"] = { "Creek", 523014, "nai-mus", "Latn", } m["mut"] = { "Western Muria", 12952886, "dra-mur", } m["muu"] = { "Yaaku", 34222, "cus-eas", } m["muv"] = { "Muthuvan", 3327420, "dra-tam", } m["mux"] = { "Bo-Ung", 15831607, "ngf-hag", "Latn", } m["muy"] = { "Muyang", 3502301, "cdc-cbm", "Latn", } m["muz"] = { "Mursi", 36013, "sdv", } m["mva"] = { "Manam", 6746851, "poz-ocw", "Latn", } m["mvb"] = { "Mattole", 20824, "ath-pco", "Latn", } m["mvd"] = { "Mamboru", 578815, "poz", "Latn", } m["mvg"] = { "Yucuañe Mixtec", 25562736, "omq-mxt", "Latn", } m["mvh"] = { "Mire", 3441359, } m["mvi"] = { "Miyako", 36218, "jpx-sry", "Jpan", translit = s["jpx-translit"], display_text = s["jpx-displaytext"], strip_diacritics = s["jpx-stripdiacritics"], sort_key = s["jpx-sortkey"], } m["mvk"] = { "Mekmek", 6810592, "paa-yua", "Latn", } m["mvl"] = { "Mbara (Australia)", 6799620, "aus-pam", "Latn", } m["mvm"] = { "Muya", 2422759, "sit-qia", } m["mvn"] = { "Minaveha", 6863278, "poz-ocw", "Latn", } m["mvo"] = { "Marovo", 3294683, "poz-ocw", "Latn", } m["mvp"] = { "Duri", 3915414, "poz-ssw", "Latn", } m["mvq"] = { "Moere", 11732458, "ngf-kum", "Latn", } m["mvr"] = { "Marau", 6755069, "poz-hce", "Latn", } m["mvs"] = { "Massep", 3502895, "qfa-dis", -- poorly documented (but in vigorous use); isolate per Ethnologue, Glottolog, and Foley (2018); Greater -- Kwerba per Usher "Latn", } m["mvt"] = { "Mpotovoro", 6928305, "poz-vnc", "Latn", } m["mvu"] = { "Marfa", 713633, } m["mvv"] = { "Tagal Murut", 7675300, "poz-san", "Latn", } m["mvw"] = { "Machinga", 12952754, "bnt-rvm", } m["mvx"] = { "Meoswar", 6817777, "poz-hce", "Latn", } m["mvy"] = { "Indus Kohistani", 33399, "inc-koh", "Arab", } m["mvz"] = { "Mesqan", 6821677, "sem-eth", } m["mwa"] = { "Mwatebu", 14916896, "poz-ocw", "Latn", } m["mwb"] = { "Juwal", 6319103, "paa-mmu", "Latn", } m["mwc"] = { "Are", 29277, "poz-ocw", "Latn", } m["mwe"] = { "Mwera", 6944725, "bnt-rvm", "Latn", } m["mwf"] = { "Murrinh-Patha", 2980398, "aus-dal", "Latn", } m["mwg"] = { "Aiklep", 3399652, "poz-ocw", "Latn", } m["mwh"] = { "Mouk-Aria", 3325498, "poz-ocw", "Latn", } m["mwi"] = { "Labo", 2157452, "poz-vnc", "Latn", } m["mwk"] = { "Kita Maninkakan", 3015523, "dmn-wmn", } m["mwl"] = { "Mirandes", 13330, "roa-asl", "Latn", } m["mwm"] = { "Sar", 56850, "csu-sar", "Latn", } m["mwn"] = { "Nyamwanga", 6944666, "bnt-mwi", "Latn", } m["mwo"] = { "Sungwadaga", 3276435, "poz-vnn", "Latn", } m["mwp"] = { "Kala Lagaw Ya", 2591262, "aus-pam", "Latn", } m["mwq"] = { "Mün Chin", 331340, "tbq-kuk", } m["mwr"] = { "Marwari", 56312, "raj", "Deva, Mahj", translit = { Deva = "hi-translit", -- for now Mahj = "Mahj-translit", }, } m["mws"] = { "Mwimbi-Muthambi", 15632357, "bnt-kka", "Latn", } m["mwt"] = { "Moken", 18648701, "poz", } m["mwu"] = { "Mittu", 6883573, "csu-bbk", "Latn", } m["mwv"] = { "Mentawai", 13365, "poz-nws", "Latn", } m["mww"] = { "White Hmong", 3138829, "hmn", "Latn, Hmng, Hmnp", } m["mwz"] = { "Moingi", 11011905, } m["mxa"] = { "Northwest Oaxaca Mixtec", 12953739, "omq-mxt", "Latn", } m["mxb"] = { "Tezoatlán Mixtec", 3317286, "omq-mxt", "Latn", } m["mxd"] = { "Modang", 6888037, "poz", "Latn", } m["mxe"] = { "Mele-Fila", 3305008, "poz-pnp", "Latn", } m["mxf"] = { "Malgbe", 3502224, } m["mxg"] = { "Mbangala", 6799612, "bnt-yak", } m["mxh"] = { "Mvuba", 6944591, "csu-mle", "Latn", } m["mxi"] = { "Mozarabic", 317044, "roa-ibe", "Arab, Hebr, Latn", translit = "mxi-translit", strip_diacritics = { Arab = "ar-stripdiacritics", }, -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["mxj"] = { "Miju", 56332, "sit-mdz", "Latn, Deva", } m["mxk"] = { "Monumbo", 6906792, "paa-mon", "Latn", } m["mxl"] = { "Maxi Gbe", 35770, "alv-gbe", } m["mxm"] = { "Meramera", 6817936, "poz-ocw", "Latn", } m["mxn"] = { "Moi (Indonesia)", 11732459, "paa-wbh", "Latn", } m["mxo"] = { "Mbowe", 10962309, "bnt-kav", } m["mxp"] = { "Tlahuitoltepec Mixe", 7810697, } m["mxq"] = { "Juquila Mixe", 25559721, } m["mxr"] = { "Murik (Malaysia)", 3328150, nil, "Latn", } m["mxs"] = { "Huitepec Mixtec", 12953729, "omq-mxt", "Latn", } m["mxt"] = { "Jamiltepec Mixtec", 12953730, "omq-mxt", "Latn", } m["mxu"] = { "Mada (Cameroon)", 3441206, "cdc-cbm", "Latn", } m["mxv"] = { "Metlatónoc Mixtec", 36363, "omq-mxt", "Latn", } m["mxw"] = { "Namo", 12952923, "paa-nam", "Latn", } m["mxx"] = { "Mahou", 11004334, "dmn-mnk", "Latn, Nkoo", } m["mxy"] = { "Southeastern Nochixtlán Mixtec", 7070684, "omq-mxt", "Latn", } m["mxz"] = { "Central Masela", 42575433, "poz-tim", "Latn", } m["myb"] = { "Mbay", 3033565, "csu-sar", "Latn", } m["myc"] = { "Mayeka", 11129517, "bnt-boa", } m["mye"] = { "Myene", 35832, "bnt-tso", "Latn", } m["myf"] = { "Bambassi", 56540, "omv-mao", "Latn", } m["myg"] = { "Manta", 35799, "nic-mom", "Latn", } m["myh"] = { "Makah", 3280640, "wak", "Latn", } m["myj"] = { "Mangayat", 35988, "nic-ser", } m["myk"] = { "Mamara", 36187, "alv-sma", "Latn", } m["myl"] = { "Moma", 6897018, "poz", "Latn", } m["mym"] = { "Me'en", 3408516, "sdv", } m["myo"] = { "Anfillo", 34928, "omv-gon", } m["myp"] = { "Pirahã", 33825, "sai-mur", "Latn", } m["myr"] = { "Muniche", 3915654, } m["mys"] = { "Mesmes", 3508617, "sem-eth", } m["myu"] = { "Mundurukú", 746723, "tup", "Latn", } m["myv"] = { "Erzya", 29952, "urj-mdv", "Cyrl", translit = "myv-translit", override_translit = true, } m["myw"] = { "Muyuw", 3502878, "poz-ocw", "Latn", } m["myx"] = { "Masaba", 12952814, "bnt-msl", "Latn", } m["myy"] = { "Macuna", 3275059, "sai-tuc", "Latn", } m["myz"] = { "Classical Mandaic", 25559314, "sem-ase", "Mand", translit = { Mand = "Mand-translit", }, strip_diacritics = { Mand = "Mand-stripdiacritics", } } m["mza"] = { "Santa María Zacatepec Mixtec", 8063756, "omq-mxt", "Latn", } m["mzb"] = { "Northern Saharan Berber", 11156769, "ber", "Arab, Latn, Tfng", } m["mzc"] = { "Madagascar Sign Language", 12715020, "sgn", } m["mzd"] = { "Malimba", 35806, "bnt-saw", } m["mze"] = { "Morawa", 6909384, "paa-mal", "Latn", } m["mzg"] = { "Monastic Sign Language", 3217333, "sgn", } m["mzh"] = { "Wichí Lhamtés Güisnay", 7998197, "sai-wic", "Latn", } m["mzi"] = { "Ixcatlán Mazatec", 6101049, "omq-maz", "Latn", } m["mzj"] = { "Manya", 11006832, "dmn-mnk", } m["mzk"] = { "Nigeria Mambila", 11004163, "nic-mmb", "Latn", } m["mzl"] = { "Mazatlán Mixe", 25559728, } m["mzm"] = { "Mumuye", 36021, "alv-mum", "Latn", } m["mzn"] = { "Mazanderani", 13356, "ira-msh", "mzn-Arab", } m["mzo"] = { "Matipuhy", 6787588, "sai-kui", "Latn", } m["mzp"] = { "Movima", 1659701, "qfa-iso", "Latn", } m["mzq"] = { "Mori Atas", 3324070, "poz-btk", "Latn", } m["mzr"] = { "Marúbo", 3296011, "sai-pan", "Latn", } m["mzs"] = { "Macanese", 35785, "crp", "Latn", ancestors = "pt", sort_key = {Latn = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.tilde .. c.diaer .. c.cedilla}}, } m["mzt"] = { "Mintil", 6869641, "mkh-asl", } m["mzu"] = { "Inapang", 6013569, "paa-tam", "Latn", } m["mzv"] = { "Manza", 36038, "gba-eas", } m["mzw"] = { "Deg", 35183, "nic-gnw", "Latn", } m["mzx"] = { "Mawayana", 6794377, "awd", } m["mzy"] = { "Mozambican Sign Language", 6927809, "sgn", } m["mzz"] = { "Maiadomu", 6735234, "poz-ocw", "Latn", } return require("Module:languages").finalizeData(m, "language") buaqdfr6jac0tirj7a4vrsi62fc8b7g Module:languages/data/exceptional 828 32629 178457 178433 2026-10-27T01:43:58Z GinawaSaHapon 3989 178457 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["aav-khs-pro"] = { "Proto-Khasian", 116773216, "aav-khs", "Latn", type = "reconstructed", } m["aav-nic-pro"] = { "Proto-Nicobarese", 116773793, "aav-nic", "Latn", type = "reconstructed", } m["aav-pkl-pro"] = { "Proto-Pnar-Khasi-Lyngngam", 116773259, "aav-pkl", "Latn", type = "reconstructed", } m["aav-pro"] = { -- mkh-pro will merge into this "Proto-Austroasiatic", 116773186, "aav", "Latn", type = "reconstructed", } m["afa-pro"] = { "Proto-Afroasiatic", 269125, "afa", "Latn", type = "reconstructed", } m["alg-aga"] = { "Agawam", nil, "alg-eas", "Latn", } m["alg-pro"] = { "Proto-Algonquian", 7251834, "alg", "Latn", type = "reconstructed", sort_key = {remove_diacritics = "·"}, } m["alv-ama"] = { "Amasi", 4740400, "nic-grs", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.tilde .. c.macron}, } m["alv-bgu"] = { "Bainouk Gubeeher", 17002646, "alv-bny", "Latn", } m["alv-bua-pro"] = { "Proto-Bua", 116773723, "alv-bua", "Latn", type = "reconstructed", } m["alv-cng-pro"] = { "Proto-Cangin", 116773726, "alv-cng", "Latn", type = "reconstructed", } m["alv-edo-pro"] = { "Proto-Edoid", 116773206, "alv-edo", "Latn", type = "reconstructed", } m["alv-fli-pro"] = { "Proto-Fali", 116773754, "alv-fli", "Latn", type = "reconstructed", } m["alv-gbe-pro"] = { "Proto-Gbe", 116773208, "alv-gbe", "Latn", type = "reconstructed", } m["alv-gng-pro"] = { "Proto-Guang", 116773757, "alv-gng", "Latn", type = "reconstructed", } m["alv-gtm-pro"] = { "Proto-Central Togo", 116773732, "alv-gtm", "Latn", type = "reconstructed", } m["alv-gwa"] = { "Gwara", 16945580, "nic-pla", "Latn", } m["alv-hei-pro"] = { "Proto-Heiban", 116773760, "alv-hei", "Latn", type = "reconstructed", } m["alv-ido-pro"] = { "Proto-Idomoid", 116773764, "alv-ido", "Latn", type = "reconstructed", } m["alv-igb-pro"] = { "Proto-Igboid", 116773765, "alv-igb", "Latn", type = "reconstructed", } m["alv-kwa-pro"] = { "Proto-Kwa", 116773780, "alv-kwa", "Latn", type = "reconstructed", } m["alv-mum-pro"] = { "Proto-Mumuye", 116773791, "alv-mum", "Latn", type = "reconstructed", } m["alv-nup-pro"] = { "Proto-Nupoid", 116773795, "alv-nup", "Latn", type = "reconstructed", } m["alv-pro"] = { "Proto-Atlantic-Congo", 116732838, "alv", "Latn", type = "reconstructed", } m["alv-edk-pro"] = { "Proto-Edekiri", nil, "alv-edk", "Latn", type = "reconstructed", } m["alv-yor-pro"] = { "Proto-Yoruba", nil, "alv-yor", "Latn", type = "reconstructed", } m["alv-yrd-pro"] = { "Proto-Yoruboid", 116773824, "alv-yrd", "Latn", type = "reconstructed", } m["alv-von-pro"] = { "Proto-Volta-Niger", 116773820, "alv-von", "Latn", type = "reconstructed", } m["apa-pro"] = { "Proto-Apachean", 116773135, "apa", "Latn", type = "reconstructed", } m["aql-pro"] = { "Proto-Algic", 18389588, "aql", "Latn", type = "reconstructed", sort_key = {remove_diacritics = "·"}, } m["art-adu"] = { "Adûni", 1232159, "art", "Latn", type = "appendix-constructed", } m["art-bel"] = { "Belter Creole", 108055510, "art", "Latn", type = "appendix-constructed", sort_key = { remove_diacritics = c.acute, from = {"ɒ"}, to = {"a"}, }, } m["art-blk"] = { "Bolak", 2909283, "art", "Latn", type = "appendix-constructed", } m["art-bsp"] = { "Black Speech", 686210, "art", "Latn, Teng", type = "appendix-constructed", } m["art-com"] = { "Communicationssprache", 35227, "art", "Latn", type = "appendix-constructed", } m["art-dtk"] = { "Dothraki", 2914733, "art", "Latn", type = "appendix-constructed", } m["art-elo"] = { "Eloi", nil, "art", "Latn", type = "appendix-constructed", } m["art-gld"] = { "Goa'uld", 19823, "art", "Latn, Egyp, Mero", type = "appendix-constructed", } m["art-lap"] = { "Lapine", 6488195, "art", "Latn", type = "appendix-constructed", } m["art-man"] = { "Mandalorian", 54289, "art", "Latn", type = "appendix-constructed", } m["art-mun"] = { "Mundolinco", 851355, "art", "Latn", type = "appendix-constructed", } m["art-nav"] = { "Naʼvi", 316939, "art", "Latn", type = "appendix-constructed", } m["art-vlh"] = { "High Valyrian", 64483808, "art", "Latn", type = "appendix-constructed", } m["ath-nic"] = { "Nicola", 20609, "ath-nor", "Latn", } m["ath-pro"] = { "Proto-Athabaskan", 104841722, "ath", "Latn", type = "reconstructed", } m["auf-pro"] = { "Proto-Arawa", 116773706, "auf", "Latn", type = "reconstructed", } m["aus-alu"] = { "Alungul", 16827670, "aus-pmn", "Latn", } m["aus-and"] = { "Andjingith", 4754509, "aus-pmn", "Latn", } m["aus-ang"] = { "Angkula", 16828520, "aus-pmn", "Latn", } m["aus-arn-pro"] = { "Proto-Arnhem", 116773720, "aus-arn", "Latn", type = "reconstructed", } m["aus-bra"] = { "Barranbinya", 4863220, "aus-pmn", "Latn", } m["aus-brm"] = { "Barunggam", 4865914, "aus-pmn", "Latn", } m["aus-cww-pro"] = { "Proto-Central New South Wales", 116773199, "aus-cww", "Latn", type = "reconstructed", } m["aus-dal-pro"] = { "Proto-Daly", 116773743, "aus-dal", "Latn", type = "reconstructed", } m["aus-guw"] = { "Guwar", 6652138, "aus-pam", "Latn", } m["aus-lsw"] = { "Little Swanport", 6652138, "qfa-unc", "Latn", } m["aus-mbi"] = { "Mbiywom", 6799701, "aus-pmn", "Latn", } m["aus-ngk"] = { "Ngkoth", 7022405, "aus-pmn", "Latn", } m["aus-nyu-pro"] = { "Proto-Nyulnyulan", 116773797, "aus-nyu", "Latn", type = "reconstructed", } m["aus-pam-pro"] = { "Proto-Pama-Nyungan", 33942, "aus-pam", "Latn", type = "reconstructed", } m["aus-tul"] = { "Tulua", 16938541, "aus-pam", "Latn", } m["aus-uwi"] = { "Uwinymil", 7903995, "aus-arn", "Latn", } m["aus-wdj-pro"] = { "Proto-Iwaidjan", 116773767, "aus-wdj", "Latn", type = "reconstructed", } m["aus-won"] = { "Wong-gie", nil, "aus-pam", "Latn", } m["aus-wul"] = { "Wulguru", 8039196, "aus-dyb", "Latn", } m["aus-ynk"] = { -- contrast nny "Yangkaal", 3913770, "aus-tnk", "Latn", } m["awd-amc-pro"] = { "Proto-Amuesha-Chamicuro", nil, "awd", "Latn", type = "reconstructed", } m["awd-kmp-pro"] = { "Proto-Kampa", nil, "awd", "Latn", type = "reconstructed", } m["awd-prw-pro"] = { "Proto-Paresi-Waura", nil, "awd", "Latn", type = "reconstructed", } m["awd-ama"] = { "Amarizana", 16827787, "awd", "Latn", } m["awd-ana"] = { "Anauyá", 16828252, "awd", "Latn", } m["awd-apo"] = { "Apolista", 16916645, "awd", "Latn", } m["awd-cab"] = { "Cabre", 16850160, "awd", "Latn", } m["awd-gnu"] = { "Guinau", 3504087, "awd", "Latn", } m["awd-kar"] = { "Cariay", 16920253, "awd", "Latn", } m["awd-kaw"] = { "Kawishana", 6379993, "awd-nwk", "Latn", } m["awd-kus"] = { "Kustenau", 5196293, "awd", "Latn", } m["awd-man"] = { "Manao", 6746920, "awd", "Latn", } m["awd-mar"] = { "Marawan", 6755108, "awd", "Latn", } m["awd-mpr"] = { "Maipure", 6736872, "awd", "Latn", } m["awd-mrt"] = { "Mariaté", 16910017, "awd-nwk", "Latn", } m["awd-nwk-pro"] = { "Proto-Nawiki", 116773234, "awd-nwk", "Latn", type = "reconstructed", } m["awd-pai"] = { "Paikoneka", 128807835, "awd", "Latn", } m["awd-pas"] = { "Pasé", 7143168, "awd-nwk", "Latn", } m["awd-pro"] = { "Proto-Arawak", 97573478, "awd", "Latn", type = "reconstructed", } m["awd-she"] = { "Shebayo", 7492248, "awd", "Latn", } m["awd-taa-pro"] = { "Proto-Ta-Arawak", 116773282, "awd-taa", "Latn", type = "reconstructed", } m["awd-wai"] = { "Wainumá", 16910017, "awd-nwk", "Latn", } m["awd-yum"] = { "Yumana", 8061062, "awd-nwk", "Latn", } m["azc-caz"] = { "Cazcan", 5055514, "azc", "Latn", } m["azc-cup-pro"] = { "Proto-Cupan", 116773738, "azc-cup", "Latn", type = "reconstructed", } m["azc-ktn"] = { "Kitanemuk", 3197558, "azc-tak", "Latn", } m["azc-nah-pro"] = { "Proto-Nahuan", 7251860, "azc-nah", "Latn", type = "reconstructed", } m["azc-num-pro"] = { "Proto-Numic", 116773247, "azc-num", "Latn", type = "reconstructed", } m["azc-pro"] = { "Proto-Uto-Aztecan", 96400333, "azc", "Latn", type = "reconstructed", } m["azc-tak-pro"] = { "Proto-Takic", 116773283, "azc-tak", "Latn", type = "reconstructed", } m["azc-tat"] = { "Tataviam", 743736, "azc", "Latn", } m["ber-pro"] = { "Proto-Berber", 2855698, "ber", "Latn", type = "reconstructed", } m["ber-fog"] = { "Fogaha", 107610173, "ber", "Latn", } m["ber-zuw"] = { "Zuwara", 4117169, "ber", "Latn", } m["bnt-bal"] = { "Balong", 93935237, "bnt-bbo", "Latn", } m["bnt-bon"] = { "Boma Nkuu", nil, "bnt", "Latn", } m["bnt-boy"] = { "Boma Yumu", nil, "bnt", "Latn", } m["bnt-bwa"] = { "Bwala", 128810345, "bnt-tek", "Latn", } m["bnt-cmw"] = { "Chimwiini", 4958328, "bnt-swh", "Latn", } m["bnt-ind"] = { "Indanga", 51412803, "bnt", "Latn", } m["bnt-lal"] = { "Lala (South Africa)", 6480154, "bnt-ngu", "Latn", } m["bnt-mpi"] = { "Mpiin", 93937013, "bnt-bdz", "Latn", } m["bnt-mpu"] = { "Mpuono", -- not to be confused with Mbuun zmp 36056, "bnt", "Latn", } m["bnt-ngu-pro"] = { "Proto-Nguni", 961559, "bnt-ngu", "Latn", type = "reconstructed", sort_key = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron}, } m["bnt-phu"] = { "Phuthi", 33796, "bnt-ngu", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute}, } m["bnt-pro"] = { "Proto-Bantu", 3408025, "bnt", "Latn", type = "reconstructed", sort_key = "bnt-pro-sortkey", } m["bnt-sab-pro"] = { "Proto-Sabaki", nil, -- Q2209395 is the code for the Sabaki family "bnt-sab", "Latn", type = "reconstructed", } m["bnt-sbo"] = { "South Boma", nil, "bnt", "Latn", } m["bnt-sts-pro"] = { "Proto-Sotho-Tswana", 116773278, "bnt-sts", "Latn", type = "reconstructed", } m["btk-pro"] = { "Proto-Batak", 116773191, "btk", "Latn", type = "reconstructed", } m["cau-abz-pro"] = { "Proto-Abkhaz-Abaza", 7251831, "cau-abz", "Latn", type = "reconstructed", } m["cau-and-pro"] = { "Proto-Andian", nil, "cau-and", "Latn", type = "reconstructed", } m["cau-ava-pro"] = { "Proto-Avaro-Andian", 116773187, "cau-ava", "Latn", type = "reconstructed", } m["cau-cir-pro"] = { "Proto-Circassian", 7251838, "cau-cir", "Latn", type = "reconstructed", } m["cau-drg-pro"] = { "Proto-Dargwa", 116773205, "cau-drg", "Latn", type = "reconstructed", } m["cau-lzg-pro"] = { "Proto-Lezghian", 116773223, "cau-lzg", "Latn", type = "reconstructed", } m["cau-nec-pro"] = { "Proto-Northeast Caucasian", 116773244, "cau-nec", "Latn", type = "reconstructed", } m["cau-nkh-pro"] = { "Proto-Nakh", 108032840, "cau-nkh", "Latn", type = "reconstructed", } m["cau-nwc-pro"] = { "Proto-Northwest Caucasian", 7251861, "cau-nwc", "Latn", type = "reconstructed", } m["cau-tsz-pro"] = { "Proto-Tsezian", 116773287, "cau-tsz", "Latn", type = "reconstructed", } m["cba-ata"] = { "Atanques", 4812783, "cba", "Latn", } m["cba-cat"] = { "Catío Chibcha", 7083619, "cba", "Latn", } m["cba-dor"] = { "Dorasque", 5297532, "cba", "Latn", } m["cba-dui"] = { "Duit", 3041061, "cba", "Latn", } m["cba-hue"] = { "Huetar", 35514, "cba", "Latn", } m["cba-nut"] = { "Nutabe", 7070405, "cba", "Latn", } m["cba-pro"] = { "Proto-Chibchan", 116773203, "cba", "Latn", type = "reconstructed", } m["ccs-pro"] = { "Proto-Kartvelian", 2608203, "ccs", "Latn", type = "reconstructed", strip_diacritics = { from = {"q̣", "p̣", "ʓ", "ċ"}, to = {"q̇", "ṗ", "ʒ", "c̣"} }, } m["ccs-gzn-pro"] = { "Proto-Georgian-Zan", 23808119, "ccs-gzn", "Latn", type = "reconstructed", strip_diacritics = { from = {"q̣", "p̣", "ʓ", "ċ"}, to = {"q̇", "ṗ", "ʒ", "c̣"} }, } m["cdc-cbm-pro"] = { "Proto-Central Chadic", 116773197, "cdc-cbm", "Latn", type = "reconstructed", } m["cdc-mas-pro"] = { "Proto-Masa", 116773789, "cdc-mas", "Latn", type = "reconstructed", } m["cdc-pro"] = { "Proto-Chadic", 116773201, "cdc", "Latn", type = "reconstructed", } m["cdd-pro"] = { "Proto-Caddoan", 116773725, "cdd", "Latn", type = "reconstructed", } m["cel-bry-pro"] = { "Proto-Brythonic", 1248800, "cel-bry", "Latn, Polyt", sort_key = { Latn = "cel-bry-pro-sortkey", }, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["cel-gal"] = { "Gallaecian", 3094789, "cel-his", } m["cel-gau"] = { "Gaulish", 29977, "cel", "Latn, Polyt, Ital", strip_diacritics = { Latn = {remove_diacritics = c.macron .. c.breve .. c.diaer}, }, sort_key = { Latn = "cel-bry-pro-sortkey", }, -- Ital translit in [[Module:scripts/data]] -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["cel-pro"] = { "Proto-Celtic", 653649, "cel", "Latn", type = "reconstructed", sort_key = "cel-pro-sortkey", } m["chi-pro"] = { "Proto-Chimakuan", 116773734, "chi", "Latn", type = "reconstructed", } m["chm-pro"] = { "Proto-Mari", 116773788, "chm", "Latn", type = "reconstructed", } m["cmc-pro"] = { "Proto-Chamic", 114793834, "cmc", "Latn", type = "reconstructed", } m["crp-bip"] = { "Basque-Icelandic Pidgin", 810378, "crp", "Latn", ancestors = "eu", } m["crp-gep"] = { "West Greenlandic Pidgin", 17036301, "crp", "Latn", ancestors = "kl", } m["crp-kia"] = { "Kiautschou German Pidgin", 108314615, "crp", "Latn", ancestors = "de", } m["crp-mar"] = { "Maroon Spirit Language", 1093206, "crp", "Latn", ancestors = "en", } m["crp-mpp"] = { "Macau Pidgin Portuguese", 128804537, "crp", "Hant, Latn", ancestors = "pt", sort_key = {Hant = "Hani-sortkey"}, } m["crp-rsn"] = { "Russenorsk", 505125, "crp", "Cyrl, Latn", ancestors = "nn, ru", translit = {Cyrl = "ru-translit"}, } m["crp-spp"] = { "Samoan Plantation Pidgin", 7409948, "crp", "Latn", ancestors = "en", } m["crp-slb"] = { "Solombala English", 7558525, "crp", "Cyrl, Latn", ancestors = "en, ru", translit = {Cyrl = "ru-translit"}, } m["crp-tpr"] = { "Taimyr Pidgin Russian", 16930506, "crp", "Cyrl", ancestors = "ru", translit = "ru-translit", } m["csu-bba-pro"] = { "Proto-Bongo-Bagirmi", 116773722, "csu-bba", "Latn", type = "reconstructed", } m["csu-maa-pro"] = { "Proto-Mangbetu", 116773786, "csu-maa", "Latn", type = "reconstructed", } m["csu-pro"] = { "Proto-Central Sudanic", 116773730, "csu", "Latn", type = "reconstructed", } m["csu-sar-pro"] = { "Proto-Sara", 116773809, "csu-sar", "Latn", type = "reconstructed", } m["cus-ash"] = { "Ashraaf", 4805855, "cus-som", "Latn", } m["cus-hec-pro"] = { "Proto-Highland East Cushitic", 116773761, "cus-hec", "Latn", type = "reconstructed", } m["cus-som-pro"] = { "Proto-Somaloid", nil, "cus-som", "Latn", type = "reconstructed", } m["cus-sou-pro"] = { "Proto-South Cushitic", 126081567, "cus-sou", "Latn", type = "reconstructed", } m["cus-pro"] = { "Proto-Cushitic", 116773204, "cus", "Latn", type = "reconstructed", } m["dmn-dam"] = { "Dama (Sierra Leone)", 19601574, "dmn", "Latn", } m["dra-bry"] = { "Beary", 1089116, "qfa-mix", "Mlym, Knda", ancestors = "ml, tcy", -- Knda translit in [[Module:scripts/data]] -- Mlym translit in [[Module:scripts/data]] } m["dra-cen-pro"] = { "Proto-Central Dravidian", nil, "dra-cen", "Latn", type = "reconstructed", } m["dra-mkn"] = { "Middle Kannada", 128810572, "dra-kan", "Knda", -- Knda translit in [[Module:scripts/data]] } m["dra-nor-pro"] = { "Proto-North Dravidian", 124433593, "dra-nor", "Latn", type = "reconstructed", } m["dra-okn"] = { "Old Kannada", 15723156, "dra-kan", "Knda", -- Knda translit in [[Module:scripts/data]] } m["dra-ote"] = { "Old Telugu", 126720868, "dra-tel", "Telu", translit = "te-translit", } m["dra-pro"] = { "Proto-Dravidian", 1702853, "dra", "Latn", type = "reconstructed", } m["dra-sdo-pro"] = { "Proto-South Dravidian I", 104847952, -- Wikipedia's "Proto-South Dravidian" is Proto-South Dravidian I in this scheme. "dra-sdo", "Latn", type = "reconstructed", } m["dra-sdt-pro"] = { "Proto-South Dravidian II", 128885257, "dra-sdt", "Latn", type = "reconstructed", } m["dra-sou-pro"] = { "Proto-South Dravidian", 128886121, "dra-sou", "Latn", type = "reconstructed", } m["egx-dem"] = { "Demotic Egyptian", 36765, "egx", "Latn, Egyd, Polyt", sort_key = { Latn = { remove_diacritics = "'%-%s", from = {"ꜣ", "j", "e", "ꜥ", "y", "w", "b", "p", "f", "m", "n", "r", "l", "ḥ", "ḫ", "h̭", "ẖ", "h", "š", "s", "q", "k", "g", "ṱ", "ṯ", "t", "ḏ", "%.", "⸗"}, to = {p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[15], p[16], p[16], p[17], p[14], p[19], p[18], p[20], p[21], p[22], p[23], p[24], p[23], p[25], p[26], p[26]} }, }, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["dmn-pro"] = { "Proto-Mande", 116773785, "dmn", "Latn", type = "reconstructed", } m["dmn-mdw-pro"] = { "Proto-Western Mande", 116773822, "dmn-mdw", "Latn", type = "reconstructed", } m["dru-pro"] = { "Proto-Rukai", 116773807, "map", "Latn", type = "reconstructed", } m["ero-gsz"] = { "Geshiza", nil, "ero", "Latn", } m["ero-nya"] = { "Nyagrong Minyag", nil, "ero", "Latn", } m["ero-tau"] = { "Stau", nil, "ero", "Latn", } m["esx-esk-pro"] = { "Proto-Eskimo", 7251842, "esx-esk", "Latn", type = "reconstructed", } m["esx-ink"] = { "Inuktun", 1671647, "esx-inu", "Latn", } m["esx-inq"] = { "Inuinnaqtun", 28070, "esx-inu", "Latn", } m["esx-inu-pro"] = { "Proto-Inuit", 60785588, "esx-inu", "Latn", type = "reconstructed", } m["esx-pro"] = { "Proto-Eskimo-Aleut", 7251843, "esx", "Latn", type = "reconstructed", } m["esx-tut"] = { "Tunumiisut", 15665389, "esx-inu", "Latn", } m["euq-pro"] = { "Proto-Basque", 938011, "euq", "Latn", type = "reconstructed", } m["gba-pro"] = { "Proto-Gbaya", nil, "gba", "Latn", type = "reconstructed", } m["gem-pro"] = { "Proto-Germanic", 669623, "gem", "Latn", type = "reconstructed", sort_key = "gem-pro-sortkey", } m["gme-bur"] = { "Burgundian", 47625, "gme", "Latn", } m["gme-cgo"] = { "Crimean Gothic", 36211, "gme", "Latn", } m["gmq-gut"] = { "Gutnish", 1256646, "gmq", "Latn", ancestors = "gmq-ogt", } m["gmq-jmk"] = { "Jamtish", 35512, "gmq-eas", "Latn", } m["gmq-mno"] = { "Middle Norwegian", 3417070, "gmq-wes", "Latn", } m["gmq-oda"] = { "Old Danish", 12330003, "gmq-eas", "Latn, Runr", strip_diacritics = {remove_diacritics = c.macron}, } m["gmq-ogt"] = { "Old Gutnish", 1133488, "gmq", "Latn, Runr", ancestors = "non", } m["gmq-osw"] = { "Old Swedish", 2417210, "gmq-eas", "Latn, Runr", strip_diacritics = {remove_diacritics = c.macron}, } m["gmq-pro"] = { "Proto-Norse", 1671294, "gmq", "Runr", translit = "Runr-translit", } m["gmq-scy"] = { "Scanian", 768017, "gmq-eas", "Latn", } m["gmw-bgh"] = { "Bergish", 329030, "gmw-frk", "Latn", } m["gmw-cfr"] = { "Central Franconian", 572197, "gmw-hgm", "Latn", ancestors = "gmh", wikimedia_codes = "ksh", } m["gmw-ecg"] = { "East Central German", 499344, -- subsumes Q699284, Q152965 "gmw-hgm", "Latn", ancestors = "gmh", } m["gmw-fin"] = { "Fingallian", 3072588, "gmw-ian", "Latn", } m["gmw-gts"] = { "Gottscheerish", 533109, "gmw-hgm", "Latn", ancestors = "bar", } m["gmw-jdt"] = { "Jersey Dutch", 1687911, "gmw-frk", "Latn", ancestors = "nl", } m["gmw-msc"] = { "Middle Scots", 3327000, "gmw-ang", "Latn", ancestors = "enm-esc", } m["gmw-pro"] = { "Proto-West Germanic", 78079021, "gmw", "Latn, Runr", -- type = "reconstructed", -- largely but not entirely reconstructed (like Proto-Norse); see April '24 BP, set back to reconstructed (?) if 'anti-asterisk' is added sort_key = "gmw-pro-sortkey", } m["gmw-rfr"] = { "Rhine Franconian", 707007, "gmw-hgm", "Latn", ancestors = "gmh", } m["gmw-stm"] = { "Sathmar Swabian", 2223059, "gmw-hgm", "Latn", ancestors = "swg", } m["gmw-tsx"] = { "Transylvanian Saxon", 260942, "gmw-hgm", "Latn", ancestors = "gmw-cfr", } m["gmw-vog"] = { "Volga German", 312574, "gmw-hgm", "Latn", ancestors = "gmw-rfr", } m["gmw-zps"] = { "Zipser German", 205548, "gmw-hgm", "Latn", ancestors = "gmh", } m["gn-cls"] = { "Classical Guarani", 17478065, "gn", "Latn", } m["grk-cal"] = { "Calabrian Greek", 1146398, "grk", "Latn, Grek", ancestors = "grk-ita", translit = { Grek = "el-translit", }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-ita"] = { "Italiot Greek", 19720507, "grk", "Latn, Grek", ancestors = "gkm", translit = { Grek = "el-translit", }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-mar"] = { "Mariupol Greek", 4400023, "grk", "Cyrl, Latn, Grek", ancestors = "gkm", translit = { Cyrl = "grk-mar-translit", Grek = "grk-mar-translit", }, override_translit = true, strip_diacritics = { Cyrl = {remove_diacritics = c.acute}, }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-pro"] = { "Proto-Hellenic", 1231805, "grk", "Latn, Polyt", type = "reconstructed", sort_key = {Latn = { from = {"ʰ", "ʷ"}, to = {"h", "w"}, remove_diacritics = c.grave .. c.acute .. c.macron .. c.breve .. c.caron }}, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] -- NOTE: formerly no translit specified for Polyt; presumably an accidental omission; if not, set Polyt = false in -- the translit section } m["hmn-pro"] = { "Proto-Hmong", 116773210, "hmn", "Latn", type = "reconstructed", } m["hmx-mie-pro"] = { "Proto-Mien", 116773229, "hmx-mie", "Latn", type = "reconstructed", } m["hmx-pro"] = { "Proto-Hmong-Mien", 7251846, "hmx", "Latn", type = "reconstructed", } m["hyx-pro"] = { "Proto-Armenian", 3848498, "hyx", "Latn", type = "reconstructed", } m["iir-nur-pro"] = { "Proto-Nuristani", 116773248, "iir-nur", "Latn", type = "reconstructed", } m["iir-pro"] = { "Proto-Indo-Iranian", 966439, "iir", "Latn", type = "reconstructed", } m["ijo-pro"] = { "Proto-Ijoid", 116773766, "ijo", "Latn", type = "reconstructed", } m["inc-apa"] = { "Apabhramsa", 616419, "inc-mid", "Deva, Shrd, Sidd", ancestors = "pra", translit = { Deva = "sa-translit", -- Shrd translit in [[Module:scripts/data]] -- Sidd translit in [[Module:scripts/data]] }, } m["inc-ash"] = { "Ashokan Prakrit", 104854379, "inc-mid", "Brah, Khar", ancestors = "sa", translit = { -- Brah translit in [[Module:scripts/data]] Khar = "Khar-translit", }, } m["inc-dng-pro"] = { "Proto-Dangari", nil, "inc-dng", "Latn", type = "reconstructed", } m["inc-kam"] = { "Kamarupi Prakrit", 6356097, "inc-bas", "Brah, Sidd", -- Brah, Sidd translit in [[Module:scripts/data]] } m["inc-kho"] = { "Kholosi", 24952008, "inc-snd", "Latn", } m["inc-krd-pro"] = { "Proto-Kamta", 128816843, "inc-bas", "Latn", ancestors = "inc-kam", type = "reconstructed", } m["inc-mas"] = { "Middle Assamese", 128806836, "inc-bas", "as-Beng", ancestors = "inc-oas", translit = "inc-mas-translit", } m["inc-mbn"] = { "Gitnang Benggali", --TLCHANGE 113559927, "inc-bas", "Beng", ancestors = "inc-obn", translit = "inc-mbn-translit", english_name = "Middle Bengali", --TLCHANGE } m["inc-mgu"] = { "Middle Gujarati", 24907429, "inc-wes", "Deva", ancestors = "inc-ogu", } m["inc-mor"] = { "Middle Odia", 128810882, "inc-eas", "Orya", ancestors = "inc-oor", } m["inc-oas"] = { "Early Assamese", 85758237, "inc-bas", "as-Beng", ancestors = "inc-kam", translit = "inc-oas-translit", } m["inc-oaw"] = { "Old Awadhi", nil, "inc-hie", "Deva, Kthi, ur-Arab", strip_diacritics = { from = {"هٔ", "ۂ"}, -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه" to = {"ہ", "ہ"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, translit = { Deva = "sa-translit", Kthi = "sa-Kthi-translit", ["ur-Arab"] = "inc-ohi-translit", }, } m["inc-obn"] = { "Lumang Benggali", --TLCHANGE 113559926, "inc-bas", "Beng", english_name = "Old Bengali", --TLCHANGE } m["inc-ogu"] = { "Old Gujarati", 24907427, "inc-wes", "Deva", translit = "sa-translit", } m["inc-ohi"] = { "Lumang Hindi", --TLCHANGE 48767781, "inc-hiw", "Deva, ur-Arab", strip_diacritics = { from = {"هٔ", "ۂ"}, -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه" to = {"ہ", "ہ"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, translit = { Deva = "sa-translit", ["ur-Arab"] = "inc-ohi-translit", }, english_name = "Old Hindi", --TLCHANGE } m["inc-oor"] = { "Old Odia", 128807801, "inc-eas", "Orya", } m["inc-opa"] = { "Old Punjabi", 115270971, "inc-pan", "Guru, pa-Arab", translit = { Guru = "inc-opa-Guru-translit", ["pa-Arab"] = "pa-Arab-translit", }, strip_diacritics = {remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun}, } m["inc-pro"] = { "Proto-Indo-Aryan", 23808344, "inc", "Latn", type = "reconstructed", } m["ine-ana-pro"] = { "Proto-Anatolian", 7251833, "ine-ana", "Latn", type = "reconstructed", } m["ine-bsl-pro"] = { "Proto-Balto-Slavic", 1703347, "ine-bsl", "Latn", type = "reconstructed", sort_key = { from = {"[áā]", "[éēḗ]", "[íī]", "[óōṓ]", "[úū]", c.acute, c.macron, "ˀ"}, to = {"a", "e", "i", "o", "u"} }, } m["ine-kal"] = { "Kalašma", 122770439, "ine-ana", "Xsux", } m["ine-pae"] = { "Paeonian", 2705672, "ine", "Polyt", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["ine-pro"] = { "Proto-Indo-Europeo", --TLCHANGE 37178, "ine", "Latn", type = "reconstructed", sort_key = { from = {"[áā]", "[éēḗ]", "[íī]", "[óōṓ]", "[úū]", "ĺ", "ḿ", "ń", "ŕ", "ǵ", "ḱ", "ʰ", "ʷ", "₁", "₂", "₃", c.ringbelow, c.acute, c.macron}, to = {"a", "e", "i", "o", "u", "l", "m", "n", "r", "g'", "k'", "¯h", "¯w", "1", "2", "3"} }, english_name = "Proto-Indo-European", --TLCHANGE spanish_name = "Protoindoeuropeo", --TLCHANGE } m["ine-toc-pro"] = { "Proto-Tocharian", 104841462, "ine-toc", "Latn", type = "reconstructed", } m["xme-old"] = { "Old Median", 36461, "xme", "Polyt, Latn", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["xme-mid"] = { "Middle Median", 12836150, "xme", "Latn", } m["xme-ker"] = { "Kermanic", 129850, "xme", "fa-Arab, Latn, Hebr", ancestors = "xme-mid", -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["xme-taf"] = { "Tafreshi", nil, "xme", "fa-Arab, Latn", ancestors = "xme-mid", } m["xme-ttc-pro"] = { "Proto-Tatic", 122973870, "xme-ttc", "Latn", ancestors = "xme-mid", } m["xme-kls"] = { "Kalasuri", nil, "xme-ttc", ancestors = "xme-ttc-nor", } m["xme-klt"] = { "Kilit", 3612452, "xme-ttc", "Cyrl", -- and fa-Arab? } m["xme-ott"] = { "Old Tati", 434697, "xme-ttc", "fa-Arab, Latn", } m["ira-kms-pro"] = { "Proto-Komisenian", 116773777, "ira-kms", "Latn", type = "reconstructed", } m["ira-mpr-pro"] = { "Proto-Medo-Parthian", 116773227, "ira-mpr", "Latn", type = "reconstructed", } m["ira-pat-pro"] = { "Proto-Pathan", 116773255, "ira-pat", "Latn", type = "reconstructed", } m["ira-pro"] = { "Proto-Iranian", 4167865, "ira", "Latn", type = "reconstructed", } m["ira-zgr-pro"] = { "Proto-Zaza-Gorani", 116775031, "ira-zgr", "Latn", type = "reconstructed", } m["xsc-pro"] = { "Proto-Scythian", 116773273, "xsc", "Latn", type = "reconstructed", } m["xsc-sar-pro"] = { "Proto-Sarmatian", 116773249, "xsc-sar", "Latn", type = "reconstructed", } m["xsc-skw-pro"] = { "Proto-Saka-Wakhi", 116773267, "xsc-skw", "Latn", type = "reconstructed", } m["xsc-sak-pro"] = { "Proto-Saka", 116773264, "xsc-sak", "Latn", type = "reconstructed", } m["ira-sym-pro"] = { "Proto-Shughni-Yazghulami-Munji", 116773813, "ira-sym", "Latn", type = "reconstructed", } m["ira-sgi-pro"] = { "Proto-Sanglechi-Ishkashimi", 116773808, "ira-sgi", "Latn", type = "reconstructed", } m["ira-mny-pro"] = { "Proto-Munji-Yidgha", 116773792, "ira-mny", "Latn", type = "reconstructed", } m["ira-shy-pro"] = { "Proto-Shughni-Yazghulami", 116773812, "ira-shy", "Latn", type = "reconstructed", } m["ira-shr-pro"] = { "Proto-Shughni-Roshani", 116773811, "ira-shr", "Latn", type = "reconstructed", } m["ira-sgc-pro"] = { "Proto-Sogdic", 116773276, "ira-sgc", "Latn", type = "reconstructed", } m["ira-wnj"] = { "Vanji", 3398419, "ira-shy", "Latn", } m["iro-ere"] = { "Erie", 5388365, "iro-nor", "Latn", } m["iro-min"] = { "Mingo", 128531, "iro-nor", "Latn", ietf_subtag = "i-mingo", -- grandfathered IETF tag } m["iro-nor-pro"] = { "Proto-North Iroquoian", 116773242, "iro-nor", "Latn", type = "reconstructed", } m["iro-pro"] = { "Proto-Iroquoian", 7251852, "iro", "Latn", type = "reconstructed", } m["itc-pro"] = { "Proto-Italiko", -- tlchange 17102720, "itc", "Latn", type = "reconstructed", } m["itc-psa"] = { "Pre-Samnite", 7239186, "itc-sbl", "Ital, Polyt, Latn", -- Ital translit in [[Module:scripts/data]] (NOTE: formerly not present, probably an accidental omission) -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["jpx-hcj"] = { "Hachijō", 5637049, "jpx", "Jpan", ancestors = "ojp-eas", translit = s["jpx-translit"], display_text = s["jpx-displaytext"], strip_diacritics = s["jpx-stripdiacritics"], sort_key = s["jpx-sortkey"], } m["jpx-pro"] = { "Proto-Japonic", 3924309, "jpx", "Latn", type = "reconstructed", } m["jpx-ryu-pro"] = { "Proto-Ryukyuan", 56349069, "jpx-ryu", "Latn", type = "reconstructed", } m["kar-pro"] = { "Proto-Karen", 85794783, "kar", "Latn", type = "reconstructed", } m["kca-eas"] = { "Eastern Khanty", 30304622, "kca", "Cyrl", translit = "kca-translit", override_translit = true, -- TODO temporary until MediaWiki supports Unicode 16 (probably requires a PHP update from their side) sort_key = { Cyrl = { from = {"ᲊ"}, to = {"Ᲊ"} } }, } m["kca-nor"] = { "Northern Khanty", 30304527, "kca", "Cyrl", translit = "kca-translit", override_translit = true, -- TODO temporary until MediaWiki supports Unicode 16 (probably requires a PHP update from their side) sort_key = { Cyrl = { from = {"ᲊ"}, to = {"Ᲊ"} } }, } m["kca-pro"] = { "Proto-Khanty", 127505171, "kca", "Latn", type = "reconstructed", } m["kca-sou"] = { "Southern Khanty", 30304618, "kca", "Cyrl", translit = "kca-translit", override_translit = true, } m["khi-kho-pro"] = { "Proto-Khoe", 116773218, "khi-kho", "Latn", type = "reconstructed", } m["khi-kun"] = { "ǃKung", 32904, "khi-kxa", "Latn", } m["ko-ear"] = { "Early Modern Korean", 756014, "qfa-kor", "Kore", ancestors = "okm", translit = "okm-translit", -- Kore strip_diacritics in [[Module:scripts/data]] } m["kro-pro"] = { "Proto-Kru", 116773778, "kro", "Latn", type = "reconstructed", } m["ku-pro"] = { "Proto-Kurdish", 116773221, "ku", "Latn", type = "reconstructed", } m["map-ata-pro"] = { "Proto-Atayalic", 116773151, "map-ata", "Latn", type = "reconstructed", } m["map-bms"] = { "Banyumasan", 33219, "map", "Latn, Java", } m["map-pro"] = { "Proto-Austronesian", 49230, "map", "Latn", type = "reconstructed", } m["mis-hkl"] = { "Kelantan Peranakan Hokkien", 108794818, "qfa-mix", ancestors = "nan-hbl, sou, mfa", } m["mis-idn"] = { "Idiom Neutral", 35847, "art", "Latn", type = "appendix-constructed", } m["mis-isa"] = { "Isaurian", 16956868, nil, -- "Xsux, Hluw, Latn", } m["mis-jie"] = { "Jie", 124424186, nil, "Hani", sort_key = "Hani-sortkey", } m["mis-jzh"] = { "Jizhao", 45242758, "qfa-bej", "Latn", } m["mis-kas"] = { "Kassite", 35612, nil, "Xsux", } m["mis-mmd"] = { "Mimi of Decorse", 6862206, nil, "Latn", } m["mis-mmn"] = { "Mimi of Nachtigal", 6862207, nil, "Latn", } m["mis-phi"] = { "Philistine", 2230924, nil, "Phnx", -- Phnx translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission) } m["mis-rou"] = { "Rouran", 48816637, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-tdl"] = { "Turdulian", 133176492, } m["mis-tdt"] = { "Turdetanian", 133176461, } m["mis-tnw"] = { "Tangwang", 7683179, "qfa-mix", "Latn", ancestors = "cmn, sce", } m["mis-tuh"] = { "Tuyuhun", 48816625, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-tuo"] = { "Tuoba", 48816629, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-wuh"] = { "Wuhuan", 118976867, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-xbi"] = { "Xianbei", 4448647, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-xnu"] = { "Xiongnu", 10901674, nil, "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mjg-mgl"] = { "Mongghul", 53765528, "mjg", "Latn", -- also Mong, Cyrl ? } m["mjg-mgr"] = { "Mangghuer", 56285392, "mjg", "Latn", -- also Mong, Cyrl ? } m["mkh-asl-pro"] = { "Proto-Aslian", 55630680, "mkh-asl", "Latn", type = "reconstructed", } m["mkh-ban-pro"] = { "Proto-Bahnaric", 116773189, "mkh-ban", "Latn", type = "reconstructed", } m["mkh-kat-pro"] = { "Proto-Katuic", 116773772, "mkh-kat", "Latn", type = "reconstructed", } m["mkh-khm-pro"] = { "Proto-Khmuic", 116773774, "mkh-khm", "Latn", type = "reconstructed", } m["mkh-kmr-pro"] = { "Proto-Khmeric", 55630684, "mkh-kmr", "Latn", type = "reconstructed", } m["mkh-mmn"] = { "Middle Mon", 121337926, "mkh-mnc", "Latn, Mymr", --and also Pallava ancestors = "omx", } m["mkh-mnc-pro"] = { "Proto-Monic", 116773231, "mkh-mnc", "Latn", type = "reconstructed", } m["mkh-mvi"] = { "Middle Vietnamese", 9199, "mkh-vie", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mkh-pal-pro"] = { "Proto-Palaungic", 104847372, "mkh-pal", "Latn", type = "reconstructed", } m["mkh-pea-pro"] = { "Proto-Pearic", 116773804, "mkh-pea", "Latn", type = "reconstructed", } m["mkh-pkn-pro"] = { "Proto-Pakanic", 116773803, "mkh-pkn", "Latn", type = "reconstructed", } m["mkh-pro"] = { --This will be merged into 2015 aav-pro. "Proto-Mon-Khmer", 7251859, "mkh", "Latn", type = "reconstructed", } m["mnw-tha"] = { -- To be removed. "Thai Mon", nil, "mkh-mnc", "Mymr, Thai", ancestors = "mkh-mmn", sort_key = { from = {"[%p]", "ျ", "ြ", "ွ", "ှ", "ၞ", "ၟ", "ၠ", "ၚ", "ဿ", "[็-๎]", "([เแโใไ])([ก-ฮ])ฺ?"}, to = {"", "္ယ", "္ရ", "္ဝ", "္ဟ", "္န", "္မ", "္လ", "င", "သ္သ", "", "%2%1"} }, } m["mkh-vie-pro"] = { "Proto-Vietic", 109432616, "mkh-vie", "Latn", type = "reconstructed", } m["mns-cen"] = { "Central Mansi", 128810384, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mns-nor"] = { "Northern Mansi", 30304537, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mns-pro"] = { "Proto-Mansi", 128883093, "mns", "Latn", type = "reconstructed", } m["mns-sou"] = { "Southern Mansi", 30304629, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mun-pro"] = { "Proto-Munda", 105102373, "mun", "Latn", type = "reconstructed", } m["myn-chl"] = { -- the stage after ''emy'' "Ch'olti'", 873995, "myn", "Latn", } m["myn-pro"] = { "Proto-Mayan", 3321532, "myn", "Latn", type = "reconstructed", } m["nai-ala"] = { "Alazapa", 128810233, nil, "Latn", } m["nai-bay"] = { "Bayogoula", 1563704, nil, "Latn", } m["nai-cal"] = { "Calusa", 51782, nil, "Latn", } m["nai-chi"] = { "Chiquimulilla", 25339627, "nai-xin", "Latn", } m["nai-chu-pro"] = { "Proto-Chumash", 116773736, "nai-chu", "Latn", type = "reconstructed", } m["nai-cig"] = { "Ciguayo", 20741700, nil, "Latn", } m["nai-ckn-pro"] = { "Proto-Chinookan", 116773735, "nai-ckn", "Latn", type = "reconstructed", } m["nai-guz"] = { "Guazacapán", 19572028, "nai-xin", "Latn", } m["nai-hit"] = { "Hitchiti", 1542882, "nai-mus", "Latn", } m["nai-ipa"] = { "Ipai", 3027474, "nai-yuc", "Latn", } m["nai-jtp"] = { "Jutiapa", nil, "nai-xin", "Latn", } m["nai-jum"] = { "Jumaytepeque", 25339626, "nai-xin", "Latn", } m["nai-kat"] = { "Kathlamet", 6376639, "nai-ckn", "Latn", } m["nai-klp-pro"] = { "Proto-Kalapuyan", 116773771, "nai-klp", "Latn", type = "reconstructed", } m["nai-knm"] = { "Konomihu", 3198734, "nai-shs", "Latn", } m["nai-kum"] = { "Kumeyaay", 4910139, "nai-yuc", "Latn", } m["nai-mac"] = { "Macoris", 21070851, nil, "Latn", } m["nai-mdu-pro"] = { "Proto-Maidun", 116773784, "nai-mdu", "Latn", type = "reconstructed", } m["nai-miz-pro"] = { "Proto-Mixe-Zoque", 7251858, "nai-miz", "Latn", type = "reconstructed", } m["nai-mus-pro"] = { "Proto-Muskogean", 116775368, "nai-mus", "Latn", type = "reconstructed", } m["nai-nao"] = { "Naolan", 6964594, nil, "Latn", } m["nai-nrs"] = { "New River Shasta", 7011254, "nai-shs", "Latn", } m["nai-okw"] = { "Okwanuchu", 3350126, "nai-shs", "Latn", } m["nai-per"] = { "Pericú", 3375369, nil, "Latn", } m["nai-pic"] = { "Picuris", 7191257, "nai-kta", "Latn", } m["nai-plp-pro"] = { "Proto-Plateau Penutian", 116773806, "nai-plp", "Latn", type = "reconstructed", } m["nai-pom-pro"] = { "Proto-Pomo", 116773262, "nai-pom", "Latn", type = "reconstructed", } m["nai-qng"] = { "Quinigua", 36360, nil, "Latn", } m["nai-sca-pro"] = { -- NB 'sio-pro' "Proto-Siouan" which is Proto-Western Siouan "Proto-Siouan-Catawban", 116773275, "nai-sca", "Latn", type = "reconstructed", } m["nai-sin"] = { "Sinacantán", 24190249, "nai-xin", "Latn", } m["nai-sln"] = { "Salvadoran Lenca", 3229434, "nai-len", "Latn", } m["nai-spt"] = { "Sahaptin", 3833015, "nai-shp", "Latn", } m["nai-tap"] = { "Tapachultec", 7684401, "nai-miz", "Latn", } m["nai-taw"] = { "Tawasa", 7689233, nil, "Latn", } m["nai-teq"] = { "Tequistlatec", 2964454, "nai-tqn", "Latn", } m["nai-tip"] = { "Tipai", 3027471, "nai-yuc", "Latn", } m["nai-tot-pro"] = { "Proto-Totozoquean", 116773285, "nai-tot", "Latn", type = "reconstructed", } m["nai-tsi-pro"] = { "Proto-Tsimshianic", nil, "nai-tsi", "Latn", type = "reconstructed", } m["nai-utn-pro"] = { "Proto-Utian", 116773290, "nai-utn", "Latn", type = "reconstructed", } m["nai-wai"] = { "Waikuri", 3118702, nil, "Latn", } m["nai-wji"] = { "Western Jicaque", 3178610, "nai-jcq", "Latn", } m["nai-yup"] = { "Yupiltepeque", 25339628, "nai-xin", "Latn", } m["nan-dat"] = { "Datian Min", 19855572, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-hbl"] = { "Hokkien", 1624231, "zhx-nan", "Hants, Latn, Bopo, Kana", wikimedia_codes = "zh-min-nan", generate_forms = "zh-generateforms", sort_key = { Hani = "Hani-sortkey", Kana = "Kana-sortkey" }, } m["nan-hlh"] = { "Hailufeng Min", 120755728, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-lnx"] = { "Longyan Min", 6674568, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-tws"] = { "Teochew", 36759, "zhx-nan", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", } m["nan-zhe"] = { "Zhenan Min", 3846710, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-zsh"] = { "Sanxiang Min", 7420769, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nds-de"] = { "German Low German", 25433, "gmw-lgm", "Latn", ancestors = "nds", ietf_subtag = "nds-DE", -- should we make this the actual code? wikimedia_codes = "nds", } m["nds-nl"] = { "Dutch Low Saxon", 516137, "gmw-lgm", "Latn", ancestors = "nds", ietf_subtag = "nds-NL", -- should we make this the actual code? wikimedia_codes = "nds-nl", } m["ngf-bin-pro"] = { "Proto-Binanderean", 137881672, "ngf-bin", "Latn", type = "reconstructed", } m["ngf-pro"] = { "Proto-Trans-New Guinea", 85794785, "ngf", "Latn", type = "reconstructed", } m["nic-bco-pro"] = { "Proto-Benue-Congo", 116773194, "nic-bco", "Latn", type = "reconstructed", } m["nic-bod-pro"] = { "Proto-Bantoid", 116773190, "nic-bod", "Latn", type = "reconstructed", } m["nic-eov-pro"] = { "Proto-Eastern Oti-Volta", 116773753, "nic-eov", "Latn", type = "reconstructed", } m["nic-gns-pro"] = { "Proto-Gurunsi", 116773759, "nic-gns", "Latn", type = "reconstructed", } m["nic-grf-pro"] = { "Proto-Grassfields", 116773755, "nic-grf", "Latn", type = "reconstructed", } m["nic-gur-pro"] = { "Proto-Gur", 116773758, "nic-gur", "Latn", type = "reconstructed", } m["nic-jkn-pro"] = { "Proto-Jukunoid", 116773769, "nic-jkn", "Latn", type = "reconstructed", } m["nic-lcr-pro"] = { "Proto-Lower Cross River", 116773782, "nic-lcr", "Latn", type = "reconstructed", } m["nic-ogo-pro"] = { "Proto-Ogoni", 116773799, "nic-ogo", "Latn", type = "reconstructed", } m["nic-ovo-pro"] = { "Proto-Oti-Volta", 116773802, "nic-ovo", "Latn", type = "reconstructed", } m["nic-plt-pro"] = { "Proto-Plateau", 116773805, "nic-plt", "Latn", type = "reconstructed", } m["nic-pro"] = { "Proto-Niger-Congo", 108000748, "nic", "Latn", type = "reconstructed", } m["nic-ubg-pro"] = { "Proto-Ubangian", 116773818, "nic-ubg", "Latn", type = "reconstructed", } m["nic-ucr-pro"] = { "Proto-Upper Cross River", 116773819, "nic-ucr", "Latn", type = "reconstructed", } m["nic-vco-pro"] = { "Proto-Volta-Congo", 116773293, "nic-vco", "Latn", type = "reconstructed", } m["nub-har"] = { "Haraza", 19572059, "nub", "Arab, Latn", } m["nub-pro"] = { "Proto-Nubian", 116773246, "nub", "Latn", type = "reconstructed", } m["omq-cha-pro"] = { "Proto-Chatino", 116773202, "omq-cha", "Latn", type = "reconstructed", } m["omq-maz-pro"] = { "Proto-Mazatec", 116773790, "omq-maz", "Latn", type = "reconstructed", } m["omq-mix-pro"] = { "Proto-Mixtecan", 21573423, "omq-mix", "Latn", type = "reconstructed", } m["omq-mxt-pro"] = { "Proto-Mixtec", 21573424, "omq-mxt", "Latn", type = "reconstructed", } m["omq-otp-pro"] = { "Proto-Oto-Pamean", 116773251, "omq-otp", "Latn", type = "reconstructed", } m["omq-pro"] = { "Proto-Oto-Manguean", 33669, "omq", "Latn", type = "reconstructed", } m["omq-sjq"] = { "San Juan Quiahije Chatino", 17003130, "omq-cha", "Latn", } m["omq-tel"] = { "Teposcolula Mixtec", nil, "omq-mxt", "Latn", } m["omq-teo"] = { "Teojomulco Chatino", 25340451, "omq-cha", "Latn", } m["omq-tri-pro"] = { "Proto-Triqui", 116773817, "omq-tri", "Latn", type = "reconstructed", } m["omq-zap-pro"] = { "Proto-Zapotecan", 116773297, "omq-zap", "Latn", type = "reconstructed", } m["omq-zpc-pro"] = { "Proto-Zapotec", 116773296, "omq-zpc", "Latn", type = "reconstructed", } m["omv-aro-pro"] = { "Proto-Aroid", 116773721, "omv-aro", "Latn", type = "reconstructed", } m["omv-diz-pro"] = { "Proto-Dizoid", 116773750, "omv-diz", "Latn", type = "reconstructed", } m["omv-pro"] = { "Proto-Omotic", 116773800, "omv", "Latn", type = "reconstructed", } m["oto-otm-pro"] = { "Proto-Otomi", 5908710, "oto-otm", "Latn", type = "reconstructed", } m["oto-pro"] = { "Proto-Otomian", 116773252, "oto", "Latn", type = "reconstructed", } m["paa-kmn"] = { "Kómnzo", 18344310, "paa-wko", "Latn", } m["paa-kwn"] = { "Kuwani", 6449056, "qfa-unc", -- poorly attested, possibly the same as or related to Kalabra "Latn", } m["paa-lei"] = { "Leitre", 85776228, "paa-isk", } m["paa-nha-pro"] = { "Proto-North Halmahera", 116773241, "paa-nha", "Latn", type = "reconstructed" } m["paa-nun"] = { "Nungon", 128807788, "ngf-ynu", "Latn", } m["phi-din"] = { "Dinapigue Agta", 16945774, "phi", "Latn", } m["phi-kal-pro"] = { "Proto-Kalamian", 116773213, "phi-kal", "Latn", type = "reconstructed", } m["phi-nag"] = { "Nagtipunan Agta", 16966111, "phi", "Latn", } m["phi-pro"] = { "Proto-Pilipino", --TLCHANGE 18204898, "phi", "Latn", type = "reconstructed", english_name = "Proto-Philippine", --TLCHANGE } m["poz-abi"] = { "Abai", 19570729, "poz-san", "Latn", } m["poz-bal"] = { "Baliledo", 4850912, "poz", "Latn", } m["poz-btk-pro"] = { "Proto-Bungku-Tolaki", 116773724, "poz-btk", "Latn", type = "reconstructed", } m["poz-cet-pro"] = { "Proto-Central-Eastern Malayo-Polynesian", 2269883, "poz-cet", "Latn", type = "reconstructed", } m["poz-hce-pro"] = { "Proto-Halmahera-Cenderawasih", 116773209, "poz-hce", "Latn", type = "reconstructed", } m["poz-lgx-pro"] = { "Proto-Lampungic", 116773222, "poz-lgx", "Latn", type = "reconstructed", } m["poz-mcm-pro"] = { "Proto-Malayo-Chamic", 116773225, "poz-mcm", "Latn", type = "reconstructed", } m["poz-mic-pro"] = { "Proto-Micronesian", 111939079, "poz-mic", "Latn", type = "reconstructed", } m["poz-mly-pro"] = { "Proto-Malayic", 98057728, "poz-mly", "Latn", type = "reconstructed", } m["poz-msa-pro"] = { "Proto-Malayo-Sumbawan", 116773226, "poz-msa", "Latn", type = "reconstructed", } m["poz-oce-pro"] = { "Proto-Oceanic", 141741, "poz-oce", "Latn", type = "reconstructed", } m["poz-pep-pro"] = { "Proto-Eastern Polynesian", 113988745, "poz-pep", "Latn", type = "reconstructed", } m["poz-pnp-pro"] = { "Proto-Nuclear Polynesian", 113988746, "poz-pnp", "Latn", type = "reconstructed", } m["poz-pol-pro"] = { "Proto-Polynesian", 1658709, "poz-pol", "Latn", type = "reconstructed", } m["poz-pro"] = { "Proto-Malayo-Polynesian", 3832960, "poz", "Latn", type = "reconstructed", } m["poz-sml"] = { "Sarawak Malay", 4251702, "poz-mly", "Latn, ms-Arab", } m["poz-ssw-pro"] = { "Proto-South Sulawesi", 116773279, "poz-ssw", "Latn", type = "reconstructed", } m["poz-swa-pro"] = { "Proto-North Sarawak", 116773243, "poz-swa", "Latn", type = "reconstructed", } m["poz-ter"] = { "Terengganu Malay", 4207412, "poz-mly", "Latn, ms-Arab", } m["pqe-pro"] = { "Proto-Eastern Malayo-Polynesian", 2269883, "pqe", "Latn", type = "reconstructed", } m["pra-niy"] = { "Niya Prakrit", 11991601, "inc-mid", "Khar", ancestors = "inc-ash", translit = "Khar-translit", } m["qfa-adm-pro"] = { "Proto-Great Andamanese", 116773756, "qfa-adm", "Latn", type = "reconstructed", } m["qfa-bet-pro"] = { "Proto-Be-Tai", 116773193, "qfa-bet", "Latn", type = "reconstructed", } m["qfa-cka-pro"] = { "Proto-Chukotko-Kamchatkan", 7251837, "qfa-cka", "Latn", type = "reconstructed", } m["qfa-hur-pro"] = { "Proto-Hurro-Urartian", 116773211, "qfa-hur", "Latn", type = "reconstructed", } m["qfa-kad-pro"] = { "Proto-Kadu", 116773770, "qfa-kad", "Latn", type = "reconstructed", } m["qfa-kms-pro"] = { "Proto-Kam-Sui", 55630682, "qfa-kms", "Latn", type = "reconstructed", } m["qfa-kor-pro"] = { "Proto-Koreanic", 467883, "qfa-kor", "Latn", type = "reconstructed", } m["qfa-kra-pro"] = { "Proto-Kra", 7251854, "qfa-kra", "Latn", type = "reconstructed", } m["qfa-lic-pro"] = { "Proto-Hlai", 7251845, "qfa-lic", "Latn", type = "reconstructed", } m["qfa-onb-pro"] = { "Proto-Be", 116773192, "qfa-onb", "Latn", type = "reconstructed", } m["qfa-ong-pro"] = { "Proto-Ongan", 116773801, "qfa-ong", "Latn", type = "reconstructed", } m["qfa-tak-pro"] = { "Proto-Kra-Dai", 104901616, "qfa-tak", "Latn", type = "reconstructed", } m["qfa-yen-pro"] = { "Proto-Yeniseian", 27639, "qfa-yen", "Latn", type = "reconstructed", } m["qfa-yuk-pro"] = { "Proto-Yukaghir", 116773294, "qfa-yuk", "Latn", type = "reconstructed", } m["qwe-kch"] = { "Kichwa", 1740805, "qwe", "Latn", ancestors = "qu", } m["qwe-pro"] = { "Proto-Quechuan", 5575757, "qwe", "Latn", type = "reconstructed", } m["roa-ang"] = { "Angevin", 56782, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-bbn"] = { "Bourbonnais-Berrichon", 2899128, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-brg"] = { "Bourguignon", 508332, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-can"] = { "Cantabrian", 917021, "roa-asl", "Latn", } m["roa-cha"] = { "Champenois", 430018, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-fcm"] = { "Franc-Comtois", 510561, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-gal"] = { "Gallo", 37300, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-gib"] = { "Gallo-Italic of Basilicata", 3094838, "roa-git", ancestors = "pms-old", "Latn", } m["roa-gis"] = { "Gallo-Italic of Sicily", 2629019, "roa-git", "Latn", ancestors = "pms-old", } m["roa-leo"] = { "Leones", --TLCHANGE 34108, "roa-asl", "Latn", english_name = "Leonese", --TLCHANGE spanish_name = "Leonés", --TLCHANGE } m["roa-lor"] = { "Lorrain", 671198, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-oca"] = { "Lumang Katalan", --TLCHANGE 15478520, "roa-ocr", "Latn", sort_key = {remove_diacritics = c.grave .. c.acute .. c.diaer .. c.cedilla .. "·"}, english_name = "Old Catalan", --TLCHANGE } m["roa-ole"] = { "Lumang Leones", --TLCHANGE 125977465, "roa-asl", "Latn", english_name = "Old Leonese", --TLCHANGE } m["roa-ona"] = { "Old Navarro-Aragonese", 2736184, "roa-nar", "Latn", } m["roa-opt"] = { "Lumang Galisyano-Portuges", 1072111, "roa-gap", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ}, } m["roa-orl"] = { "Orléanais", 28497058, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-poi"] = { "Poitevin-Saintongeais", 514123, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-tar"] = { "Tarantino", 695526, "roa-itr", "Latn", wikimedia_codes = "roa-tara", } m["sai-all"] = { "Allentiac", 19570789, "sai-hrp", "Latn", } m["sai-and"] = { -- not to be confused with 'cbc' or 'ano' "Andoquero", 16828359, "sai-wit", "Latn", } m["sai-ayo"] = { "Ayomán", 16937754, "sai-jir", "Latn", } m["sai-bae"] = { "Baenan", 3401998, "qfa-unc", -- extinct, poorly attested; only known through 9 words "Latn", } m["sai-bag"] = { "Bagua", 5390321, "qfa-unc", -- extinct, poorly attested; possibly Cariban "Latn", } m["sai-bet"] = { "Betoi", 926551, "qfa-iso", "Latn", } m["sai-bor-pro"] = { "Proto-Boran", nil, "sai-bor", "Latn", } m["sai-cac"] = { "Cacán", 945482, "qfa-unc", -- extinct, poorly attested; no consensus on classification "Latn", } m["sai-caq"] = { "Caranqui", 2937753, "sai-bar", "Latn", } m["sai-car-pro"] = { "Proto-Cariban", 116773196, "sai-car", "Latn", type = "reconstructed", } m["sai-cat"] = { "Catacao", 5051136, "sai-ctc", "Latn", } m["sai-cer-pro"] = { "Proto-Cerrado", 116773200, "sai-cer", "Latn", type = "reconstructed", } m["sai-chi"] = { "Chirino", 5390321, "qfa-unc", -- extinct, only four words known; possibly related to Candoshi-Shapra (cbu) "Latn", } m["sai-chn"] = { "Chaná", 5072718, "sai-crn", "Latn", } m["sai-chp"] = { "Chapacura", 5072884, "sai-cpc", "Latn", } m["sai-chr"] = { "Charrua", 5086680, "sai-crn", "Latn", } m["sai-chu"] = { "Churuya", 5118339, "sai-guh", "Latn", } m["sai-cje-pro"] = { "Proto-Central Jê", 116773198, "sai-cje", "Latn", type = "reconstructed", } m["sai-cmg"] = { "Comechingon", 6644203, "qfa-unc", -- extinct, poorly attested; no consensus on classification "Latn", } m["sai-cno"] = { "Chono", 5104704, "qfa-unc", -- extinct, poorly attested; no consensus on classification, possibly spurious "Latn", } m["sai-cnr"] = { "Cañari", 5055572, "qfa-unc", -- extinct, poorly attested; possibly Chimuan or Barbacoan "Latn", } m["sai-coe"] = { "Coeruna", 6425639, "sai-wit", "Latn", } m["sai-col"] = { "Colán", 5141893, "sai-ctc", "Latn", } m["sai-cop"] = { "Copallén", 5390321, "qfa-unc", -- extinct, only four words attested; possibly Cholonan "Latn", } m["sai-crd"] = { "Coroado Puri", 24191321, "sai-mje", "Latn", } m["sai-ctq"] = { "Catuquinaru", 16858455, "qfa-unc", -- extinct, poorly attested; vocabulary does not resemble other languages "Latn", } m["sai-cul"] = { "Culli", 2879660, "qfa-unc", -- extinct, poorly attested; often considered an isolate "Latn", } m["sai-cva"] = { "Cueva", 5192644, "qfa-unc", -- extinct, poorly attested; possibly Chocoan "Latn", } m["sai-esm"] = { "Esmeralda", 3058083, "qfa-unc", -- extinct, poorly attested; possibly related to Yaruro "Latn", } m["sai-ewa"] = { "Ewarhuyana", 16898104, nil, "Latn", } m["sai-gam"] = { "Gamela", 5403661, "qfa-unc", -- extinct, poorly attested; possibly an isolate "Latn", } m["sai-gay"] = { "Gayón", 5528902, "sai-jir", "Latn", } m["sai-gmo"] = { "Guamo", 5613495, "qfa-unc", -- extinct; "Kaufman (1990) finds a connection with the Chapacuran languages convincing." [Wikipedia] Considered an isolate by Campbell (2024). "Latn", } m["sai-gua"] = { "Guachí", 5613172, "sai-guc", "Latn", } m["sai-gue"] = { "Güenoa", 5626799, "sai-crn", "Latn", } m["sai-hau"] = { "Haush", 3128376, "sai-cho", "Latn", } m["sai-jee-pro"] = { "Proto-Jê", 116773212, "sai-jee", "Latn", type = "reconstructed", } m["sai-jko"] = { "Jeikó", 6176527, "sai-mje", "Latn", } m["sai-jrj"] = { "Jirajara", 6202966, "sai-jir", "Latn", } m["sai-kat"] = { -- contrast xoo, kzw, sai-xoc "Katembri", 6375925, "qfa-unc", -- extinct, poorly attested; "Kaufman (1990) has linked it with the nearly extinct Taruma, although this has not been accepted by other scholars." [Wikipedia] "Latn", } m["sai-mal"] = { "Malalí", 6741212, "sai-mje", -- considered the most divergent Maxakalían language (a subdivision of Macro-Jê), for which we have no entry "Latn", } m["sai-mar"] = { "Maratino", 6755055, "qfa-unc", -- extinct, poorly attested; possibly Uto-Aztecan "Latn", } m["sai-mat"] = { "Matanawi", 6786047, "qfa-unc", -- extinct; either an isolate or distantly related to the Muran languages; Campbell (2024) lists it as an isolate, Glottolog gives it as unclassified "Latn", } m["sai-mcn"] = { "Mocana", 3402048, "qfa-unc", -- extinct, poorly attested; given as part of the Malibu languages (geographic grouping; not a clade) "Latn", } m["sai-men"] = { "Menien", 16890110, "sai-mje", "Latn", } m["sai-mil"] = { "Millcayac", 19573012, "sai-hrp", "Latn", } m["sai-mlb"] = { "Malibu", 3402048, "qfa-unc", -- extinct, poorly attested; given as part of the Malibu languages (geographic grouping; not a clade) "Latn", } m["sai-msk"] = { "Masakará", 6782426, "sai-mje", "Latn", } m["sai-muc"] = { "Mucuchí", 6931290, nil, -- generally considered Timotean, for which we have no entry "Latn", } m["sai-mue"] = { "Muellama", 16886936, "sai-bar", "Latn", } m["sai-muz"] = { "Muzo", 6644203, "qfa-unc", -- extinct language of Colombia, poorly attested; may be Pijao (Cariban) "Latn", } m["sai-mys"] = { "Maynas", 16919393, "sai-cah", -- per Campbell (2024); formerly considered unclassified "Latn", } m["sai-nat"] = { "Natú", 9006749, "qfa-unc", -- extinct, poorly attested; "only Greenberg dares to classify [it]".[Wikipedia, quoting Moseley, Christopher; Asher, R. E.; Tait, Mary (1994), Atlas of the world's languages] "Latn", } m["sai-nje-pro"] = { "Proto-Northern Jê", 116773245, "sai-nje", "Latn", type = "reconstructed", } m["sai-opo"] = { "Opón", 7099152, "sai-car", "Latn", } m["sai-oto"] = { "Otomaco", 16879234, "sai-otm", "Latn", } m["sai-pal"] = { "Palta", 3042978, "qfa-unc", -- extinct, unclassified; possibly Chicham "Latn", } m["sai-pam"] = { "Pamigua", 5908689, "sai-otm", "Latn", } m["sai-par"] = { "Paratió", 16890038, "qfa-unc", -- extinct, poorly attested; possibly Xukuruan "Latn", } m["sai-peb"] = { "Peba", 3373890, "sai-pey", "Latn", } m["sai-pnz"] = { "Panzaleo", 3123275, "qfa-unc", -- extinct, unclassified; possibly Paezan "Latn", } m["sai-prh"] = { "Puruhá", 3410994, "qfa-unc", -- extinct, poorly attested; possibly in a famil with Cañari "Latn", } m["sai-ptg"] = { "Patagón", 128807870, "sai-tar", -- extinct, only known from 4 words, which suggest Cariban lineage (Campbell 2024) "Latn", } m["sai-pur"] = { "Purukotó", 7261622, "sai-pem", "Latn", } m["sai-pyg"] = { "Payaguá", 7156643, "sai-guc", "Latn", } m["sai-pyk"] = { "Pykobjê", 98113977, "sai-nje", "Latn", } m["sai-qmb"] = { "Quimbaya", 7272043, "qfa-unc", -- extinct, might not exist; few known words "Latn", } m["sai-qtm"] = { "Quitemo", 7272651, "sai-cpc", "Latn", } m["sai-rab"] = { "Rabona", 6644203, "qfa-unc", -- extinct, poorly attested, mostly plant names; possibly Candoshi-Shapra "Latn", } m["sai-ram"] = { "Ramanos", 16902824, "qfa-unc", -- extinct, poorly attested, possibly an isolate; per Glottolog: "the minuscule wordlist ... shows no convincing resemblances to surrounding languages" "Latn", } m["sai-sac"] = { "Sácata", 5390321, "qfa-unc", -- extinct, only 3 words known; possibly Candoshí or Arawakan "Latn", } m["sai-san"] = { "Sanaviron", 16895999, "qfa-unc", -- extinct, unclassified; no consensus on classification "Latn", } m["sai-sap"] = { "Sapará", 7420922, "sai-car", "Latn", } m["sai-sec"] = { "Sechura", 7442912, "qfa-unc", -- extinct, poorly attested; possibly Catacaoan "Latn", } m["sai-sin"] = { "Sinúfana", 7525275, "qfa-unc", -- moribund, poorly attested; possibly Chocoan "Latn", } m["sai-sje-pro"] = { "Proto-Southern Jê", 116773814, "sai-sje", "Latn", type = "reconstructed", } m["sai-tab"] = { "Tabancale", 5390321, "qfa-unc", -- extinct, only 5 words known; no obvious connections, might be an isolate "Latn", } m["sai-tal"] = { "Tallán", 16910468, "qfa-unc", -- extinct, poorly attested; might be Catacaoan "Latn", } m["sai-tap"] = { "Tapayuna", 30719984, "sai-nje", "Latn", } m["sai-tar-pro"] = { "Proto-Taranoan", 116773816, "sai-tar", "Latn", type = "reconstructed", } m["sai-teu"] = { "Teushen", 3519243, "qfa-unc", -- probably extinct by the 1950's; possibly Chonan "Latn", } m["sai-tim"] = { "Timote", 7806995, nil, -- possibly in a small Timotean family "Latn", } m["sai-tpr"] = { "Taparita", 7684460, "sai-otm", "Latn", } m["sai-trr"] = { "Tarairiú", 7685313, "qfa-unc", -- extinct, too poorly attested to classify "Latn", } m["sai-wai"] = { "Waitaká", 16918610, "qfa-unc", -- extinct, possibly Purian "Latn", } m["sai-way"] = { "Wayumara", 7960726, "sai-car", "Latn", } m["sai-wit-pro"] = { "Proto-Witotoan", 116773823, "sai-wit", "Latn", type = "reconstructed", } m["sai-wnm"] = { "Wanham", 16879440, "sai-cpc", "Latn", } m["sai-xoc"] = { -- contrast xoo, kzw, sai-kat "Xocó", 12953620, "qfa-unc", -- extinct and poorly attested; not clear if one or three languages "Latn", } m["sai-yao"] = { "Yao (South America)", 16979655, "sai-ven", "Latn", } m["sai-yar"] = { -- not the same family as 'suy' "Yarumá", 3505859, "sai-pek", "Latn", } m["sai-yri"] = { "Yuri", 2669157, "sai-tyu", "Latn", } m["sai-yup"] = { "Yupua", 8061430, "sai-tuc", "Latn", } m["sai-yur"] = { "Yurumanguí", 1281291, "qfa-unc", -- extinct, too poorly attested to classify "Latn", } m["sal-pro"] = { "Proto-Salish", 116773269, "sal", "Latn", type = "reconstructed", } m["sdv-daj-pro"] = { "Proto-Daju", 116773739, "sdv-daj", "Latn", type = "reconstructed", } m["sdv-eje-pro"] = { "Proto-Eastern Jebel", 116773751, "sdv-eje", "Latn", type = "reconstructed", } m["sdv-nil-pro"] = { "Proto-Nilotic", 116773794, "sdv-nil", "Latn", type = "reconstructed", } m["sdv-nyi-pro"] = { "Proto-Nyima", 116773796, "sdv-nyi", "Latn", type = "reconstructed", } m["sdv-tmn-pro"] = { "Proto-Taman", 116773815, "sdv-tmn", "Latn", type = "reconstructed", } m["sel-nor"] = { "Northern Selkup", 30304565, "sel", "Cyrl", translit = "sel-nor-translit", } m["sel-pro"] = { "Proto-Selkup", 128884235, "sel", "Latn", type = "reconstructed", } m["sel-sou"] = { "Southern Selkup", 30304639, "sel", "Cyrl", translit = "sel-sou-translit", } m["sem-amm"] = { "Ammonite", 279181, "sem-can", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["sem-amo"] = { "Amorite", 35941, "sem-nwe", "Xsux, Latn", } m["sem-cha"] = { "Chaha", 35543, "sem-eth", "Ethi", translit = "Ethi-translit", } m["sem-dad"] = { "Dadanitic", 21838040, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-dum"] = { "Dumaitic", 128810397, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-has"] = { "Hasaitic", 3541433, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-his"] = { "Hismaic", 22948260, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-mhr"] = { "Muher", 33743, "sem-eth", "Latn", } m["sem-pro"] = { "Proto-Semitic", 1658554, "sem", "Latn", type = "reconstructed", } m["sem-saf"] = { "Safaitic", 472586, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-sam"] = { "Samalian", 85847147, "sem-nwe", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["sem-srb"] = { "Old South Arabian", 35025, "sem-osa", "Sarb", -- Sarb translit in [[Module:scripts/data]] } m["sem-tay"] = { "Taymanitic", 24912301, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-tha"] = { "Thamudic", 843030, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-wes-pro"] = { "Proto-West Semitic", 98021726, "sem-wes", "Latn", type = "reconstructed", } m["sio-pro"] = { -- NB this is not Proto-Siouan-Catawban 'nai-sca-pro' "Proto-Siouan", 34181, "sio", "Latn", type = "reconstructed", } m["sit-aao-pro"] = { "Proto-Central Naga", nil, "sit-aao", "Latn", type = "reconstructed", } m["sit-bai-pro"] = { "Proto-Bai", nil, "sit-bai", "Latn", type = "reconstructed", } m["sit-ban"] = { "Bangru", 56071779, "sit-hrs", "Latn", } m["sit-bdi-pro"] = { "Proto-Bodish", nil, "sit-bdi", "Latn", type = "reconstructed", } m["sit-bok"] = { "Bokar", 4938727, "sit-tan", "Latn, Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["sit-cai"] = { "Caijia", 5017528, "sit-cln", "Latn" } m["sit-cha"] = { "Chairel", 5068066, "sit-luu", "Latn", } m["sit-ers-pro"] = { "Proto-Ersuic", nil, "sit-ers", "Latn", type = "reconstructed", } m["sit-hrs-pro"] = { "Proto-Hrusish", 116773762, "sit-hrs", "Latn", type = "reconstructed", } m["sit-jap"] = { "Japhug", 3162245, "sit-egy", "Latn", } m["sit-kha-pro"] = { "Proto-Kham", 116773773, "sit-kha", "Latn", type = "reconstructed", } m["sit-khb-pro"] = { "Proto-Kho-Bwa", nil, "sit-khb", "Latn", type = "reconstructed", } m["sit-khp-pro"] = { "Proto-Puroik", nil, "sit-khb", "Latn", type = "reconstructed", } m["sit-khw-pro"] = { "Proto-Western Kho-Bwa", nil, "sit-khw", "Latn", type = "reconstructed", } m["sit-kon-pro"] = { "Proto-Northern Naga", nil, "sit-kon", "Latn", type = "reconstructed", } m["sit-liz"] = { "Lizu", 6660653, "sit-ers", "Latn", -- and Ersu Shaba } m["sit-lnj"] = { "Longjia", 17096251, "sit-cln", "Latn" } m["sit-lrn"] = { "Luren", 16946370, "sit-cln", "Latn" } m["sit-luu-pro"] = { "Proto-Luish", 116773783, "sit-luu", "Latn", type = "reconstructed", } m["sit-nas-pro"] = { "Proto-Naish", nil, "sit-nas", "Latn", type = "reconstructed", } m["sit-prn"] = { "Puiron", 7259048, "sit-zem", } m["sit-pro"] = { "Proto-Sino-Tibetan", 24839178, "sit", "Latn", type = "reconstructed", } m["sit-sit"] = { "Situ", 19840830, "sit-egy", "Latn", } m["sit-tam-pro"] = { "Proto-Tamangic", 117469295, "sit-tam", "Latn", type = "reconstructed", } m["sit-tan-pro"] = { "Proto-Tani", 116773284, "sit-tan", "Latn", -- needs verification type = "reconstructed", } m["sit-tgm"] = { "Tangam", 17041370, "sit-tan", "Latn", } m["sit-tng-pro"] = { "Proto-Tangkhulic", nil, "sit-tng", "Latn", type = "reconstructed" } m["sit-tos"] = { "Tosu", 7827899, "sit-ers", "Latn", -- also Ersu Shaba } m["sit-tsh"] = { "Tshobdun", 19840950, "sit-egy", "Latn", } m["sit-zbu"] = { "Zbu", 19841106, "sit-egy", "Latn", } m["sla-pro"] = { "Proto-Slavic", 747537, "sla", "Latn", type = "reconstructed", strip_diacritics = { remove_diacritics = c.grave .. c.acute .. c.tilde .. c.macron .. c.dgrave .. c.invbreve, remove_exceptions = {'ś'}, }, sort_key = { from = {"č", "ď", "ě", "ę", "ь", "ľ", "ň", "ǫ", "ř", "š", "ś", "ť", "ъ", "ž"}, to = {"c²", "d²", "e²", "e³", "i²", "l²", "nj", "o²", "r²", "s²", "s³", "t²", "u²", "z²"}, } } m["smi-pro"] = { "Proto-Samic", 7251862, "smi", "Latn", type = "reconstructed", sort_key = { from = {"ā", "č", "δ", "[ëē]", "ŋ", "ń", "ō", "š", "θ", "%([^()]+%)"}, to = {"a", "c²", "d", "e", "n²", "n³", "o", "s²", "t²"} }, } m["son-pro"] = { "Proto-Songhay", 116773277, "son", "Latn", type = "reconstructed", } m["sqj-pro"] = { "Proto-Albanian", 18210846, "sqj", "Latn", type = "reconstructed", } m["ssa-klk-pro"] = { "Proto-Kuliak", 116773779, "ssa-klk", "Latn", type = "reconstructed", } m["ssa-kom-pro"] = { "Proto-Koman", 116773775, "ssa-kom", "Latn", type = "reconstructed", } m["ssa-pro"] = { "Proto-Nilo-Saharan", 116773236, "ssa", "Latn", type = "reconstructed", } m["syd-pro"] = { "Proto-Samoyedic", 7251863, "syd", "Latn", type = "reconstructed", } m["tai-pro"] = { "Proto-Tai", 6583709, "tai", "Latn", type = "reconstructed", } m["tai-swe-pro"] = { "Proto-Southwestern Tai", 116773280, "tai-swe", "Latn", type = "reconstructed", } m["tbq-bdg-pro"] = { "Proto-Bodo-Garo", 116773195, "tbq-bdg", "Latn", type = "reconstructed", } m["tbq-blg"] = { "Bailang", 2879843, "tbq-lob", "Hani", sort_key = "Hani-sortkey", } m["tbq-brm-pro"] = { "Proto-Burmish", nil, "tbq-brm", "Latn", type = "reconstructed", } m["tbq-gkh"] = { "Gokhy", 5578069, "tbq-sil", "Latn", } m["tbq-kuk-pro"] = { "Proto-Kuki-Chin", 116773220, "tbq-kuk", "Latn", type = "reconstructed", } m["tbq-lal-pro"] = { "Proto-Lalo", 116773781, "tbq-lal", "Latn", type = "reconstructed", } m["tbq-laz"] = { "Laze", 17007626, "sit-nas", "Latn", } m["tbq-lob-pro"] = { "Proto-Lolo-Burmese", 116773224, "tbq-lob", "Latn", type = "reconstructed", } m["tbq-lol-pro"] = { "Proto-Loloish", 7251855, "tbq-lol", "Latn", type = "reconstructed", } m["tbq-mil"] = { "Milang", 6850761, "sit-gsi", "Deva, Latn", } m["tbq-mor"] = { "Moran", 6909216, "tbq-bdg", "Latn", } m["tbq-ngo"] = { "Ngochang", 56582, "tbq-brm", "Latn", } -- tbq-pro is now etymology-only m["trk-dkh"] = { "Dukhan", 12809273, "trk-ssb", "Latn, Cyrl, Mong", -- Mong translit, display_text and strip_diacritics in [[Module:scripts/data]] } -- As described in Mahmud al-Kashgari's 11th century ''Dīwān Lughāt al-Turk''. m["trk-eog"] = { "Early Old Oghuz", nil, "trk-ogz", "ota-Arab", strip_diacritics = {["ota-Arab"] = "ar-stripdiacritics"}, } m["trk-oat"] = { "Old Anatolian Turkish", 7083390, "trk-ogz", "ota-Arab", strip_diacritics = {["ota-Arab"] = "ar-stripdiacritics"}, ancestors = "trk-eog", } m["trk-pro"] = { "Proto-Turkic", 3657773, "trk", "Latn", type = "reconstructed", standard_chars = { Latn = " ()-abdegiklmnoprstuxyzïöüāčēīĺŋōŕšūǖȫẹ" .. c.macron, } } m["tup-gua-pro"] = { "Proto-Tupi-Guarani", 116773288, "tup-gua", "Latn", type = "reconstructed", } m["tup-kab"] = { "Kabishiana", 15302988, "tup", "Latn", } m["tup-pro"] = { "Proto-Tupian", 10354700, "tup", "Latn", type = "reconstructed", } m["tuw-alk"] = { "Altsuka", --TLCHANGE basing from https://en.wiktionary.org/wiki/%E9%98%BF%E5%8B%92%E6%A5%9A%E5%96%80 and https://en.wiktionary.org/wiki/%E1%A0%A0%E1%A0%AF%E1%A0%B4%E1%A1%A0%E1%A1%B4%E1%A0%A0#Manchu 113553616, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, english_name = "Alchuka", --TLCHANGE } m["tuw-bal"] = { "Bala", 86730632, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, } m["tuw-kkl"] = { "Kyakala", 118875708, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, } m["tuw-kli"] = { "Kili", 6406892, "tuw-ewe", "Cyrl", } m["tuw-pro"] = { "Proto-Tungusic", 85872335, "tuw", "Latn", type = "reconstructed", } m["tuw-sol"] = { "Solon", 30004, "tuw-ewe", } m["urj-fin-pro"] = { "Proto-Finnic", 11883720, "urj-fin", "Latn", type = "reconstructed", } m["urj-koo"] = { "Old Komi", 86679962, "kv", "Perm, Cyrs", translit = "urj-koo-translit", -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]]; previously, Cyrs strip_diacritics not present } m["urj-kuk"] = { "Kukkuzi", 107410460, "urj-fin", "Latn", ancestors = "vot", } m["urj-kya"] = { "Komi-Yazva", 2365210, "kv", "Cyrl", translit = "kv-translit", override_translit = true, strip_diacritics = {remove_diacritics = c.acute}, } m["urj-mdv-pro"] = { "Proto-Mordvinic", 116773232, "urj-mdv", "Latn", type = "reconstructed", } m["urj-prm-pro"] = { "Proto-Permic", 116773257, "urj-prm", "Latn", type = "reconstructed", } m["urj-pro"] = { "Proto-Uralic", 288765, "urj", "Latn", type = "reconstructed", } m["urj-ugr-pro"] = { "Proto-Ugric", 156631, "urj-ugr", "Latn", type = "reconstructed", } m["xnd-pro"] = { "Proto-Na-Dene", 116773233, "xnd", "Latn", type = "reconstructed", } m["xgn-pro"] = { "Proto-Mongolic", 2493677, "xgn", "Latn", type = "reconstructed", sort_key = { from = {"č", "i", "ï", "ǰ", "ŋ", "ö", "š", "ü"}, to = {"c", "i" .. p[1], "i", "j", "n" .. p[1], "o" .. p[1], "s" .. p[1], "u" .. p[1]}, }, } m["yok-bvy"] = { "Buena Vista Yokuts", 4985474, "yok", "Latn", } m["yok-dly"] = { "Delta Yokuts", 70923266, "yok", "Latn", } m["yok-gsy"] = { "Gashowu Yokuts", 3098708, "yok", "Latn", } m["yok-kry"] = { "Kings River Yokuts", 6413014, "yok", "Latn", } m["yok-nvy"] = { "Northern Valley Yokuts", 85789777, "yok", "Latn", } m["yok-ply"] = { "Palewyami Yokuts", 2387391, "yok", "Latn", } m["yok-svy"] = { "Southern Valley Yokuts", 12642473, "yok", "Latn", } m["yok-tky"] = { "Tule-Kaweah Yokuts", 7851988, "yok", "Latn", } m["ypk-pro"] = { "Proto-Yupik", 116773295, "ypk", "Latn", type = "reconstructed", } m["yrk-for"] = { "Forest Nenets", 1295107, "yrk", "Cyrl", translit = "yrk-for-translit", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.macron .. c.breve .. c.dotabove}, } m["yrk-tun"] = { "Tundra Nenets", 36452, "yrk", "Cyrl", strip_diacritics = { from = {"ӑ", "а̄", "э̇", "ӣ", "ы̄", "ӯ", "ю̄", "я̆", "я̄"}, to = {"а", "а", "э", "и", "ы", "у", "ю", "я", "я"}, }, translit = "yrk-tun-translit", } m["zhx-min-pro"] = { "Proto-Min", 19646347, "zhx-min", "Latn", type = "reconstructed", } m["zhx-sht"] = { "Shaozhou Tuhua", 1920769, "zhx", "Nshu, Hants", generate_forms = "zh-generateforms", sort_key = {Hani = "Hani-sortkey"}, } m["zhx-sic"] = { "Sitsuwanes", --TLCHANGE 2278732, "zhx-man", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", english_name = "Sichuanese", --TLCHANGE spanish_name = "Sichuanés", --TLCHANGE } m["zhx-tai"] = { "Toisanes", --TLCHANGE 2208940, "zhx-yue", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", english_name = "Taishanese", --TLCHANGE spanish_name = "Toisanés", --TLCHANGE } m["zle-ono"] = { "Old Novgorodian", 162013, "zle", "Cyrs, Glag", translit = {Cyrs = "Cyrs-translit", Glag = "Glag-translit"}, -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]] } m["zle-ort"] = { "Old Ruthenian", 13211, "zle", "Arab, Cyrs, Latn", ancestors = "orv", translit = { Cyrs = "zle-ort-translit", Arab = "zle-ort-Arab-translit", }, strip_diacritics = { Cyrs = { remove_diacritics = m_langdata.chars_substitutions["Cyrs_remove_diacritics"], remove_exceptions = {"Ї", "ї"}, }, Arab = "ar-stripdiacritics", }, -- Cyrs sort_key in [[Module:scripts/data]] } m["zls-chs"] = { "Church Slavonic", 33251, "zls", "Cyrs, Glag, Latn", ancestors = "cu", translit = { Cyrs = "Cyrs-translit", Glag = "Glag-translit" }, -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]] } m["zlw-ocs"] = { "Lumang Tseko", --TLCHANGE 593096, "zlw", "Latn", english_name = "Old Czech", --TLCHANGE spanish_name = "Checo antiguo", --TLCHANGE } m["zlw-opl"] = { "Lumang Polako", --TLCHANGE 149838, "zlw-lch", "Latn", strip_diacritics = {remove_diacritics = c.ringabove}, english_name = "Old Polish", --TLCHANGE spanish_name = "Polaco antiguo", --TLCHANGE } m["zlw-osk"] = { "Lumang Eslovako", --TLCHANGE 12776676, "zlw", "Latn", english_name = "Old Slovak", --TLCHANGE spanish_name = "Eslovaco antiguo", --TLCHANGE } m["zlw-slv"] = { "Slovincian", 36822, "zlw-pom", "Latn", strip_diacritics = {remove_diacritics = c.macron .. c.breve}, } return require("Module:languages").finalizeData(m, "language") cjftw5znzzb9zv027x09bk2n08tlnxq 178467 178457 2026-10-27T02:13:00Z GinawaSaHapon 3989 178467 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["aav-khs-pro"] = { "Proto-Khasian", 116773216, "aav-khs", "Latn", type = "reconstructed", } m["aav-nic-pro"] = { "Proto-Nicobarese", 116773793, "aav-nic", "Latn", type = "reconstructed", } m["aav-pkl-pro"] = { "Proto-Pnar-Khasi-Lyngngam", 116773259, "aav-pkl", "Latn", type = "reconstructed", } m["aav-pro"] = { -- mkh-pro will merge into this "Proto-Austroasiatic", 116773186, "aav", "Latn", type = "reconstructed", } m["afa-pro"] = { "Proto-Afroasiatic", 269125, "afa", "Latn", type = "reconstructed", } m["alg-aga"] = { "Agawam", nil, "alg-eas", "Latn", } m["alg-pro"] = { "Proto-Algonquian", 7251834, "alg", "Latn", type = "reconstructed", sort_key = {remove_diacritics = "·"}, } m["alv-ama"] = { "Amasi", 4740400, "nic-grs", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.tilde .. c.macron}, } m["alv-bgu"] = { "Bainouk Gubeeher", 17002646, "alv-bny", "Latn", } m["alv-bua-pro"] = { "Proto-Bua", 116773723, "alv-bua", "Latn", type = "reconstructed", } m["alv-cng-pro"] = { "Proto-Cangin", 116773726, "alv-cng", "Latn", type = "reconstructed", } m["alv-edo-pro"] = { "Proto-Edoid", 116773206, "alv-edo", "Latn", type = "reconstructed", } m["alv-fli-pro"] = { "Proto-Fali", 116773754, "alv-fli", "Latn", type = "reconstructed", } m["alv-gbe-pro"] = { "Proto-Gbe", 116773208, "alv-gbe", "Latn", type = "reconstructed", } m["alv-gng-pro"] = { "Proto-Guang", 116773757, "alv-gng", "Latn", type = "reconstructed", } m["alv-gtm-pro"] = { "Proto-Central Togo", 116773732, "alv-gtm", "Latn", type = "reconstructed", } m["alv-gwa"] = { "Gwara", 16945580, "nic-pla", "Latn", } m["alv-hei-pro"] = { "Proto-Heiban", 116773760, "alv-hei", "Latn", type = "reconstructed", } m["alv-ido-pro"] = { "Proto-Idomoid", 116773764, "alv-ido", "Latn", type = "reconstructed", } m["alv-igb-pro"] = { "Proto-Igboid", 116773765, "alv-igb", "Latn", type = "reconstructed", } m["alv-kwa-pro"] = { "Proto-Kwa", 116773780, "alv-kwa", "Latn", type = "reconstructed", } m["alv-mum-pro"] = { "Proto-Mumuye", 116773791, "alv-mum", "Latn", type = "reconstructed", } m["alv-nup-pro"] = { "Proto-Nupoid", 116773795, "alv-nup", "Latn", type = "reconstructed", } m["alv-pro"] = { "Proto-Atlantic-Congo", 116732838, "alv", "Latn", type = "reconstructed", } m["alv-edk-pro"] = { "Proto-Edekiri", nil, "alv-edk", "Latn", type = "reconstructed", } m["alv-yor-pro"] = { "Proto-Yoruba", nil, "alv-yor", "Latn", type = "reconstructed", } m["alv-yrd-pro"] = { "Proto-Yoruboid", 116773824, "alv-yrd", "Latn", type = "reconstructed", } m["alv-von-pro"] = { "Proto-Volta-Niger", 116773820, "alv-von", "Latn", type = "reconstructed", } m["apa-pro"] = { "Proto-Apachean", 116773135, "apa", "Latn", type = "reconstructed", } m["aql-pro"] = { "Proto-Algic", 18389588, "aql", "Latn", type = "reconstructed", sort_key = {remove_diacritics = "·"}, } m["art-adu"] = { "Adûni", 1232159, "art", "Latn", type = "appendix-constructed", } m["art-bel"] = { "Belter Creole", 108055510, "art", "Latn", type = "appendix-constructed", sort_key = { remove_diacritics = c.acute, from = {"ɒ"}, to = {"a"}, }, } m["art-blk"] = { "Bolak", 2909283, "art", "Latn", type = "appendix-constructed", } m["art-bsp"] = { "Black Speech", 686210, "art", "Latn, Teng", type = "appendix-constructed", } m["art-com"] = { "Communicationssprache", 35227, "art", "Latn", type = "appendix-constructed", } m["art-dtk"] = { "Dothraki", 2914733, "art", "Latn", type = "appendix-constructed", } m["art-elo"] = { "Eloi", nil, "art", "Latn", type = "appendix-constructed", } m["art-gld"] = { "Goa'uld", 19823, "art", "Latn, Egyp, Mero", type = "appendix-constructed", } m["art-lap"] = { "Lapine", 6488195, "art", "Latn", type = "appendix-constructed", } m["art-man"] = { "Mandalorian", 54289, "art", "Latn", type = "appendix-constructed", } m["art-mun"] = { "Mundolinco", 851355, "art", "Latn", type = "appendix-constructed", } m["art-nav"] = { "Naʼvi", 316939, "art", "Latn", type = "appendix-constructed", } m["art-vlh"] = { "High Valyrian", 64483808, "art", "Latn", type = "appendix-constructed", } m["ath-nic"] = { "Nicola", 20609, "ath-nor", "Latn", } m["ath-pro"] = { "Proto-Athabaskan", 104841722, "ath", "Latn", type = "reconstructed", } m["auf-pro"] = { "Proto-Arawa", 116773706, "auf", "Latn", type = "reconstructed", } m["aus-alu"] = { "Alungul", 16827670, "aus-pmn", "Latn", } m["aus-and"] = { "Andjingith", 4754509, "aus-pmn", "Latn", } m["aus-ang"] = { "Angkula", 16828520, "aus-pmn", "Latn", } m["aus-arn-pro"] = { "Proto-Arnhem", 116773720, "aus-arn", "Latn", type = "reconstructed", } m["aus-bra"] = { "Barranbinya", 4863220, "aus-pmn", "Latn", } m["aus-brm"] = { "Barunggam", 4865914, "aus-pmn", "Latn", } m["aus-cww-pro"] = { "Proto-Central New South Wales", 116773199, "aus-cww", "Latn", type = "reconstructed", } m["aus-dal-pro"] = { "Proto-Daly", 116773743, "aus-dal", "Latn", type = "reconstructed", } m["aus-guw"] = { "Guwar", 6652138, "aus-pam", "Latn", } m["aus-lsw"] = { "Little Swanport", 6652138, "qfa-unc", "Latn", } m["aus-mbi"] = { "Mbiywom", 6799701, "aus-pmn", "Latn", } m["aus-ngk"] = { "Ngkoth", 7022405, "aus-pmn", "Latn", } m["aus-nyu-pro"] = { "Proto-Nyulnyulan", 116773797, "aus-nyu", "Latn", type = "reconstructed", } m["aus-pam-pro"] = { "Proto-Pama-Nyungan", 33942, "aus-pam", "Latn", type = "reconstructed", } m["aus-tul"] = { "Tulua", 16938541, "aus-pam", "Latn", } m["aus-uwi"] = { "Uwinymil", 7903995, "aus-arn", "Latn", } m["aus-wdj-pro"] = { "Proto-Iwaidjan", 116773767, "aus-wdj", "Latn", type = "reconstructed", } m["aus-won"] = { "Wong-gie", nil, "aus-pam", "Latn", } m["aus-wul"] = { "Wulguru", 8039196, "aus-dyb", "Latn", } m["aus-ynk"] = { -- contrast nny "Yangkaal", 3913770, "aus-tnk", "Latn", } m["awd-amc-pro"] = { "Proto-Amuesha-Chamicuro", nil, "awd", "Latn", type = "reconstructed", } m["awd-kmp-pro"] = { "Proto-Kampa", nil, "awd", "Latn", type = "reconstructed", } m["awd-prw-pro"] = { "Proto-Paresi-Waura", nil, "awd", "Latn", type = "reconstructed", } m["awd-ama"] = { "Amarizana", 16827787, "awd", "Latn", } m["awd-ana"] = { "Anauyá", 16828252, "awd", "Latn", } m["awd-apo"] = { "Apolista", 16916645, "awd", "Latn", } m["awd-cab"] = { "Cabre", 16850160, "awd", "Latn", } m["awd-gnu"] = { "Guinau", 3504087, "awd", "Latn", } m["awd-kar"] = { "Cariay", 16920253, "awd", "Latn", } m["awd-kaw"] = { "Kawishana", 6379993, "awd-nwk", "Latn", } m["awd-kus"] = { "Kustenau", 5196293, "awd", "Latn", } m["awd-man"] = { "Manao", 6746920, "awd", "Latn", } m["awd-mar"] = { "Marawan", 6755108, "awd", "Latn", } m["awd-mpr"] = { "Maipure", 6736872, "awd", "Latn", } m["awd-mrt"] = { "Mariaté", 16910017, "awd-nwk", "Latn", } m["awd-nwk-pro"] = { "Proto-Nawiki", 116773234, "awd-nwk", "Latn", type = "reconstructed", } m["awd-pai"] = { "Paikoneka", 128807835, "awd", "Latn", } m["awd-pas"] = { "Pasé", 7143168, "awd-nwk", "Latn", } m["awd-pro"] = { "Proto-Arawak", 97573478, "awd", "Latn", type = "reconstructed", } m["awd-she"] = { "Shebayo", 7492248, "awd", "Latn", } m["awd-taa-pro"] = { "Proto-Ta-Arawak", 116773282, "awd-taa", "Latn", type = "reconstructed", } m["awd-wai"] = { "Wainumá", 16910017, "awd-nwk", "Latn", } m["awd-yum"] = { "Yumana", 8061062, "awd-nwk", "Latn", } m["azc-caz"] = { "Cazcan", 5055514, "azc", "Latn", } m["azc-cup-pro"] = { "Proto-Cupan", 116773738, "azc-cup", "Latn", type = "reconstructed", } m["azc-ktn"] = { "Kitanemuk", 3197558, "azc-tak", "Latn", } m["azc-nah-pro"] = { "Proto-Nahuan", 7251860, "azc-nah", "Latn", type = "reconstructed", } m["azc-num-pro"] = { "Proto-Numic", 116773247, "azc-num", "Latn", type = "reconstructed", } m["azc-pro"] = { "Proto-Uto-Aztecan", 96400333, "azc", "Latn", type = "reconstructed", } m["azc-tak-pro"] = { "Proto-Takic", 116773283, "azc-tak", "Latn", type = "reconstructed", } m["azc-tat"] = { "Tataviam", 743736, "azc", "Latn", } m["ber-pro"] = { "Proto-Berber", 2855698, "ber", "Latn", type = "reconstructed", } m["ber-fog"] = { "Fogaha", 107610173, "ber", "Latn", } m["ber-zuw"] = { "Zuwara", 4117169, "ber", "Latn", } m["bnt-bal"] = { "Balong", 93935237, "bnt-bbo", "Latn", } m["bnt-bon"] = { "Boma Nkuu", nil, "bnt", "Latn", } m["bnt-boy"] = { "Boma Yumu", nil, "bnt", "Latn", } m["bnt-bwa"] = { "Bwala", 128810345, "bnt-tek", "Latn", } m["bnt-cmw"] = { "Chimwiini", 4958328, "bnt-swh", "Latn", } m["bnt-ind"] = { "Indanga", 51412803, "bnt", "Latn", } m["bnt-lal"] = { "Lala (South Africa)", 6480154, "bnt-ngu", "Latn", } m["bnt-mpi"] = { "Mpiin", 93937013, "bnt-bdz", "Latn", } m["bnt-mpu"] = { "Mpuono", -- not to be confused with Mbuun zmp 36056, "bnt", "Latn", } m["bnt-ngu-pro"] = { "Proto-Nguni", 961559, "bnt-ngu", "Latn", type = "reconstructed", sort_key = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron}, } m["bnt-phu"] = { "Phuthi", 33796, "bnt-ngu", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute}, } m["bnt-pro"] = { "Proto-Bantu", 3408025, "bnt", "Latn", type = "reconstructed", sort_key = "bnt-pro-sortkey", } m["bnt-sab-pro"] = { "Proto-Sabaki", nil, -- Q2209395 is the code for the Sabaki family "bnt-sab", "Latn", type = "reconstructed", } m["bnt-sbo"] = { "South Boma", nil, "bnt", "Latn", } m["bnt-sts-pro"] = { "Proto-Sotho-Tswana", 116773278, "bnt-sts", "Latn", type = "reconstructed", } m["btk-pro"] = { "Proto-Batak", 116773191, "btk", "Latn", type = "reconstructed", } m["cau-abz-pro"] = { "Proto-Abkhaz-Abaza", 7251831, "cau-abz", "Latn", type = "reconstructed", } m["cau-and-pro"] = { "Proto-Andian", nil, "cau-and", "Latn", type = "reconstructed", } m["cau-ava-pro"] = { "Proto-Avaro-Andian", 116773187, "cau-ava", "Latn", type = "reconstructed", } m["cau-cir-pro"] = { "Proto-Circassian", 7251838, "cau-cir", "Latn", type = "reconstructed", } m["cau-drg-pro"] = { "Proto-Dargwa", 116773205, "cau-drg", "Latn", type = "reconstructed", } m["cau-lzg-pro"] = { "Proto-Lezghian", 116773223, "cau-lzg", "Latn", type = "reconstructed", } m["cau-nec-pro"] = { "Proto-Northeast Caucasian", 116773244, "cau-nec", "Latn", type = "reconstructed", } m["cau-nkh-pro"] = { "Proto-Nakh", 108032840, "cau-nkh", "Latn", type = "reconstructed", } m["cau-nwc-pro"] = { "Proto-Northwest Caucasian", 7251861, "cau-nwc", "Latn", type = "reconstructed", } m["cau-tsz-pro"] = { "Proto-Tsezian", 116773287, "cau-tsz", "Latn", type = "reconstructed", } m["cba-ata"] = { "Atanques", 4812783, "cba", "Latn", } m["cba-cat"] = { "Catío Chibcha", 7083619, "cba", "Latn", } m["cba-dor"] = { "Dorasque", 5297532, "cba", "Latn", } m["cba-dui"] = { "Duit", 3041061, "cba", "Latn", } m["cba-hue"] = { "Huetar", 35514, "cba", "Latn", } m["cba-nut"] = { "Nutabe", 7070405, "cba", "Latn", } m["cba-pro"] = { "Proto-Chibchan", 116773203, "cba", "Latn", type = "reconstructed", } m["ccs-pro"] = { "Proto-Kartvelian", 2608203, "ccs", "Latn", type = "reconstructed", strip_diacritics = { from = {"q̣", "p̣", "ʓ", "ċ"}, to = {"q̇", "ṗ", "ʒ", "c̣"} }, } m["ccs-gzn-pro"] = { "Proto-Georgian-Zan", 23808119, "ccs-gzn", "Latn", type = "reconstructed", strip_diacritics = { from = {"q̣", "p̣", "ʓ", "ċ"}, to = {"q̇", "ṗ", "ʒ", "c̣"} }, } m["cdc-cbm-pro"] = { "Proto-Central Chadic", 116773197, "cdc-cbm", "Latn", type = "reconstructed", } m["cdc-mas-pro"] = { "Proto-Masa", 116773789, "cdc-mas", "Latn", type = "reconstructed", } m["cdc-pro"] = { "Proto-Chadic", 116773201, "cdc", "Latn", type = "reconstructed", } m["cdd-pro"] = { "Proto-Caddoan", 116773725, "cdd", "Latn", type = "reconstructed", } m["cel-bry-pro"] = { "Proto-Britoniko", 1248800, "cel-bry", "Latn, Polyt", sort_key = { Latn = "cel-bry-pro-sortkey", }, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["cel-gal"] = { "Gallaecian", 3094789, "cel-his", } m["cel-gau"] = { "Gaulish", 29977, "cel", "Latn, Polyt, Ital", strip_diacritics = { Latn = {remove_diacritics = c.macron .. c.breve .. c.diaer}, }, sort_key = { Latn = "cel-bry-pro-sortkey", }, -- Ital translit in [[Module:scripts/data]] -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["cel-pro"] = { "Proto-Celtic", 653649, "cel", "Latn", type = "reconstructed", sort_key = "cel-pro-sortkey", } m["chi-pro"] = { "Proto-Chimakuan", 116773734, "chi", "Latn", type = "reconstructed", } m["chm-pro"] = { "Proto-Mari", 116773788, "chm", "Latn", type = "reconstructed", } m["cmc-pro"] = { "Proto-Chamic", 114793834, "cmc", "Latn", type = "reconstructed", } m["crp-bip"] = { "Basque-Icelandic Pidgin", 810378, "crp", "Latn", ancestors = "eu", } m["crp-gep"] = { "West Greenlandic Pidgin", 17036301, "crp", "Latn", ancestors = "kl", } m["crp-kia"] = { "Kiautschou German Pidgin", 108314615, "crp", "Latn", ancestors = "de", } m["crp-mar"] = { "Maroon Spirit Language", 1093206, "crp", "Latn", ancestors = "en", } m["crp-mpp"] = { "Macau Pidgin Portuguese", 128804537, "crp", "Hant, Latn", ancestors = "pt", sort_key = {Hant = "Hani-sortkey"}, } m["crp-rsn"] = { "Russenorsk", 505125, "crp", "Cyrl, Latn", ancestors = "nn, ru", translit = {Cyrl = "ru-translit"}, } m["crp-spp"] = { "Samoan Plantation Pidgin", 7409948, "crp", "Latn", ancestors = "en", } m["crp-slb"] = { "Solombala English", 7558525, "crp", "Cyrl, Latn", ancestors = "en, ru", translit = {Cyrl = "ru-translit"}, } m["crp-tpr"] = { "Taimyr Pidgin Russian", 16930506, "crp", "Cyrl", ancestors = "ru", translit = "ru-translit", } m["csu-bba-pro"] = { "Proto-Bongo-Bagirmi", 116773722, "csu-bba", "Latn", type = "reconstructed", } m["csu-maa-pro"] = { "Proto-Mangbetu", 116773786, "csu-maa", "Latn", type = "reconstructed", } m["csu-pro"] = { "Proto-Central Sudanic", 116773730, "csu", "Latn", type = "reconstructed", } m["csu-sar-pro"] = { "Proto-Sara", 116773809, "csu-sar", "Latn", type = "reconstructed", } m["cus-ash"] = { "Ashraaf", 4805855, "cus-som", "Latn", } m["cus-hec-pro"] = { "Proto-Highland East Cushitic", 116773761, "cus-hec", "Latn", type = "reconstructed", } m["cus-som-pro"] = { "Proto-Somaloid", nil, "cus-som", "Latn", type = "reconstructed", } m["cus-sou-pro"] = { "Proto-South Cushitic", 126081567, "cus-sou", "Latn", type = "reconstructed", } m["cus-pro"] = { "Proto-Cushitic", 116773204, "cus", "Latn", type = "reconstructed", } m["dmn-dam"] = { "Dama (Sierra Leone)", 19601574, "dmn", "Latn", } m["dra-bry"] = { "Beary", 1089116, "qfa-mix", "Mlym, Knda", ancestors = "ml, tcy", -- Knda translit in [[Module:scripts/data]] -- Mlym translit in [[Module:scripts/data]] } m["dra-cen-pro"] = { "Proto-Central Dravidian", nil, "dra-cen", "Latn", type = "reconstructed", } m["dra-mkn"] = { "Middle Kannada", 128810572, "dra-kan", "Knda", -- Knda translit in [[Module:scripts/data]] } m["dra-nor-pro"] = { "Proto-North Dravidian", 124433593, "dra-nor", "Latn", type = "reconstructed", } m["dra-okn"] = { "Old Kannada", 15723156, "dra-kan", "Knda", -- Knda translit in [[Module:scripts/data]] } m["dra-ote"] = { "Old Telugu", 126720868, "dra-tel", "Telu", translit = "te-translit", } m["dra-pro"] = { "Proto-Dravidian", 1702853, "dra", "Latn", type = "reconstructed", } m["dra-sdo-pro"] = { "Proto-South Dravidian I", 104847952, -- Wikipedia's "Proto-South Dravidian" is Proto-South Dravidian I in this scheme. "dra-sdo", "Latn", type = "reconstructed", } m["dra-sdt-pro"] = { "Proto-South Dravidian II", 128885257, "dra-sdt", "Latn", type = "reconstructed", } m["dra-sou-pro"] = { "Proto-South Dravidian", 128886121, "dra-sou", "Latn", type = "reconstructed", } m["egx-dem"] = { "Demotic Egyptian", 36765, "egx", "Latn, Egyd, Polyt", sort_key = { Latn = { remove_diacritics = "'%-%s", from = {"ꜣ", "j", "e", "ꜥ", "y", "w", "b", "p", "f", "m", "n", "r", "l", "ḥ", "ḫ", "h̭", "ẖ", "h", "š", "s", "q", "k", "g", "ṱ", "ṯ", "t", "ḏ", "%.", "⸗"}, to = {p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[15], p[16], p[16], p[17], p[14], p[19], p[18], p[20], p[21], p[22], p[23], p[24], p[23], p[25], p[26], p[26]} }, }, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["dmn-pro"] = { "Proto-Mande", 116773785, "dmn", "Latn", type = "reconstructed", } m["dmn-mdw-pro"] = { "Proto-Western Mande", 116773822, "dmn-mdw", "Latn", type = "reconstructed", } m["dru-pro"] = { "Proto-Rukai", 116773807, "map", "Latn", type = "reconstructed", } m["ero-gsz"] = { "Geshiza", nil, "ero", "Latn", } m["ero-nya"] = { "Nyagrong Minyag", nil, "ero", "Latn", } m["ero-tau"] = { "Stau", nil, "ero", "Latn", } m["esx-esk-pro"] = { "Proto-Eskimo", 7251842, "esx-esk", "Latn", type = "reconstructed", } m["esx-ink"] = { "Inuktun", 1671647, "esx-inu", "Latn", } m["esx-inq"] = { "Inuinnaqtun", 28070, "esx-inu", "Latn", } m["esx-inu-pro"] = { "Proto-Inuit", 60785588, "esx-inu", "Latn", type = "reconstructed", } m["esx-pro"] = { "Proto-Eskimo-Aleut", 7251843, "esx", "Latn", type = "reconstructed", } m["esx-tut"] = { "Tunumiisut", 15665389, "esx-inu", "Latn", } m["euq-pro"] = { "Proto-Basque", 938011, "euq", "Latn", type = "reconstructed", } m["gba-pro"] = { "Proto-Gbaya", nil, "gba", "Latn", type = "reconstructed", } m["gem-pro"] = { "Proto-Germanic", 669623, "gem", "Latn", type = "reconstructed", sort_key = "gem-pro-sortkey", } m["gme-bur"] = { "Burgundian", 47625, "gme", "Latn", } m["gme-cgo"] = { "Crimean Gothic", 36211, "gme", "Latn", } m["gmq-gut"] = { "Gutnish", 1256646, "gmq", "Latn", ancestors = "gmq-ogt", } m["gmq-jmk"] = { "Jamtish", 35512, "gmq-eas", "Latn", } m["gmq-mno"] = { "Middle Norwegian", 3417070, "gmq-wes", "Latn", } m["gmq-oda"] = { "Old Danish", 12330003, "gmq-eas", "Latn, Runr", strip_diacritics = {remove_diacritics = c.macron}, } m["gmq-ogt"] = { "Old Gutnish", 1133488, "gmq", "Latn, Runr", ancestors = "non", } m["gmq-osw"] = { "Old Swedish", 2417210, "gmq-eas", "Latn, Runr", strip_diacritics = {remove_diacritics = c.macron}, } m["gmq-pro"] = { "Proto-Norse", 1671294, "gmq", "Runr", translit = "Runr-translit", } m["gmq-scy"] = { "Scanian", 768017, "gmq-eas", "Latn", } m["gmw-bgh"] = { "Bergish", 329030, "gmw-frk", "Latn", } m["gmw-cfr"] = { "Central Franconian", 572197, "gmw-hgm", "Latn", ancestors = "gmh", wikimedia_codes = "ksh", } m["gmw-ecg"] = { "East Central German", 499344, -- subsumes Q699284, Q152965 "gmw-hgm", "Latn", ancestors = "gmh", } m["gmw-fin"] = { "Fingallian", 3072588, "gmw-ian", "Latn", } m["gmw-gts"] = { "Gottscheerish", 533109, "gmw-hgm", "Latn", ancestors = "bar", } m["gmw-jdt"] = { "Jersey Dutch", 1687911, "gmw-frk", "Latn", ancestors = "nl", } m["gmw-msc"] = { "Middle Scots", 3327000, "gmw-ang", "Latn", ancestors = "enm-esc", } m["gmw-pro"] = { "Proto-West Germanic", 78079021, "gmw", "Latn, Runr", -- type = "reconstructed", -- largely but not entirely reconstructed (like Proto-Norse); see April '24 BP, set back to reconstructed (?) if 'anti-asterisk' is added sort_key = "gmw-pro-sortkey", } m["gmw-rfr"] = { "Rhine Franconian", 707007, "gmw-hgm", "Latn", ancestors = "gmh", } m["gmw-stm"] = { "Sathmar Swabian", 2223059, "gmw-hgm", "Latn", ancestors = "swg", } m["gmw-tsx"] = { "Transylvanian Saxon", 260942, "gmw-hgm", "Latn", ancestors = "gmw-cfr", } m["gmw-vog"] = { "Volga German", 312574, "gmw-hgm", "Latn", ancestors = "gmw-rfr", } m["gmw-zps"] = { "Zipser German", 205548, "gmw-hgm", "Latn", ancestors = "gmh", } m["gn-cls"] = { "Classical Guarani", 17478065, "gn", "Latn", } m["grk-cal"] = { "Calabrian Greek", 1146398, "grk", "Latn, Grek", ancestors = "grk-ita", translit = { Grek = "el-translit", }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-ita"] = { "Italiot Greek", 19720507, "grk", "Latn, Grek", ancestors = "gkm", translit = { Grek = "el-translit", }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-mar"] = { "Mariupol Greek", 4400023, "grk", "Cyrl, Latn, Grek", ancestors = "gkm", translit = { Cyrl = "grk-mar-translit", Grek = "grk-mar-translit", }, override_translit = true, strip_diacritics = { Cyrl = {remove_diacritics = c.acute}, }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["grk-pro"] = { "Proto-Hellenic", 1231805, "grk", "Latn, Polyt", type = "reconstructed", sort_key = {Latn = { from = {"ʰ", "ʷ"}, to = {"h", "w"}, remove_diacritics = c.grave .. c.acute .. c.macron .. c.breve .. c.caron }}, -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] -- NOTE: formerly no translit specified for Polyt; presumably an accidental omission; if not, set Polyt = false in -- the translit section } m["hmn-pro"] = { "Proto-Hmong", 116773210, "hmn", "Latn", type = "reconstructed", } m["hmx-mie-pro"] = { "Proto-Mien", 116773229, "hmx-mie", "Latn", type = "reconstructed", } m["hmx-pro"] = { "Proto-Hmong-Mien", 7251846, "hmx", "Latn", type = "reconstructed", } m["hyx-pro"] = { "Proto-Armenian", 3848498, "hyx", "Latn", type = "reconstructed", } m["iir-nur-pro"] = { "Proto-Nuristani", 116773248, "iir-nur", "Latn", type = "reconstructed", } m["iir-pro"] = { "Proto-Indo-Iranian", 966439, "iir", "Latn", type = "reconstructed", } m["ijo-pro"] = { "Proto-Ijoid", 116773766, "ijo", "Latn", type = "reconstructed", } m["inc-apa"] = { "Apabhramsa", 616419, "inc-mid", "Deva, Shrd, Sidd", ancestors = "pra", translit = { Deva = "sa-translit", -- Shrd translit in [[Module:scripts/data]] -- Sidd translit in [[Module:scripts/data]] }, } m["inc-ash"] = { "Ashokan Prakrit", 104854379, "inc-mid", "Brah, Khar", ancestors = "sa", translit = { -- Brah translit in [[Module:scripts/data]] Khar = "Khar-translit", }, } m["inc-dng-pro"] = { "Proto-Dangari", nil, "inc-dng", "Latn", type = "reconstructed", } m["inc-kam"] = { "Kamarupi Prakrit", 6356097, "inc-bas", "Brah, Sidd", -- Brah, Sidd translit in [[Module:scripts/data]] } m["inc-kho"] = { "Kholosi", 24952008, "inc-snd", "Latn", } m["inc-krd-pro"] = { "Proto-Kamta", 128816843, "inc-bas", "Latn", ancestors = "inc-kam", type = "reconstructed", } m["inc-mas"] = { "Middle Assamese", 128806836, "inc-bas", "as-Beng", ancestors = "inc-oas", translit = "inc-mas-translit", } m["inc-mbn"] = { "Gitnang Benggali", --TLCHANGE 113559927, "inc-bas", "Beng", ancestors = "inc-obn", translit = "inc-mbn-translit", english_name = "Middle Bengali", --TLCHANGE } m["inc-mgu"] = { "Middle Gujarati", 24907429, "inc-wes", "Deva", ancestors = "inc-ogu", } m["inc-mor"] = { "Middle Odia", 128810882, "inc-eas", "Orya", ancestors = "inc-oor", } m["inc-oas"] = { "Early Assamese", 85758237, "inc-bas", "as-Beng", ancestors = "inc-kam", translit = "inc-oas-translit", } m["inc-oaw"] = { "Old Awadhi", nil, "inc-hie", "Deva, Kthi, ur-Arab", strip_diacritics = { from = {"هٔ", "ۂ"}, -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه" to = {"ہ", "ہ"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, translit = { Deva = "sa-translit", Kthi = "sa-Kthi-translit", ["ur-Arab"] = "inc-ohi-translit", }, } m["inc-obn"] = { "Lumang Benggali", --TLCHANGE 113559926, "inc-bas", "Beng", english_name = "Old Bengali", --TLCHANGE } m["inc-ogu"] = { "Old Gujarati", 24907427, "inc-wes", "Deva", translit = "sa-translit", } m["inc-ohi"] = { "Lumang Hindi", --TLCHANGE 48767781, "inc-hiw", "Deva, ur-Arab", strip_diacritics = { from = {"هٔ", "ۂ"}, -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه" to = {"ہ", "ہ"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, translit = { Deva = "sa-translit", ["ur-Arab"] = "inc-ohi-translit", }, english_name = "Old Hindi", --TLCHANGE } m["inc-oor"] = { "Old Odia", 128807801, "inc-eas", "Orya", } m["inc-opa"] = { "Old Punjabi", 115270971, "inc-pan", "Guru, pa-Arab", translit = { Guru = "inc-opa-Guru-translit", ["pa-Arab"] = "pa-Arab-translit", }, strip_diacritics = {remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun}, } m["inc-pro"] = { "Proto-Indo-Aryan", 23808344, "inc", "Latn", type = "reconstructed", } m["ine-ana-pro"] = { "Proto-Anatolian", 7251833, "ine-ana", "Latn", type = "reconstructed", } m["ine-bsl-pro"] = { "Proto-Balto-Slavic", 1703347, "ine-bsl", "Latn", type = "reconstructed", sort_key = { from = {"[áā]", "[éēḗ]", "[íī]", "[óōṓ]", "[úū]", c.acute, c.macron, "ˀ"}, to = {"a", "e", "i", "o", "u"} }, } m["ine-kal"] = { "Kalašma", 122770439, "ine-ana", "Xsux", } m["ine-pae"] = { "Paeonian", 2705672, "ine", "Polyt", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["ine-pro"] = { "Proto-Indo-Europeo", --TLCHANGE 37178, "ine", "Latn", type = "reconstructed", sort_key = { from = {"[áā]", "[éēḗ]", "[íī]", "[óōṓ]", "[úū]", "ĺ", "ḿ", "ń", "ŕ", "ǵ", "ḱ", "ʰ", "ʷ", "₁", "₂", "₃", c.ringbelow, c.acute, c.macron}, to = {"a", "e", "i", "o", "u", "l", "m", "n", "r", "g'", "k'", "¯h", "¯w", "1", "2", "3"} }, english_name = "Proto-Indo-European", --TLCHANGE spanish_name = "Protoindoeuropeo", --TLCHANGE } m["ine-toc-pro"] = { "Proto-Tocharian", 104841462, "ine-toc", "Latn", type = "reconstructed", } m["xme-old"] = { "Old Median", 36461, "xme", "Polyt, Latn", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["xme-mid"] = { "Middle Median", 12836150, "xme", "Latn", } m["xme-ker"] = { "Kermanic", 129850, "xme", "fa-Arab, Latn, Hebr", ancestors = "xme-mid", -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["xme-taf"] = { "Tafreshi", nil, "xme", "fa-Arab, Latn", ancestors = "xme-mid", } m["xme-ttc-pro"] = { "Proto-Tatic", 122973870, "xme-ttc", "Latn", ancestors = "xme-mid", } m["xme-kls"] = { "Kalasuri", nil, "xme-ttc", ancestors = "xme-ttc-nor", } m["xme-klt"] = { "Kilit", 3612452, "xme-ttc", "Cyrl", -- and fa-Arab? } m["xme-ott"] = { "Old Tati", 434697, "xme-ttc", "fa-Arab, Latn", } m["ira-kms-pro"] = { "Proto-Komisenian", 116773777, "ira-kms", "Latn", type = "reconstructed", } m["ira-mpr-pro"] = { "Proto-Medo-Parthian", 116773227, "ira-mpr", "Latn", type = "reconstructed", } m["ira-pat-pro"] = { "Proto-Pathan", 116773255, "ira-pat", "Latn", type = "reconstructed", } m["ira-pro"] = { "Proto-Iranian", 4167865, "ira", "Latn", type = "reconstructed", } m["ira-zgr-pro"] = { "Proto-Zaza-Gorani", 116775031, "ira-zgr", "Latn", type = "reconstructed", } m["xsc-pro"] = { "Proto-Scythian", 116773273, "xsc", "Latn", type = "reconstructed", } m["xsc-sar-pro"] = { "Proto-Sarmatian", 116773249, "xsc-sar", "Latn", type = "reconstructed", } m["xsc-skw-pro"] = { "Proto-Saka-Wakhi", 116773267, "xsc-skw", "Latn", type = "reconstructed", } m["xsc-sak-pro"] = { "Proto-Saka", 116773264, "xsc-sak", "Latn", type = "reconstructed", } m["ira-sym-pro"] = { "Proto-Shughni-Yazghulami-Munji", 116773813, "ira-sym", "Latn", type = "reconstructed", } m["ira-sgi-pro"] = { "Proto-Sanglechi-Ishkashimi", 116773808, "ira-sgi", "Latn", type = "reconstructed", } m["ira-mny-pro"] = { "Proto-Munji-Yidgha", 116773792, "ira-mny", "Latn", type = "reconstructed", } m["ira-shy-pro"] = { "Proto-Shughni-Yazghulami", 116773812, "ira-shy", "Latn", type = "reconstructed", } m["ira-shr-pro"] = { "Proto-Shughni-Roshani", 116773811, "ira-shr", "Latn", type = "reconstructed", } m["ira-sgc-pro"] = { "Proto-Sogdic", 116773276, "ira-sgc", "Latn", type = "reconstructed", } m["ira-wnj"] = { "Vanji", 3398419, "ira-shy", "Latn", } m["iro-ere"] = { "Erie", 5388365, "iro-nor", "Latn", } m["iro-min"] = { "Mingo", 128531, "iro-nor", "Latn", ietf_subtag = "i-mingo", -- grandfathered IETF tag } m["iro-nor-pro"] = { "Proto-North Iroquoian", 116773242, "iro-nor", "Latn", type = "reconstructed", } m["iro-pro"] = { "Proto-Iroquoian", 7251852, "iro", "Latn", type = "reconstructed", } m["itc-pro"] = { "Proto-Italiko", -- tlchange 17102720, "itc", "Latn", type = "reconstructed", } m["itc-psa"] = { "Pre-Samnite", 7239186, "itc-sbl", "Ital, Polyt, Latn", -- Ital translit in [[Module:scripts/data]] (NOTE: formerly not present, probably an accidental omission) -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["jpx-hcj"] = { "Hachijō", 5637049, "jpx", "Jpan", ancestors = "ojp-eas", translit = s["jpx-translit"], display_text = s["jpx-displaytext"], strip_diacritics = s["jpx-stripdiacritics"], sort_key = s["jpx-sortkey"], } m["jpx-pro"] = { "Proto-Japonic", 3924309, "jpx", "Latn", type = "reconstructed", } m["jpx-ryu-pro"] = { "Proto-Ryukyuan", 56349069, "jpx-ryu", "Latn", type = "reconstructed", } m["kar-pro"] = { "Proto-Karen", 85794783, "kar", "Latn", type = "reconstructed", } m["kca-eas"] = { "Eastern Khanty", 30304622, "kca", "Cyrl", translit = "kca-translit", override_translit = true, -- TODO temporary until MediaWiki supports Unicode 16 (probably requires a PHP update from their side) sort_key = { Cyrl = { from = {"ᲊ"}, to = {"Ᲊ"} } }, } m["kca-nor"] = { "Northern Khanty", 30304527, "kca", "Cyrl", translit = "kca-translit", override_translit = true, -- TODO temporary until MediaWiki supports Unicode 16 (probably requires a PHP update from their side) sort_key = { Cyrl = { from = {"ᲊ"}, to = {"Ᲊ"} } }, } m["kca-pro"] = { "Proto-Khanty", 127505171, "kca", "Latn", type = "reconstructed", } m["kca-sou"] = { "Southern Khanty", 30304618, "kca", "Cyrl", translit = "kca-translit", override_translit = true, } m["khi-kho-pro"] = { "Proto-Khoe", 116773218, "khi-kho", "Latn", type = "reconstructed", } m["khi-kun"] = { "ǃKung", 32904, "khi-kxa", "Latn", } m["ko-ear"] = { "Early Modern Korean", 756014, "qfa-kor", "Kore", ancestors = "okm", translit = "okm-translit", -- Kore strip_diacritics in [[Module:scripts/data]] } m["kro-pro"] = { "Proto-Kru", 116773778, "kro", "Latn", type = "reconstructed", } m["ku-pro"] = { "Proto-Kurdish", 116773221, "ku", "Latn", type = "reconstructed", } m["map-ata-pro"] = { "Proto-Atayalic", 116773151, "map-ata", "Latn", type = "reconstructed", } m["map-bms"] = { "Banyumasan", 33219, "map", "Latn, Java", } m["map-pro"] = { "Proto-Austronesian", 49230, "map", "Latn", type = "reconstructed", } m["mis-hkl"] = { "Kelantan Peranakan Hokkien", 108794818, "qfa-mix", ancestors = "nan-hbl, sou, mfa", } m["mis-idn"] = { "Idiom Neutral", 35847, "art", "Latn", type = "appendix-constructed", } m["mis-isa"] = { "Isaurian", 16956868, nil, -- "Xsux, Hluw, Latn", } m["mis-jie"] = { "Jie", 124424186, nil, "Hani", sort_key = "Hani-sortkey", } m["mis-jzh"] = { "Jizhao", 45242758, "qfa-bej", "Latn", } m["mis-kas"] = { "Kassite", 35612, nil, "Xsux", } m["mis-mmd"] = { "Mimi of Decorse", 6862206, nil, "Latn", } m["mis-mmn"] = { "Mimi of Nachtigal", 6862207, nil, "Latn", } m["mis-phi"] = { "Philistine", 2230924, nil, "Phnx", -- Phnx translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission) } m["mis-rou"] = { "Rouran", 48816637, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-tdl"] = { "Turdulian", 133176492, } m["mis-tdt"] = { "Turdetanian", 133176461, } m["mis-tnw"] = { "Tangwang", 7683179, "qfa-mix", "Latn", ancestors = "cmn, sce", } m["mis-tuh"] = { "Tuyuhun", 48816625, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-tuo"] = { "Tuoba", 48816629, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-wuh"] = { "Wuhuan", 118976867, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-xbi"] = { "Xianbei", 4448647, "qfa-xgx", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mis-xnu"] = { "Xiongnu", 10901674, nil, "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mjg-mgl"] = { "Mongghul", 53765528, "mjg", "Latn", -- also Mong, Cyrl ? } m["mjg-mgr"] = { "Mangghuer", 56285392, "mjg", "Latn", -- also Mong, Cyrl ? } m["mkh-asl-pro"] = { "Proto-Aslian", 55630680, "mkh-asl", "Latn", type = "reconstructed", } m["mkh-ban-pro"] = { "Proto-Bahnaric", 116773189, "mkh-ban", "Latn", type = "reconstructed", } m["mkh-kat-pro"] = { "Proto-Katuic", 116773772, "mkh-kat", "Latn", type = "reconstructed", } m["mkh-khm-pro"] = { "Proto-Khmuic", 116773774, "mkh-khm", "Latn", type = "reconstructed", } m["mkh-kmr-pro"] = { "Proto-Khmeric", 55630684, "mkh-kmr", "Latn", type = "reconstructed", } m["mkh-mmn"] = { "Middle Mon", 121337926, "mkh-mnc", "Latn, Mymr", --and also Pallava ancestors = "omx", } m["mkh-mnc-pro"] = { "Proto-Monic", 116773231, "mkh-mnc", "Latn", type = "reconstructed", } m["mkh-mvi"] = { "Middle Vietnamese", 9199, "mkh-vie", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["mkh-pal-pro"] = { "Proto-Palaungic", 104847372, "mkh-pal", "Latn", type = "reconstructed", } m["mkh-pea-pro"] = { "Proto-Pearic", 116773804, "mkh-pea", "Latn", type = "reconstructed", } m["mkh-pkn-pro"] = { "Proto-Pakanic", 116773803, "mkh-pkn", "Latn", type = "reconstructed", } m["mkh-pro"] = { --This will be merged into 2015 aav-pro. "Proto-Mon-Khmer", 7251859, "mkh", "Latn", type = "reconstructed", } m["mnw-tha"] = { -- To be removed. "Thai Mon", nil, "mkh-mnc", "Mymr, Thai", ancestors = "mkh-mmn", sort_key = { from = {"[%p]", "ျ", "ြ", "ွ", "ှ", "ၞ", "ၟ", "ၠ", "ၚ", "ဿ", "[็-๎]", "([เแโใไ])([ก-ฮ])ฺ?"}, to = {"", "္ယ", "္ရ", "္ဝ", "္ဟ", "္န", "္မ", "္လ", "င", "သ္သ", "", "%2%1"} }, } m["mkh-vie-pro"] = { "Proto-Vietic", 109432616, "mkh-vie", "Latn", type = "reconstructed", } m["mns-cen"] = { "Central Mansi", 128810384, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mns-nor"] = { "Northern Mansi", 30304537, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mns-pro"] = { "Proto-Mansi", 128883093, "mns", "Latn", type = "reconstructed", } m["mns-sou"] = { "Southern Mansi", 30304629, "mns", "Cyrl", translit = "mns-translit", override_translit = true, } m["mun-pro"] = { "Proto-Munda", 105102373, "mun", "Latn", type = "reconstructed", } m["myn-chl"] = { -- the stage after ''emy'' "Ch'olti'", 873995, "myn", "Latn", } m["myn-pro"] = { "Proto-Mayan", 3321532, "myn", "Latn", type = "reconstructed", } m["nai-ala"] = { "Alazapa", 128810233, nil, "Latn", } m["nai-bay"] = { "Bayogoula", 1563704, nil, "Latn", } m["nai-cal"] = { "Calusa", 51782, nil, "Latn", } m["nai-chi"] = { "Chiquimulilla", 25339627, "nai-xin", "Latn", } m["nai-chu-pro"] = { "Proto-Chumash", 116773736, "nai-chu", "Latn", type = "reconstructed", } m["nai-cig"] = { "Ciguayo", 20741700, nil, "Latn", } m["nai-ckn-pro"] = { "Proto-Chinookan", 116773735, "nai-ckn", "Latn", type = "reconstructed", } m["nai-guz"] = { "Guazacapán", 19572028, "nai-xin", "Latn", } m["nai-hit"] = { "Hitchiti", 1542882, "nai-mus", "Latn", } m["nai-ipa"] = { "Ipai", 3027474, "nai-yuc", "Latn", } m["nai-jtp"] = { "Jutiapa", nil, "nai-xin", "Latn", } m["nai-jum"] = { "Jumaytepeque", 25339626, "nai-xin", "Latn", } m["nai-kat"] = { "Kathlamet", 6376639, "nai-ckn", "Latn", } m["nai-klp-pro"] = { "Proto-Kalapuyan", 116773771, "nai-klp", "Latn", type = "reconstructed", } m["nai-knm"] = { "Konomihu", 3198734, "nai-shs", "Latn", } m["nai-kum"] = { "Kumeyaay", 4910139, "nai-yuc", "Latn", } m["nai-mac"] = { "Macoris", 21070851, nil, "Latn", } m["nai-mdu-pro"] = { "Proto-Maidun", 116773784, "nai-mdu", "Latn", type = "reconstructed", } m["nai-miz-pro"] = { "Proto-Mixe-Zoque", 7251858, "nai-miz", "Latn", type = "reconstructed", } m["nai-mus-pro"] = { "Proto-Muskogean", 116775368, "nai-mus", "Latn", type = "reconstructed", } m["nai-nao"] = { "Naolan", 6964594, nil, "Latn", } m["nai-nrs"] = { "New River Shasta", 7011254, "nai-shs", "Latn", } m["nai-okw"] = { "Okwanuchu", 3350126, "nai-shs", "Latn", } m["nai-per"] = { "Pericú", 3375369, nil, "Latn", } m["nai-pic"] = { "Picuris", 7191257, "nai-kta", "Latn", } m["nai-plp-pro"] = { "Proto-Plateau Penutian", 116773806, "nai-plp", "Latn", type = "reconstructed", } m["nai-pom-pro"] = { "Proto-Pomo", 116773262, "nai-pom", "Latn", type = "reconstructed", } m["nai-qng"] = { "Quinigua", 36360, nil, "Latn", } m["nai-sca-pro"] = { -- NB 'sio-pro' "Proto-Siouan" which is Proto-Western Siouan "Proto-Siouan-Catawban", 116773275, "nai-sca", "Latn", type = "reconstructed", } m["nai-sin"] = { "Sinacantán", 24190249, "nai-xin", "Latn", } m["nai-sln"] = { "Salvadoran Lenca", 3229434, "nai-len", "Latn", } m["nai-spt"] = { "Sahaptin", 3833015, "nai-shp", "Latn", } m["nai-tap"] = { "Tapachultec", 7684401, "nai-miz", "Latn", } m["nai-taw"] = { "Tawasa", 7689233, nil, "Latn", } m["nai-teq"] = { "Tequistlatec", 2964454, "nai-tqn", "Latn", } m["nai-tip"] = { "Tipai", 3027471, "nai-yuc", "Latn", } m["nai-tot-pro"] = { "Proto-Totozoquean", 116773285, "nai-tot", "Latn", type = "reconstructed", } m["nai-tsi-pro"] = { "Proto-Tsimshianic", nil, "nai-tsi", "Latn", type = "reconstructed", } m["nai-utn-pro"] = { "Proto-Utian", 116773290, "nai-utn", "Latn", type = "reconstructed", } m["nai-wai"] = { "Waikuri", 3118702, nil, "Latn", } m["nai-wji"] = { "Western Jicaque", 3178610, "nai-jcq", "Latn", } m["nai-yup"] = { "Yupiltepeque", 25339628, "nai-xin", "Latn", } m["nan-dat"] = { "Datian Min", 19855572, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-hbl"] = { "Hokkien", 1624231, "zhx-nan", "Hants, Latn, Bopo, Kana", wikimedia_codes = "zh-min-nan", generate_forms = "zh-generateforms", sort_key = { Hani = "Hani-sortkey", Kana = "Kana-sortkey" }, } m["nan-hlh"] = { "Hailufeng Min", 120755728, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-lnx"] = { "Longyan Min", 6674568, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-tws"] = { "Teochew", 36759, "zhx-nan", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", } m["nan-zhe"] = { "Zhenan Min", 3846710, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nan-zsh"] = { "Sanxiang Min", 7420769, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["nds-de"] = { "German Low German", 25433, "gmw-lgm", "Latn", ancestors = "nds", ietf_subtag = "nds-DE", -- should we make this the actual code? wikimedia_codes = "nds", } m["nds-nl"] = { "Dutch Low Saxon", 516137, "gmw-lgm", "Latn", ancestors = "nds", ietf_subtag = "nds-NL", -- should we make this the actual code? wikimedia_codes = "nds-nl", } m["ngf-bin-pro"] = { "Proto-Binanderean", 137881672, "ngf-bin", "Latn", type = "reconstructed", } m["ngf-pro"] = { "Proto-Trans-New Guinea", 85794785, "ngf", "Latn", type = "reconstructed", } m["nic-bco-pro"] = { "Proto-Benue-Congo", 116773194, "nic-bco", "Latn", type = "reconstructed", } m["nic-bod-pro"] = { "Proto-Bantoid", 116773190, "nic-bod", "Latn", type = "reconstructed", } m["nic-eov-pro"] = { "Proto-Eastern Oti-Volta", 116773753, "nic-eov", "Latn", type = "reconstructed", } m["nic-gns-pro"] = { "Proto-Gurunsi", 116773759, "nic-gns", "Latn", type = "reconstructed", } m["nic-grf-pro"] = { "Proto-Grassfields", 116773755, "nic-grf", "Latn", type = "reconstructed", } m["nic-gur-pro"] = { "Proto-Gur", 116773758, "nic-gur", "Latn", type = "reconstructed", } m["nic-jkn-pro"] = { "Proto-Jukunoid", 116773769, "nic-jkn", "Latn", type = "reconstructed", } m["nic-lcr-pro"] = { "Proto-Lower Cross River", 116773782, "nic-lcr", "Latn", type = "reconstructed", } m["nic-ogo-pro"] = { "Proto-Ogoni", 116773799, "nic-ogo", "Latn", type = "reconstructed", } m["nic-ovo-pro"] = { "Proto-Oti-Volta", 116773802, "nic-ovo", "Latn", type = "reconstructed", } m["nic-plt-pro"] = { "Proto-Plateau", 116773805, "nic-plt", "Latn", type = "reconstructed", } m["nic-pro"] = { "Proto-Niger-Congo", 108000748, "nic", "Latn", type = "reconstructed", } m["nic-ubg-pro"] = { "Proto-Ubangian", 116773818, "nic-ubg", "Latn", type = "reconstructed", } m["nic-ucr-pro"] = { "Proto-Upper Cross River", 116773819, "nic-ucr", "Latn", type = "reconstructed", } m["nic-vco-pro"] = { "Proto-Volta-Congo", 116773293, "nic-vco", "Latn", type = "reconstructed", } m["nub-har"] = { "Haraza", 19572059, "nub", "Arab, Latn", } m["nub-pro"] = { "Proto-Nubian", 116773246, "nub", "Latn", type = "reconstructed", } m["omq-cha-pro"] = { "Proto-Chatino", 116773202, "omq-cha", "Latn", type = "reconstructed", } m["omq-maz-pro"] = { "Proto-Mazatec", 116773790, "omq-maz", "Latn", type = "reconstructed", } m["omq-mix-pro"] = { "Proto-Mixtecan", 21573423, "omq-mix", "Latn", type = "reconstructed", } m["omq-mxt-pro"] = { "Proto-Mixtec", 21573424, "omq-mxt", "Latn", type = "reconstructed", } m["omq-otp-pro"] = { "Proto-Oto-Pamean", 116773251, "omq-otp", "Latn", type = "reconstructed", } m["omq-pro"] = { "Proto-Oto-Manguean", 33669, "omq", "Latn", type = "reconstructed", } m["omq-sjq"] = { "San Juan Quiahije Chatino", 17003130, "omq-cha", "Latn", } m["omq-tel"] = { "Teposcolula Mixtec", nil, "omq-mxt", "Latn", } m["omq-teo"] = { "Teojomulco Chatino", 25340451, "omq-cha", "Latn", } m["omq-tri-pro"] = { "Proto-Triqui", 116773817, "omq-tri", "Latn", type = "reconstructed", } m["omq-zap-pro"] = { "Proto-Zapotecan", 116773297, "omq-zap", "Latn", type = "reconstructed", } m["omq-zpc-pro"] = { "Proto-Zapotec", 116773296, "omq-zpc", "Latn", type = "reconstructed", } m["omv-aro-pro"] = { "Proto-Aroid", 116773721, "omv-aro", "Latn", type = "reconstructed", } m["omv-diz-pro"] = { "Proto-Dizoid", 116773750, "omv-diz", "Latn", type = "reconstructed", } m["omv-pro"] = { "Proto-Omotic", 116773800, "omv", "Latn", type = "reconstructed", } m["oto-otm-pro"] = { "Proto-Otomi", 5908710, "oto-otm", "Latn", type = "reconstructed", } m["oto-pro"] = { "Proto-Otomian", 116773252, "oto", "Latn", type = "reconstructed", } m["paa-kmn"] = { "Kómnzo", 18344310, "paa-wko", "Latn", } m["paa-kwn"] = { "Kuwani", 6449056, "qfa-unc", -- poorly attested, possibly the same as or related to Kalabra "Latn", } m["paa-lei"] = { "Leitre", 85776228, "paa-isk", } m["paa-nha-pro"] = { "Proto-North Halmahera", 116773241, "paa-nha", "Latn", type = "reconstructed" } m["paa-nun"] = { "Nungon", 128807788, "ngf-ynu", "Latn", } m["phi-din"] = { "Dinapigue Agta", 16945774, "phi", "Latn", } m["phi-kal-pro"] = { "Proto-Kalamian", 116773213, "phi-kal", "Latn", type = "reconstructed", } m["phi-nag"] = { "Nagtipunan Agta", 16966111, "phi", "Latn", } m["phi-pro"] = { "Proto-Pilipino", --TLCHANGE 18204898, "phi", "Latn", type = "reconstructed", english_name = "Proto-Philippine", --TLCHANGE } m["poz-abi"] = { "Abai", 19570729, "poz-san", "Latn", } m["poz-bal"] = { "Baliledo", 4850912, "poz", "Latn", } m["poz-btk-pro"] = { "Proto-Bungku-Tolaki", 116773724, "poz-btk", "Latn", type = "reconstructed", } m["poz-cet-pro"] = { "Proto-Central-Eastern Malayo-Polynesian", 2269883, "poz-cet", "Latn", type = "reconstructed", } m["poz-hce-pro"] = { "Proto-Halmahera-Cenderawasih", 116773209, "poz-hce", "Latn", type = "reconstructed", } m["poz-lgx-pro"] = { "Proto-Lampungic", 116773222, "poz-lgx", "Latn", type = "reconstructed", } m["poz-mcm-pro"] = { "Proto-Malayo-Chamic", 116773225, "poz-mcm", "Latn", type = "reconstructed", } m["poz-mic-pro"] = { "Proto-Micronesian", 111939079, "poz-mic", "Latn", type = "reconstructed", } m["poz-mly-pro"] = { "Proto-Malayic", 98057728, "poz-mly", "Latn", type = "reconstructed", } m["poz-msa-pro"] = { "Proto-Malayo-Sumbawan", 116773226, "poz-msa", "Latn", type = "reconstructed", } m["poz-oce-pro"] = { "Proto-Oceanic", 141741, "poz-oce", "Latn", type = "reconstructed", } m["poz-pep-pro"] = { "Proto-Eastern Polynesian", 113988745, "poz-pep", "Latn", type = "reconstructed", } m["poz-pnp-pro"] = { "Proto-Nuclear Polynesian", 113988746, "poz-pnp", "Latn", type = "reconstructed", } m["poz-pol-pro"] = { "Proto-Polynesian", 1658709, "poz-pol", "Latn", type = "reconstructed", } m["poz-pro"] = { "Proto-Malayo-Polynesian", 3832960, "poz", "Latn", type = "reconstructed", } m["poz-sml"] = { "Sarawak Malay", 4251702, "poz-mly", "Latn, ms-Arab", } m["poz-ssw-pro"] = { "Proto-South Sulawesi", 116773279, "poz-ssw", "Latn", type = "reconstructed", } m["poz-swa-pro"] = { "Proto-North Sarawak", 116773243, "poz-swa", "Latn", type = "reconstructed", } m["poz-ter"] = { "Terengganu Malay", 4207412, "poz-mly", "Latn, ms-Arab", } m["pqe-pro"] = { "Proto-Eastern Malayo-Polynesian", 2269883, "pqe", "Latn", type = "reconstructed", } m["pra-niy"] = { "Niya Prakrit", 11991601, "inc-mid", "Khar", ancestors = "inc-ash", translit = "Khar-translit", } m["qfa-adm-pro"] = { "Proto-Great Andamanese", 116773756, "qfa-adm", "Latn", type = "reconstructed", } m["qfa-bet-pro"] = { "Proto-Be-Tai", 116773193, "qfa-bet", "Latn", type = "reconstructed", } m["qfa-cka-pro"] = { "Proto-Chukotko-Kamchatkan", 7251837, "qfa-cka", "Latn", type = "reconstructed", } m["qfa-hur-pro"] = { "Proto-Hurro-Urartian", 116773211, "qfa-hur", "Latn", type = "reconstructed", } m["qfa-kad-pro"] = { "Proto-Kadu", 116773770, "qfa-kad", "Latn", type = "reconstructed", } m["qfa-kms-pro"] = { "Proto-Kam-Sui", 55630682, "qfa-kms", "Latn", type = "reconstructed", } m["qfa-kor-pro"] = { "Proto-Koreanic", 467883, "qfa-kor", "Latn", type = "reconstructed", } m["qfa-kra-pro"] = { "Proto-Kra", 7251854, "qfa-kra", "Latn", type = "reconstructed", } m["qfa-lic-pro"] = { "Proto-Hlai", 7251845, "qfa-lic", "Latn", type = "reconstructed", } m["qfa-onb-pro"] = { "Proto-Be", 116773192, "qfa-onb", "Latn", type = "reconstructed", } m["qfa-ong-pro"] = { "Proto-Ongan", 116773801, "qfa-ong", "Latn", type = "reconstructed", } m["qfa-tak-pro"] = { "Proto-Kra-Dai", 104901616, "qfa-tak", "Latn", type = "reconstructed", } m["qfa-yen-pro"] = { "Proto-Yeniseian", 27639, "qfa-yen", "Latn", type = "reconstructed", } m["qfa-yuk-pro"] = { "Proto-Yukaghir", 116773294, "qfa-yuk", "Latn", type = "reconstructed", } m["qwe-kch"] = { "Kichwa", 1740805, "qwe", "Latn", ancestors = "qu", } m["qwe-pro"] = { "Proto-Quechuan", 5575757, "qwe", "Latn", type = "reconstructed", } m["roa-ang"] = { "Angevin", 56782, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-bbn"] = { "Bourbonnais-Berrichon", 2899128, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-brg"] = { "Bourguignon", 508332, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-can"] = { "Cantabrian", 917021, "roa-asl", "Latn", } m["roa-cha"] = { "Champenois", 430018, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-fcm"] = { "Franc-Comtois", 510561, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-gal"] = { "Gallo", 37300, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-gib"] = { "Gallo-Italic of Basilicata", 3094838, "roa-git", ancestors = "pms-old", "Latn", } m["roa-gis"] = { "Gallo-Italic of Sicily", 2629019, "roa-git", "Latn", ancestors = "pms-old", } m["roa-leo"] = { "Leones", --TLCHANGE 34108, "roa-asl", "Latn", english_name = "Leonese", --TLCHANGE spanish_name = "Leonés", --TLCHANGE } m["roa-lor"] = { "Lorrain", 671198, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-oca"] = { "Lumang Katalan", --TLCHANGE 15478520, "roa-ocr", "Latn", sort_key = {remove_diacritics = c.grave .. c.acute .. c.diaer .. c.cedilla .. "·"}, english_name = "Old Catalan", --TLCHANGE } m["roa-ole"] = { "Lumang Leones", --TLCHANGE 125977465, "roa-asl", "Latn", english_name = "Old Leonese", --TLCHANGE } m["roa-ona"] = { "Old Navarro-Aragonese", 2736184, "roa-nar", "Latn", } m["roa-opt"] = { "Lumang Galisyano-Portuges", 1072111, "roa-gap", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ}, } m["roa-orl"] = { "Orléanais", 28497058, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-poi"] = { "Poitevin-Saintongeais", 514123, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["roa-tar"] = { "Tarantino", 695526, "roa-itr", "Latn", wikimedia_codes = "roa-tara", } m["sai-all"] = { "Allentiac", 19570789, "sai-hrp", "Latn", } m["sai-and"] = { -- not to be confused with 'cbc' or 'ano' "Andoquero", 16828359, "sai-wit", "Latn", } m["sai-ayo"] = { "Ayomán", 16937754, "sai-jir", "Latn", } m["sai-bae"] = { "Baenan", 3401998, "qfa-unc", -- extinct, poorly attested; only known through 9 words "Latn", } m["sai-bag"] = { "Bagua", 5390321, "qfa-unc", -- extinct, poorly attested; possibly Cariban "Latn", } m["sai-bet"] = { "Betoi", 926551, "qfa-iso", "Latn", } m["sai-bor-pro"] = { "Proto-Boran", nil, "sai-bor", "Latn", } m["sai-cac"] = { "Cacán", 945482, "qfa-unc", -- extinct, poorly attested; no consensus on classification "Latn", } m["sai-caq"] = { "Caranqui", 2937753, "sai-bar", "Latn", } m["sai-car-pro"] = { "Proto-Cariban", 116773196, "sai-car", "Latn", type = "reconstructed", } m["sai-cat"] = { "Catacao", 5051136, "sai-ctc", "Latn", } m["sai-cer-pro"] = { "Proto-Cerrado", 116773200, "sai-cer", "Latn", type = "reconstructed", } m["sai-chi"] = { "Chirino", 5390321, "qfa-unc", -- extinct, only four words known; possibly related to Candoshi-Shapra (cbu) "Latn", } m["sai-chn"] = { "Chaná", 5072718, "sai-crn", "Latn", } m["sai-chp"] = { "Chapacura", 5072884, "sai-cpc", "Latn", } m["sai-chr"] = { "Charrua", 5086680, "sai-crn", "Latn", } m["sai-chu"] = { "Churuya", 5118339, "sai-guh", "Latn", } m["sai-cje-pro"] = { "Proto-Central Jê", 116773198, "sai-cje", "Latn", type = "reconstructed", } m["sai-cmg"] = { "Comechingon", 6644203, "qfa-unc", -- extinct, poorly attested; no consensus on classification "Latn", } m["sai-cno"] = { "Chono", 5104704, "qfa-unc", -- extinct, poorly attested; no consensus on classification, possibly spurious "Latn", } m["sai-cnr"] = { "Cañari", 5055572, "qfa-unc", -- extinct, poorly attested; possibly Chimuan or Barbacoan "Latn", } m["sai-coe"] = { "Coeruna", 6425639, "sai-wit", "Latn", } m["sai-col"] = { "Colán", 5141893, "sai-ctc", "Latn", } m["sai-cop"] = { "Copallén", 5390321, "qfa-unc", -- extinct, only four words attested; possibly Cholonan "Latn", } m["sai-crd"] = { "Coroado Puri", 24191321, "sai-mje", "Latn", } m["sai-ctq"] = { "Catuquinaru", 16858455, "qfa-unc", -- extinct, poorly attested; vocabulary does not resemble other languages "Latn", } m["sai-cul"] = { "Culli", 2879660, "qfa-unc", -- extinct, poorly attested; often considered an isolate "Latn", } m["sai-cva"] = { "Cueva", 5192644, "qfa-unc", -- extinct, poorly attested; possibly Chocoan "Latn", } m["sai-esm"] = { "Esmeralda", 3058083, "qfa-unc", -- extinct, poorly attested; possibly related to Yaruro "Latn", } m["sai-ewa"] = { "Ewarhuyana", 16898104, nil, "Latn", } m["sai-gam"] = { "Gamela", 5403661, "qfa-unc", -- extinct, poorly attested; possibly an isolate "Latn", } m["sai-gay"] = { "Gayón", 5528902, "sai-jir", "Latn", } m["sai-gmo"] = { "Guamo", 5613495, "qfa-unc", -- extinct; "Kaufman (1990) finds a connection with the Chapacuran languages convincing." [Wikipedia] Considered an isolate by Campbell (2024). "Latn", } m["sai-gua"] = { "Guachí", 5613172, "sai-guc", "Latn", } m["sai-gue"] = { "Güenoa", 5626799, "sai-crn", "Latn", } m["sai-hau"] = { "Haush", 3128376, "sai-cho", "Latn", } m["sai-jee-pro"] = { "Proto-Jê", 116773212, "sai-jee", "Latn", type = "reconstructed", } m["sai-jko"] = { "Jeikó", 6176527, "sai-mje", "Latn", } m["sai-jrj"] = { "Jirajara", 6202966, "sai-jir", "Latn", } m["sai-kat"] = { -- contrast xoo, kzw, sai-xoc "Katembri", 6375925, "qfa-unc", -- extinct, poorly attested; "Kaufman (1990) has linked it with the nearly extinct Taruma, although this has not been accepted by other scholars." [Wikipedia] "Latn", } m["sai-mal"] = { "Malalí", 6741212, "sai-mje", -- considered the most divergent Maxakalían language (a subdivision of Macro-Jê), for which we have no entry "Latn", } m["sai-mar"] = { "Maratino", 6755055, "qfa-unc", -- extinct, poorly attested; possibly Uto-Aztecan "Latn", } m["sai-mat"] = { "Matanawi", 6786047, "qfa-unc", -- extinct; either an isolate or distantly related to the Muran languages; Campbell (2024) lists it as an isolate, Glottolog gives it as unclassified "Latn", } m["sai-mcn"] = { "Mocana", 3402048, "qfa-unc", -- extinct, poorly attested; given as part of the Malibu languages (geographic grouping; not a clade) "Latn", } m["sai-men"] = { "Menien", 16890110, "sai-mje", "Latn", } m["sai-mil"] = { "Millcayac", 19573012, "sai-hrp", "Latn", } m["sai-mlb"] = { "Malibu", 3402048, "qfa-unc", -- extinct, poorly attested; given as part of the Malibu languages (geographic grouping; not a clade) "Latn", } m["sai-msk"] = { "Masakará", 6782426, "sai-mje", "Latn", } m["sai-muc"] = { "Mucuchí", 6931290, nil, -- generally considered Timotean, for which we have no entry "Latn", } m["sai-mue"] = { "Muellama", 16886936, "sai-bar", "Latn", } m["sai-muz"] = { "Muzo", 6644203, "qfa-unc", -- extinct language of Colombia, poorly attested; may be Pijao (Cariban) "Latn", } m["sai-mys"] = { "Maynas", 16919393, "sai-cah", -- per Campbell (2024); formerly considered unclassified "Latn", } m["sai-nat"] = { "Natú", 9006749, "qfa-unc", -- extinct, poorly attested; "only Greenberg dares to classify [it]".[Wikipedia, quoting Moseley, Christopher; Asher, R. E.; Tait, Mary (1994), Atlas of the world's languages] "Latn", } m["sai-nje-pro"] = { "Proto-Northern Jê", 116773245, "sai-nje", "Latn", type = "reconstructed", } m["sai-opo"] = { "Opón", 7099152, "sai-car", "Latn", } m["sai-oto"] = { "Otomaco", 16879234, "sai-otm", "Latn", } m["sai-pal"] = { "Palta", 3042978, "qfa-unc", -- extinct, unclassified; possibly Chicham "Latn", } m["sai-pam"] = { "Pamigua", 5908689, "sai-otm", "Latn", } m["sai-par"] = { "Paratió", 16890038, "qfa-unc", -- extinct, poorly attested; possibly Xukuruan "Latn", } m["sai-peb"] = { "Peba", 3373890, "sai-pey", "Latn", } m["sai-pnz"] = { "Panzaleo", 3123275, "qfa-unc", -- extinct, unclassified; possibly Paezan "Latn", } m["sai-prh"] = { "Puruhá", 3410994, "qfa-unc", -- extinct, poorly attested; possibly in a famil with Cañari "Latn", } m["sai-ptg"] = { "Patagón", 128807870, "sai-tar", -- extinct, only known from 4 words, which suggest Cariban lineage (Campbell 2024) "Latn", } m["sai-pur"] = { "Purukotó", 7261622, "sai-pem", "Latn", } m["sai-pyg"] = { "Payaguá", 7156643, "sai-guc", "Latn", } m["sai-pyk"] = { "Pykobjê", 98113977, "sai-nje", "Latn", } m["sai-qmb"] = { "Quimbaya", 7272043, "qfa-unc", -- extinct, might not exist; few known words "Latn", } m["sai-qtm"] = { "Quitemo", 7272651, "sai-cpc", "Latn", } m["sai-rab"] = { "Rabona", 6644203, "qfa-unc", -- extinct, poorly attested, mostly plant names; possibly Candoshi-Shapra "Latn", } m["sai-ram"] = { "Ramanos", 16902824, "qfa-unc", -- extinct, poorly attested, possibly an isolate; per Glottolog: "the minuscule wordlist ... shows no convincing resemblances to surrounding languages" "Latn", } m["sai-sac"] = { "Sácata", 5390321, "qfa-unc", -- extinct, only 3 words known; possibly Candoshí or Arawakan "Latn", } m["sai-san"] = { "Sanaviron", 16895999, "qfa-unc", -- extinct, unclassified; no consensus on classification "Latn", } m["sai-sap"] = { "Sapará", 7420922, "sai-car", "Latn", } m["sai-sec"] = { "Sechura", 7442912, "qfa-unc", -- extinct, poorly attested; possibly Catacaoan "Latn", } m["sai-sin"] = { "Sinúfana", 7525275, "qfa-unc", -- moribund, poorly attested; possibly Chocoan "Latn", } m["sai-sje-pro"] = { "Proto-Southern Jê", 116773814, "sai-sje", "Latn", type = "reconstructed", } m["sai-tab"] = { "Tabancale", 5390321, "qfa-unc", -- extinct, only 5 words known; no obvious connections, might be an isolate "Latn", } m["sai-tal"] = { "Tallán", 16910468, "qfa-unc", -- extinct, poorly attested; might be Catacaoan "Latn", } m["sai-tap"] = { "Tapayuna", 30719984, "sai-nje", "Latn", } m["sai-tar-pro"] = { "Proto-Taranoan", 116773816, "sai-tar", "Latn", type = "reconstructed", } m["sai-teu"] = { "Teushen", 3519243, "qfa-unc", -- probably extinct by the 1950's; possibly Chonan "Latn", } m["sai-tim"] = { "Timote", 7806995, nil, -- possibly in a small Timotean family "Latn", } m["sai-tpr"] = { "Taparita", 7684460, "sai-otm", "Latn", } m["sai-trr"] = { "Tarairiú", 7685313, "qfa-unc", -- extinct, too poorly attested to classify "Latn", } m["sai-wai"] = { "Waitaká", 16918610, "qfa-unc", -- extinct, possibly Purian "Latn", } m["sai-way"] = { "Wayumara", 7960726, "sai-car", "Latn", } m["sai-wit-pro"] = { "Proto-Witotoan", 116773823, "sai-wit", "Latn", type = "reconstructed", } m["sai-wnm"] = { "Wanham", 16879440, "sai-cpc", "Latn", } m["sai-xoc"] = { -- contrast xoo, kzw, sai-kat "Xocó", 12953620, "qfa-unc", -- extinct and poorly attested; not clear if one or three languages "Latn", } m["sai-yao"] = { "Yao (South America)", 16979655, "sai-ven", "Latn", } m["sai-yar"] = { -- not the same family as 'suy' "Yarumá", 3505859, "sai-pek", "Latn", } m["sai-yri"] = { "Yuri", 2669157, "sai-tyu", "Latn", } m["sai-yup"] = { "Yupua", 8061430, "sai-tuc", "Latn", } m["sai-yur"] = { "Yurumanguí", 1281291, "qfa-unc", -- extinct, too poorly attested to classify "Latn", } m["sal-pro"] = { "Proto-Salish", 116773269, "sal", "Latn", type = "reconstructed", } m["sdv-daj-pro"] = { "Proto-Daju", 116773739, "sdv-daj", "Latn", type = "reconstructed", } m["sdv-eje-pro"] = { "Proto-Eastern Jebel", 116773751, "sdv-eje", "Latn", type = "reconstructed", } m["sdv-nil-pro"] = { "Proto-Nilotic", 116773794, "sdv-nil", "Latn", type = "reconstructed", } m["sdv-nyi-pro"] = { "Proto-Nyima", 116773796, "sdv-nyi", "Latn", type = "reconstructed", } m["sdv-tmn-pro"] = { "Proto-Taman", 116773815, "sdv-tmn", "Latn", type = "reconstructed", } m["sel-nor"] = { "Northern Selkup", 30304565, "sel", "Cyrl", translit = "sel-nor-translit", } m["sel-pro"] = { "Proto-Selkup", 128884235, "sel", "Latn", type = "reconstructed", } m["sel-sou"] = { "Southern Selkup", 30304639, "sel", "Cyrl", translit = "sel-sou-translit", } m["sem-amm"] = { "Ammonite", 279181, "sem-can", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["sem-amo"] = { "Amorite", 35941, "sem-nwe", "Xsux, Latn", } m["sem-cha"] = { "Chaha", 35543, "sem-eth", "Ethi", translit = "Ethi-translit", } m["sem-dad"] = { "Dadanitic", 21838040, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-dum"] = { "Dumaitic", 128810397, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-has"] = { "Hasaitic", 3541433, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-his"] = { "Hismaic", 22948260, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-mhr"] = { "Muher", 33743, "sem-eth", "Latn", } m["sem-pro"] = { "Proto-Semitic", 1658554, "sem", "Latn", type = "reconstructed", } m["sem-saf"] = { "Safaitic", 472586, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-sam"] = { "Samalian", 85847147, "sem-nwe", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["sem-srb"] = { "Old South Arabian", 35025, "sem-osa", "Sarb", -- Sarb translit in [[Module:scripts/data]] } m["sem-tay"] = { "Taymanitic", 24912301, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-tha"] = { "Thamudic", 843030, "sem-cen", "Narb", -- Narb translit in [[Module:scripts/data]] } m["sem-wes-pro"] = { "Proto-West Semitic", 98021726, "sem-wes", "Latn", type = "reconstructed", } m["sio-pro"] = { -- NB this is not Proto-Siouan-Catawban 'nai-sca-pro' "Proto-Siouan", 34181, "sio", "Latn", type = "reconstructed", } m["sit-aao-pro"] = { "Proto-Central Naga", nil, "sit-aao", "Latn", type = "reconstructed", } m["sit-bai-pro"] = { "Proto-Bai", nil, "sit-bai", "Latn", type = "reconstructed", } m["sit-ban"] = { "Bangru", 56071779, "sit-hrs", "Latn", } m["sit-bdi-pro"] = { "Proto-Bodish", nil, "sit-bdi", "Latn", type = "reconstructed", } m["sit-bok"] = { "Bokar", 4938727, "sit-tan", "Latn, Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["sit-cai"] = { "Caijia", 5017528, "sit-cln", "Latn" } m["sit-cha"] = { "Chairel", 5068066, "sit-luu", "Latn", } m["sit-ers-pro"] = { "Proto-Ersuic", nil, "sit-ers", "Latn", type = "reconstructed", } m["sit-hrs-pro"] = { "Proto-Hrusish", 116773762, "sit-hrs", "Latn", type = "reconstructed", } m["sit-jap"] = { "Japhug", 3162245, "sit-egy", "Latn", } m["sit-kha-pro"] = { "Proto-Kham", 116773773, "sit-kha", "Latn", type = "reconstructed", } m["sit-khb-pro"] = { "Proto-Kho-Bwa", nil, "sit-khb", "Latn", type = "reconstructed", } m["sit-khp-pro"] = { "Proto-Puroik", nil, "sit-khb", "Latn", type = "reconstructed", } m["sit-khw-pro"] = { "Proto-Western Kho-Bwa", nil, "sit-khw", "Latn", type = "reconstructed", } m["sit-kon-pro"] = { "Proto-Northern Naga", nil, "sit-kon", "Latn", type = "reconstructed", } m["sit-liz"] = { "Lizu", 6660653, "sit-ers", "Latn", -- and Ersu Shaba } m["sit-lnj"] = { "Longjia", 17096251, "sit-cln", "Latn" } m["sit-lrn"] = { "Luren", 16946370, "sit-cln", "Latn" } m["sit-luu-pro"] = { "Proto-Luish", 116773783, "sit-luu", "Latn", type = "reconstructed", } m["sit-nas-pro"] = { "Proto-Naish", nil, "sit-nas", "Latn", type = "reconstructed", } m["sit-prn"] = { "Puiron", 7259048, "sit-zem", } m["sit-pro"] = { "Proto-Sino-Tibetan", 24839178, "sit", "Latn", type = "reconstructed", } m["sit-sit"] = { "Situ", 19840830, "sit-egy", "Latn", } m["sit-tam-pro"] = { "Proto-Tamangic", 117469295, "sit-tam", "Latn", type = "reconstructed", } m["sit-tan-pro"] = { "Proto-Tani", 116773284, "sit-tan", "Latn", -- needs verification type = "reconstructed", } m["sit-tgm"] = { "Tangam", 17041370, "sit-tan", "Latn", } m["sit-tng-pro"] = { "Proto-Tangkhulic", nil, "sit-tng", "Latn", type = "reconstructed" } m["sit-tos"] = { "Tosu", 7827899, "sit-ers", "Latn", -- also Ersu Shaba } m["sit-tsh"] = { "Tshobdun", 19840950, "sit-egy", "Latn", } m["sit-zbu"] = { "Zbu", 19841106, "sit-egy", "Latn", } m["sla-pro"] = { "Proto-Slavic", 747537, "sla", "Latn", type = "reconstructed", strip_diacritics = { remove_diacritics = c.grave .. c.acute .. c.tilde .. c.macron .. c.dgrave .. c.invbreve, remove_exceptions = {'ś'}, }, sort_key = { from = {"č", "ď", "ě", "ę", "ь", "ľ", "ň", "ǫ", "ř", "š", "ś", "ť", "ъ", "ž"}, to = {"c²", "d²", "e²", "e³", "i²", "l²", "nj", "o²", "r²", "s²", "s³", "t²", "u²", "z²"}, } } m["smi-pro"] = { "Proto-Samic", 7251862, "smi", "Latn", type = "reconstructed", sort_key = { from = {"ā", "č", "δ", "[ëē]", "ŋ", "ń", "ō", "š", "θ", "%([^()]+%)"}, to = {"a", "c²", "d", "e", "n²", "n³", "o", "s²", "t²"} }, } m["son-pro"] = { "Proto-Songhay", 116773277, "son", "Latn", type = "reconstructed", } m["sqj-pro"] = { "Proto-Albanian", 18210846, "sqj", "Latn", type = "reconstructed", } m["ssa-klk-pro"] = { "Proto-Kuliak", 116773779, "ssa-klk", "Latn", type = "reconstructed", } m["ssa-kom-pro"] = { "Proto-Koman", 116773775, "ssa-kom", "Latn", type = "reconstructed", } m["ssa-pro"] = { "Proto-Nilo-Saharan", 116773236, "ssa", "Latn", type = "reconstructed", } m["syd-pro"] = { "Proto-Samoyedic", 7251863, "syd", "Latn", type = "reconstructed", } m["tai-pro"] = { "Proto-Tai", 6583709, "tai", "Latn", type = "reconstructed", } m["tai-swe-pro"] = { "Proto-Southwestern Tai", 116773280, "tai-swe", "Latn", type = "reconstructed", } m["tbq-bdg-pro"] = { "Proto-Bodo-Garo", 116773195, "tbq-bdg", "Latn", type = "reconstructed", } m["tbq-blg"] = { "Bailang", 2879843, "tbq-lob", "Hani", sort_key = "Hani-sortkey", } m["tbq-brm-pro"] = { "Proto-Burmish", nil, "tbq-brm", "Latn", type = "reconstructed", } m["tbq-gkh"] = { "Gokhy", 5578069, "tbq-sil", "Latn", } m["tbq-kuk-pro"] = { "Proto-Kuki-Chin", 116773220, "tbq-kuk", "Latn", type = "reconstructed", } m["tbq-lal-pro"] = { "Proto-Lalo", 116773781, "tbq-lal", "Latn", type = "reconstructed", } m["tbq-laz"] = { "Laze", 17007626, "sit-nas", "Latn", } m["tbq-lob-pro"] = { "Proto-Lolo-Burmese", 116773224, "tbq-lob", "Latn", type = "reconstructed", } m["tbq-lol-pro"] = { "Proto-Loloish", 7251855, "tbq-lol", "Latn", type = "reconstructed", } m["tbq-mil"] = { "Milang", 6850761, "sit-gsi", "Deva, Latn", } m["tbq-mor"] = { "Moran", 6909216, "tbq-bdg", "Latn", } m["tbq-ngo"] = { "Ngochang", 56582, "tbq-brm", "Latn", } -- tbq-pro is now etymology-only m["trk-dkh"] = { "Dukhan", 12809273, "trk-ssb", "Latn, Cyrl, Mong", -- Mong translit, display_text and strip_diacritics in [[Module:scripts/data]] } -- As described in Mahmud al-Kashgari's 11th century ''Dīwān Lughāt al-Turk''. m["trk-eog"] = { "Early Old Oghuz", nil, "trk-ogz", "ota-Arab", strip_diacritics = {["ota-Arab"] = "ar-stripdiacritics"}, } m["trk-oat"] = { "Old Anatolian Turkish", 7083390, "trk-ogz", "ota-Arab", strip_diacritics = {["ota-Arab"] = "ar-stripdiacritics"}, ancestors = "trk-eog", } m["trk-pro"] = { "Proto-Turkic", 3657773, "trk", "Latn", type = "reconstructed", standard_chars = { Latn = " ()-abdegiklmnoprstuxyzïöüāčēīĺŋōŕšūǖȫẹ" .. c.macron, } } m["tup-gua-pro"] = { "Proto-Tupi-Guarani", 116773288, "tup-gua", "Latn", type = "reconstructed", } m["tup-kab"] = { "Kabishiana", 15302988, "tup", "Latn", } m["tup-pro"] = { "Proto-Tupian", 10354700, "tup", "Latn", type = "reconstructed", } m["tuw-alk"] = { "Altsuka", --TLCHANGE basing from https://en.wiktionary.org/wiki/%E9%98%BF%E5%8B%92%E6%A5%9A%E5%96%80 and https://en.wiktionary.org/wiki/%E1%A0%A0%E1%A0%AF%E1%A0%B4%E1%A1%A0%E1%A1%B4%E1%A0%A0#Manchu 113553616, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, english_name = "Alchuka", --TLCHANGE } m["tuw-bal"] = { "Bala", 86730632, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, } m["tuw-kkl"] = { "Kyakala", 118875708, "tuw-jrc", "Latn, Hans", sort_key = {Hans = "Hani-sortkey"}, } m["tuw-kli"] = { "Kili", 6406892, "tuw-ewe", "Cyrl", } m["tuw-pro"] = { "Proto-Tungusic", 85872335, "tuw", "Latn", type = "reconstructed", } m["tuw-sol"] = { "Solon", 30004, "tuw-ewe", } m["urj-fin-pro"] = { "Proto-Finnic", 11883720, "urj-fin", "Latn", type = "reconstructed", } m["urj-koo"] = { "Old Komi", 86679962, "kv", "Perm, Cyrs", translit = "urj-koo-translit", -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]]; previously, Cyrs strip_diacritics not present } m["urj-kuk"] = { "Kukkuzi", 107410460, "urj-fin", "Latn", ancestors = "vot", } m["urj-kya"] = { "Komi-Yazva", 2365210, "kv", "Cyrl", translit = "kv-translit", override_translit = true, strip_diacritics = {remove_diacritics = c.acute}, } m["urj-mdv-pro"] = { "Proto-Mordvinic", 116773232, "urj-mdv", "Latn", type = "reconstructed", } m["urj-prm-pro"] = { "Proto-Permic", 116773257, "urj-prm", "Latn", type = "reconstructed", } m["urj-pro"] = { "Proto-Uralic", 288765, "urj", "Latn", type = "reconstructed", } m["urj-ugr-pro"] = { "Proto-Ugric", 156631, "urj-ugr", "Latn", type = "reconstructed", } m["xnd-pro"] = { "Proto-Na-Dene", 116773233, "xnd", "Latn", type = "reconstructed", } m["xgn-pro"] = { "Proto-Mongolic", 2493677, "xgn", "Latn", type = "reconstructed", sort_key = { from = {"č", "i", "ï", "ǰ", "ŋ", "ö", "š", "ü"}, to = {"c", "i" .. p[1], "i", "j", "n" .. p[1], "o" .. p[1], "s" .. p[1], "u" .. p[1]}, }, } m["yok-bvy"] = { "Buena Vista Yokuts", 4985474, "yok", "Latn", } m["yok-dly"] = { "Delta Yokuts", 70923266, "yok", "Latn", } m["yok-gsy"] = { "Gashowu Yokuts", 3098708, "yok", "Latn", } m["yok-kry"] = { "Kings River Yokuts", 6413014, "yok", "Latn", } m["yok-nvy"] = { "Northern Valley Yokuts", 85789777, "yok", "Latn", } m["yok-ply"] = { "Palewyami Yokuts", 2387391, "yok", "Latn", } m["yok-svy"] = { "Southern Valley Yokuts", 12642473, "yok", "Latn", } m["yok-tky"] = { "Tule-Kaweah Yokuts", 7851988, "yok", "Latn", } m["ypk-pro"] = { "Proto-Yupik", 116773295, "ypk", "Latn", type = "reconstructed", } m["yrk-for"] = { "Forest Nenets", 1295107, "yrk", "Cyrl", translit = "yrk-for-translit", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.macron .. c.breve .. c.dotabove}, } m["yrk-tun"] = { "Tundra Nenets", 36452, "yrk", "Cyrl", strip_diacritics = { from = {"ӑ", "а̄", "э̇", "ӣ", "ы̄", "ӯ", "ю̄", "я̆", "я̄"}, to = {"а", "а", "э", "и", "ы", "у", "ю", "я", "я"}, }, translit = "yrk-tun-translit", } m["zhx-min-pro"] = { "Proto-Min", 19646347, "zhx-min", "Latn", type = "reconstructed", } m["zhx-sht"] = { "Shaozhou Tuhua", 1920769, "zhx", "Nshu, Hants", generate_forms = "zh-generateforms", sort_key = {Hani = "Hani-sortkey"}, } m["zhx-sic"] = { "Sitsuwanes", --TLCHANGE 2278732, "zhx-man", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", english_name = "Sichuanese", --TLCHANGE spanish_name = "Sichuanés", --TLCHANGE } m["zhx-tai"] = { "Toisanes", --TLCHANGE 2208940, "zhx-yue", "Hants", generate_forms = "zh-generateforms", translit = "zh-translit", sort_key = "Hani-sortkey", english_name = "Taishanese", --TLCHANGE spanish_name = "Toisanés", --TLCHANGE } m["zle-ono"] = { "Old Novgorodian", 162013, "zle", "Cyrs, Glag", translit = {Cyrs = "Cyrs-translit", Glag = "Glag-translit"}, -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]] } m["zle-ort"] = { "Old Ruthenian", 13211, "zle", "Arab, Cyrs, Latn", ancestors = "orv", translit = { Cyrs = "zle-ort-translit", Arab = "zle-ort-Arab-translit", }, strip_diacritics = { Cyrs = { remove_diacritics = m_langdata.chars_substitutions["Cyrs_remove_diacritics"], remove_exceptions = {"Ї", "ї"}, }, Arab = "ar-stripdiacritics", }, -- Cyrs sort_key in [[Module:scripts/data]] } m["zls-chs"] = { "Church Slavonic", 33251, "zls", "Cyrs, Glag, Latn", ancestors = "cu", translit = { Cyrs = "Cyrs-translit", Glag = "Glag-translit" }, -- Cyrs strip_diacritics, sort_key in [[Module:scripts/data]] } m["zlw-ocs"] = { "Lumang Tseko", --TLCHANGE 593096, "zlw", "Latn", english_name = "Old Czech", --TLCHANGE spanish_name = "Checo antiguo", --TLCHANGE } m["zlw-opl"] = { "Lumang Polako", --TLCHANGE 149838, "zlw-lch", "Latn", strip_diacritics = {remove_diacritics = c.ringabove}, english_name = "Old Polish", --TLCHANGE spanish_name = "Polaco antiguo", --TLCHANGE } m["zlw-osk"] = { "Lumang Eslovako", --TLCHANGE 12776676, "zlw", "Latn", english_name = "Old Slovak", --TLCHANGE spanish_name = "Eslovaco antiguo", --TLCHANGE } m["zlw-slv"] = { "Slovincian", 36822, "zlw-pom", "Latn", strip_diacritics = {remove_diacritics = c.macron .. c.breve}, } return require("Module:languages").finalizeData(m, "language") j1oeo4zzlgwjm9tciraz0tamio01l4s Module:languages/data/3/e 828 32642 178458 177989 2026-10-27T01:45:32Z GinawaSaHapon 3989 178458 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["ebg"] = { "Ebughu", 35294, "nic-lcr", "Latn", } m["ebk"] = { "Finallig", --"Eastern Bontoc", 62664215, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/finallig/", --TLCHANGE english_name = "Eastern Bontoc", --TLCHANGE } m["ebr"] = { "Ebrié", 36644, "alv-ptn", "Latn", } m["ebu"] = { "Embu", 35318, "bnt-kka", "Latn", } m["ecr"] = { "Eteokretense", --TLCHANGE 35461, "qfa-unc", "Polyt", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] english_name = "Eteocretan", --TLCHNAGE spanish_name = "Eteocretense", --TLCHANGE } m["ecs"] = { "Ecuadorian Sign Language", 3436769, "sgn", "Latn", -- when documented } m["ecy"] = { "Eteotsipriyota", --TLCHANGE 35309, "qfa-unc", "Cprt", english_name = "Eteocypriot", --TLCHANGE spanish_name = "Eteochipriota", --TLCHANGE } m["eee"] = { "E", 35386, "qfa-mix", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["efa"] = { "Efai", 3813297, "nic-ief", "Latn", } m["efe"] = { "Efe", 56354, "csu-mle", "Latn", } m["efi"] = { "Efik", 35377, "nic-ief", "Latn", } m["ega"] = { "Ega", 3914927, "alv", "Latn", } m["egl"] = { "Emilyano", --TLCHANGE 1057898, "roa-emr", ancestors = "egl-old", "Latn", wikimedia_codes = "eml", english_name = "Emilian", --TLCHANGE spanish_name = "Emiliano", --TLCHANGE } m["ego"] = { "Eggon", 35300, "nic-pls", "Latn", } m["egy"] = { "Ehipsiyo", --TLCHANGE 50868, "egx", "Latn, Egyp, Egyh", sort_key = { remove_diacritics = "'%-%s", from = {"ꜣ", "j", "y", "ꜥ", "w", "b", "p", "f", "m", "n", "r", "ḥ", "ḫ", "ẖ", "h", "z", "š", "s", "q", "k", "g", "ṯ", "t", "ḏ", "d", "%."}, to = {p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[13], p[14], p[15], p[12], p[16], p[18], p[17], p[19], p[20], p[21], p[23], p[22], p[25], p[24], p[26]} }, english_name = "Egyptian", --TLCHANGE spanish_name = "Egipcio", --TLCHANGE } m["ehu"] = { "Ehueun", 3441392, "alv-nwd", "Latn", } m["eip"] = { "Eipomek", 5349839, "ngf-mek", "Latn", } m["eit"] = { "Eitiep", 5350030, "paa-kom", "Latn", } m["eiv"] = { "Askopan", 56324, "paa-nbo", "Latn", } m["eja"] = { "Ejamat", 6269820, "alv-jfe", "Latn", } m["eka"] = { "Ekajuk", 35250, "nic-eko", "Latn", } m["eke"] = { "Ekit", 3509628, "nic-ief", "Latn", } m["ekg"] = { "Ekari", 5350305, "ngf-pan", "Latn", } m["eki"] = { "Eki", 5350418, "nic-ief", "Latn", } m["ekl"] = { "Kolhe", 6426945, "mun", "Latn", } m["ekm"] = { "Elip", 12952414, "nic-ymb", "Latn", } m["eko"] = { "Koti", 29930, "bnt-mak", "Latn", } m["ekp"] = { "Ekpeye", 35254, "alv-igb", "Latn", } m["ekr"] = { "Yace", 36901, "alv-ido", "Latn", } m["eky"] = { "Eastern Kayah", 25559417, "kar", "Kali", } m["ele"] = { "Elepi", 5359444, "paa-mar", "Latn", } m["elh"] = { "El Hugeirat", 5351410, "nub-hil", "Latn", } m["eli"] = { "Nding", 36176, "alv-tal", "Latn", } m["elk"] = { "Elkei", 5364210, "paa-wap", "Latn", } m["elm"] = { "Eleme", 3914427, "nic-ogo", "Latn", } m["elo"] = { "El Molo", 56719, "cus-eas", "Latn", } m["elu"] = { "Elu", 3364594, "poz-aay", "Latn", } m["elx"] = { "Elamita", --TLCHANGE 35470, "qfa-iso", --ancient language of Iran "Xsux", english_name = "Elamite", --TLCHANGE spanish_name = "Elamita", --TLCHANGE } m["ema"] = { "Emai", 35428, "alv-eeo", "Latn", } m["emb"] = { "Embaloh", 5369424, "poz", "Latn", } m["eme"] = { "Emerillon", 3588942, "tup-gua", "Latn", } m["emg"] = { "Eastern Meohang", 12952840, "sit-kie", "Deva", } m["emi"] = { "Mussau-Emira", 6943093, "poz-stm", "Latn", } m["emk"] = { "Eastern Maninkakan", 11002130, "dmn-mnk", "Latn, Arab, Nkoo", } m["emm"] = { "Mamulique", 3285082, "nai-pak", "Latn", } m["emn"] = { "Eman", 5368975, "nic-tvc", "Latn", } m["emp"] = { "Northern Emberá", 2391297, "sai-chc", "Latn", } m["ems"] = { "Alutiiq", 27992, "ypk", "Latn", } m["emu"] = { "Eastern Muria", 12952883, "dra-mur", "Deva", } m["emw"] = { "Emplawas", 5374265, "poz-tim", "Latn", } m["emx"] = { "Erromintxela", 1122188, "qfa-mix", "Latn", ancestors = "rom, eu", } m["emy"] = { "Epigraphic Mayan", 301355, "myn", "Latn, Maya", } m["ena"] = { "Apali", 3504201, "ngf-sog", "Latn", } m["enb"] = { "Markweeta", 56874, "sdv-nma", "Latn", } m["enc"] = { "En", 3504110, "qfa-buy", "Latn", } m["end"] = { "Ende", 2067656, "poz-cet", "Latn", } m["enf"] = { "Forest Enets", 30249597, "syd-ene", "Cyrl", } m["enh"] = { "Tundra Enets", 25559411, "syd-ene", "Cyrl", } m["enl"] = { "Enlhet", 15462671, "sai-mas", "Latn", } m["enm"] = { "Gitnang Ingles", --TLCHANGE 36395, "gmw-ang", "Latn", strip_diacritics = {remove_diacritics = c.acute .. c.circ .. c.macron .. c.breve .. c.dotabove .. c.diaer .. c.dacute .. c.dotbelow .. c.tacute}, sort_key = { remove_diacritics = c.acute .. c.circ .. c.macron .. c.breve .. c.dotabove .. c.diaer .. c.dacute .. c.dotbelow .. c.tacute, from = {"[ꟓꟕ]", "[æðᵹꟑȝœẜþꟃƿ]"}, to = { { ["ꟓ"] = "þþ", ["ꟕ"] = "ƿƿ", -- finalized by the next substitution }, { ["æ"] = "ae", ["ð"] = "d" .. p[1], ["ᵹ"] = "g", ["ꟑ"] = "g", ["ȝ"] = "g" .. p[1], ["œ"] = "oe", ["ẜ"] = "s", ["þ"] = "t" .. p[1], ["ꟃ"] = "w", ["ƿ"] = "w", }, }, }, standard_chars = { Latn = "AaÆæBbCcDdÐðEeFfGgȜȝHhIiJjKkLlMmNnOoPpQqRrSsTtÞþUuVvWwXxYyZz", c.punc, }, english_name = "Middle English", --TLCHANGE spanish_name = "Ingles medio", --TLCHANGE } m["enn"] = { "Engenni", 3915365, "alv-dlt", "Latn", } m["eno"] = { "Enggano", 2669164, "poz", "Latn", } m["enq"] = { "Enga", 1143040, "ngf-enc", "Latn", } m["enr"] = { "Emem", 5370369, "paa-epw", "Latn", } m["enu"] = { "Enu", 5380858, "tbq-bka", } m["env"] = { "Enwan", 3438334, "alv-yek", "Latn", } m["enw"] = { "Enwang", 11134434, "nic-lcr", "Latn", } m["enx"] = { "Enxet", 15462609, "sai-mas", "Latn", } m["eot"] = { "Eotile", 3915347, "alv-ptn", "Latn", } m["epi"] = { "Epie", 35291, "alv-dlt", "Latn", } m["era"] = { "Eravallan", 5385061, "dra-tam", "Taml", } m["erg"] = { "Sie", 426254, "poz-vns", "Latn", } m["erh"] = { "Eruwa", 3441244, "alv-swd", "Latn", } m["eri"] = { "Ogea", 7079984, "ngf-nur", "Latn", } m["erk"] = { "South Efate", 3449070, "poz-vnc", "Latn", } m["err"] = { "Erre", 10488401, "qfa-iso", -- Evans (1997) put it in an Arnhem Land family "Latn", } m["ers"] = { "Ersu", 12952417, "sit-ers", "Latn", -- also Ersu Shaba } m["ert"] = { "Eritai", 56376, "paa-clp", "Latn", } m["erw"] = { "Erokwanas", 5395296, "poz-hce", "Latn", } m["ese"] = { "Ese Ejja", 2980381, "sai-tac", "Latn", } m["esh"] = { "Eshtehardi", 12952418, "xme-ttc", "fa-Arab, Latn", ancestors = "xme-ttc-sou", } -- "esi" and "esk" moved to etymology-only per [[WT:LT]] and [[Wiktionary:Beer_parlour/2023/August#Issues_regarding_the_Inuit_languages]] m["esl"] = { "Egyptian Sign Language", 5348443, "sgn", } m["esm"] = { "Esuma", 16927555, "alv-kwa", "Latn", } m["esn"] = { "Salvadoran Sign Language", 7406492, "sgn", "Latn", -- when documented } m["eso"] = { "Estonian Sign Language", 3196221, "sgn", "Latn", -- when documented } m["esq"] = { "Esselen", 1294243, "qfa-dis", -- isolate or Hokan "Latn", } m["ess"] = { "Central Siberian Yupik", 27993, "ypk", "Cyrl, Latn", } m["esu"] = { "Yup'ik", 21117, "ypk", "Latn", } m["esy"] = { "Eskayan", 867086, "art", "Latn", -- also its own native script } m["etb"] = { "Etebi", 11002851, "nic-ief", "Latn", } m["etc"] = { "Etchemin", 5402493, "alg-eas", "Latn", } m["eth"] = { "Ethiopian Sign Language", 3501903, "sgn", } m["etn"] = { "Eton (Vanuatu)", 3059362, "poz-vnc", "Latn", } m["eto"] = { "Eton (Cameroon)", 35317, "bnt-btb", "Latn", } m["etr"] = { "Edolo", 5340184, "ngf-bos", "Latn", } m["ets"] = { "Yekhee", 3915848, "alv-yek", "Latn", } m["ett"] = { "Etruscan", 35726, "qfa-tyn", "Ital", -- Ital translit in [[Module:scripts/data]] } m["etu"] = { "Ejagham", 35296, "nic-eko", "Latn", } m["etx"] = { "Eten", 3915392, "nic-beo", "Latn", } m["etz"] = { "Semimi", 10950308, "paa-mai", "Latn", } m["eve"] = { "Even", 29960, "tuw-ewe", "Cyrl, Latn", translit = {Cyrl = "eve-translit"}, strip_diacritics = {remove_diacritics = c.macron .. c.dotabove .. c.dotbelow}, sort_key = { Cyrl = { from = { "ӫ", -- 2 chars "ё", "ӈ", "ө" -- 1 char }, to = { "о" .. p[2], "е" .. p[1], "н" .. p[1], "о" .. p[1] }, }, }, } m["evh"] = { "Uvbie", 3441344, "alv-swd", "Latn", } m["evn"] = { "Evenki", 30004, "tuw-ewe", "Cyrl", translit = "evn-translit", strip_diacritics = {remove_diacritics = c.macron .. c.dotabove .. c.dotbelow}, sort_key = { from = {"ё", "ӈ"}, to = {"е" .. p[1], "н" .. p[1]} }, } m["ewo"] = { "Ewondo", 35459, "bnt-btb", "Latn", } m["ext"] = { "Ekstremenyo", --TLCHANGE 30007, "roa-asl", "Latn", english_name = "Extremaduran", --TLCHANGE spanish_name = "Extremeño", --TLCHANGE } m["eya"] = { "Eyak", 27480, "xnd", "Latn", } m["eyo"] = { "Keiyo", 56856, "sdv-nma", "Latn", } m["eza"] = { "Ezaa", 11921436, "alv-igb", "Latn", ancestors = "izi", } m["eze"] = { "Uzekwe", 3502244, "nic-ucn", "Latn", } return require("Module:languages").finalizeData(m, "language") cj1c5khr16qftok6xtkxh50wk1lz6jp Module:languages/data/3/f 828 32643 178462 178271 2026-10-27T02:07:42Z GinawaSaHapon 3989 178462 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["faa"] = { "Fasu", 3446687, "qfa-dis", -- Papuan; isolate or in the proposed Kutubuan family "Latn", } m["fab"] = { "Annobonese", 34992, "crp", "Latn", ancestors = "pt", } m["fad"] = { "Wagi", 7959569, "ngf-han", "Latn", } m["faf"] = { "Fagani", 3063759, "poz-sls", "Latn", } m["fag"] = { "Finongan", 3450761, "ngf-era", "Latn", } m["fah"] = { "Baissa Fali", 3446632, "nic-bco", "Latn", } m["fai"] = { "Faiwol", 3501773, "ngf-mok", "Latn", } m["faj"] = { "Kursav", 976953, "ngf-eso", "Latn", } m["fak"] = { "Fang (Beboid)", 5433811, "nic-beb", "Latn", } m["fal"] = { "Timog Fali", --TLCHANGE 15637351, "alv-fli", "Latn", english_name = "South Fali", --TLCHANGE } m["fam"] = { "Fam", 35290, "nic-mmb", "Latn", } m["fan"] = { "Fang (Bantu)", 33484, "bnt-btb", "Latn", } m["fap"] = { "Palor", 36318, "alv-cng", "Latn", } m["far"] = { "Fataleka", 3067168, "poz-sls", "Latn", } -- "fat" is treated as "ak", see [[WT:LT]] m["fau"] = { "Fayu", 5439113, "paa-wlp", "Latn", } m["fax"] = { "Fala", 300402, "roa-gap", "Latn", } m["fay"] = { "Southwestern Fars", 5228140, "ira-swi", "Arab", } m["faz"] = { "Northwestern Fars", 7060307, "ira-swi", } m["fbl"] = { "Bikolano ng Kanlurang Albay", --TLCHANGE 18603801, "phi", "Latn", english_name = "West Albay Bikol", --TLCHANGE } m["fcs"] = { "Wikang Senyas ng Quebec", --TLCHANGE 13193, "sgn", "Latn", -- when documented english_name = "Quebec Sign Language", --TLCHANGE spanish_name = "Lengua de signos quebequés", --TLCHANGE } m["fer"] = { "Feroge", 35287, "nic-ser", "Latn", } m["ffi"] = { "Foia Foia", 8564176, "paa-wig", "Latn", } -- "ffm" is treated as "ff", see [[WT:LT]] m["fgr"] = { "Fongoro", 3437645, "csu", "Latn", } m["fia"] = { "Nobiin", 36503, "nub", "Latn, Arab, Copt", ancestors = "onw", translit = { Copt = "Copt-translit", }, sort_key = { Copt = "Copt-sortkey", }, } m["fie"] = { "Fyer", 56273, "cdc-wst", "Latn", } m["fif"] = { "Faifi", 85760309, "sem-cen", -- conservatively putting undifferentiated sem-cen, there's debate over if it's OSA or Arabic "Arab", -- or IPA/Latn; mostly it is unwritten -- ancestors = "sem-srb", if one accepts the view that like Razihi it is sem-osa } -- "fil" is treated as "tl", see [[WT:LT]] m["fip"] = { "Fipa", 667747, "bnt-mwi", "Latn", } m["fir"] = { "Firan", 3915847, "nic-plc", "Latn", } m["fit"] = { "Meänkieli", 13357, "urj-fin", "Latn", ancestors = "fi", } m["fiw"] = { "Fiwaga", 5456292, "ngf-eku", "Latn", } m["fkk"] = { "Kirya-Konzel", 6416310, "cdc-cbm", "Latn", } m["fkv"] = { "Kven", 165795, "urj-fin", "Latn", ancestors = "fi", } m["fla"] = { "Montana Salish", 3111983, "sal", "Latn", } m["flh"] = { "Foau", 5463819, "paa-elp", "Latn", } m["fli"] = { "Fali", 56244, "cdc-cbm", "Latn", } m["fll"] = { "Hilagang Fali", --TLCHANGE 12952419, "alv-fli", "Latn", english_name = "North Fali", --TLCHANGE } m["fln"] = { "Flinders Island", 3915702, "aus-pmn", "Latn", } m["flr"] = { "Fuliiru", 7166821, "bnt-shh", "Latn", } m["fly"] = { "Tsotsitaal", 12643960, "crp", "Latn", ancestors = "af", } m["fmp"] = { "Fe'fe'", 35276, "bai", "Latn", } m["fmu"] = { "Far Western Muria", 42589412, "dra-mur", "Deva", } m["fng"] = { "Fanagalo", 35727, "crp", "Latn", ancestors = "zu", } m["fni"] = { "Fania", 317642, "alv-bua", "Latn", } m["fod"] = { "Foodo", 5465566, "alv-gng", "Latn", } m["foi"] = { "Foi", 5464146, "ngf-eku", "Latn", } m["fom"] = { "Foma", 5464911, "bnt-ske", "Latn", ancestors = "khy", } m["fon"] = { "Fon", 33291, "alv-gbe", "Latn", } m["for"] = { "Fore", 3077126, "ngf-fgi", "Latn", } m["fos"] = { "Siraya", 716604, "map", "Latn", } m["fpe"] = { "Pichinglis", 35288, "crp", "Latn", ancestors = "en", } m["fqs"] = { "Fas", 56320, "paa-fas", "Latn", } -- "frc" is treated as "fr" (or as etymology-only), see [[WT:LT]] m["frd"] = { "Fordata", 5468035, "poz-cet", "Latn", } m["frm"] = { "Gitnang Pranses", --TLCHANGE 1473289, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], english_name = "Middle French", --TLCHANGE spanish_name = "Francés medio", --TLCHANGE } m["fro"] = { "Lumang Pranses", --TLCHANGE 35222, "roa-oil", "Latn, Hebr", sort_key = { Latn = s["roa-oil-sortkey"], }, -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] english_name = "Old French", --TLCHANGE spanish_name = "Francés antiguo", --TLCHANGE } m["frp"] = { "Pranko-Provensal", --TLCHANGE 15087, "roa-grh", "Latn", ancestors = "frp-old", sort_key = { remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer .. c.cedilla .. "'", from = {"æ", "œ"}, to = {"ae", "oe"} }, english_name = "Franco-Provençal", --TLCHANGE spanish_name = "Franco-provenzal", --TLCHANGE } m["frq"] = { "Forak", 5467173, "ngf-war", "Latn", } m["frr"] = { "North Frisian", 28224, "gmw-fri", "Latn", } -- "frs" is not used, see [[WT:LT]] m["frt"] = { "Fortsenal", 2666835, "poz-vnn", "Latn", } m["fse"] = { "Wikang Senyas ng Pinlandes", --TLCHANGE 33225, "sgn", "Latn", -- when documented english_name = "Finnish Sign Language", --TLCHANGE } m["fsl"] = { "Wikang Senyas ng Pranses", --TLCHANGE 33302, "sgn-fsl", "Latn", -- when documented english_name = "French Sign Language", --TLCHANGE } m["fss"] = { "Wikang Senyas ng Pinlandes-Suweko", --TLCHANGE 5450448, "sgn", "Latn", -- when documented english_name = "Finnish-Swedish Sign Language", --TLCHANGE } -- "fub" is treated as "ff", see [[WT:LT]] -- "fuc" is treated as "ff", see [[WT:LT]] m["fud"] = { "East Futuna", 35334, "poz-pnp", "Latn", } -- "fue" is treated as "ff", see [[WT:LT]] -- "fuf" is treated as "ff", see [[WT:LT]] -- "fuh" is treated as "ff", see [[WT:LT]] -- "fui" is treated as "ff", see [[WT:LT]] m["fuj"] = { "Ko", 35693, "alv-hei", "Latn", } m["fum"] = { "Fum", 11011870, "nic-nka", "Latn", } m["fun"] = { "Fulniô", 774441, "qfa-iso", "Latn", } -- "fuq" is treated as "ff", see [[WT:LT]] m["fur"] = { "Priyulano", 33441, "roa-rhe", ancestors = "fur-old", "Latn", } m["fut"] = { "Futuna-Aniwa", 3064409, "poz-pnp", "Latn", } m["fuu"] = { "Furu", 3441160, "csu-bkr", "Latn", } -- "fuv" is treated as "ff", see [[WT:LT]] m["fuy"] = { "Fuyug", 3073472, "qfa-dis", -- Papuan; isolate per Glottolog and Usher (2020), only tentatively retained in putative Goilalan family -- within TNG by Ross (2005) "Latn", } m["fvr"] = { "Fur", 33364, "ssa-fur", "Latn", } m["fwa"] = { "Fwâi", 3091331, "poz-cln", "Latn", } m["fwe"] = { "Fwe", 5511159, "bnt-bot", "Latn", } return require("Module:languages").finalizeData(m, "language") tm6e8gdb7lyw010hs9br3s93ai81hxe 178463 178462 2026-10-27T02:08:48Z GinawaSaHapon 3989 178463 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["faa"] = { "Fasu", 3446687, "qfa-dis", -- Papuan; isolate or in the proposed Kutubuan family "Latn", } m["fab"] = { "Annobonese", 34992, "crp", "Latn", ancestors = "pt", } m["fad"] = { "Wagi", 7959569, "ngf-han", "Latn", } m["faf"] = { "Fagani", 3063759, "poz-sls", "Latn", } m["fag"] = { "Finongan", 3450761, "ngf-era", "Latn", } m["fah"] = { "Baissa Fali", 3446632, "nic-bco", "Latn", } m["fai"] = { "Faiwol", 3501773, "ngf-mok", "Latn", } m["faj"] = { "Kursav", 976953, "ngf-eso", "Latn", } m["fak"] = { "Fang (Beboid)", 5433811, "nic-beb", "Latn", } m["fal"] = { "Timog Fali", --TLCHANGE 15637351, "alv-fli", "Latn", english_name = "South Fali", --TLCHANGE } m["fam"] = { "Fam", 35290, "nic-mmb", "Latn", } m["fan"] = { "Fang (Bantu)", 33484, "bnt-btb", "Latn", } m["fap"] = { "Palor", 36318, "alv-cng", "Latn", } m["far"] = { "Fataleka", 3067168, "poz-sls", "Latn", } -- "fat" is treated as "ak", see [[WT:LT]] m["fau"] = { "Fayu", 5439113, "paa-wlp", "Latn", } m["fax"] = { "Fala", 300402, "roa-gap", "Latn", } m["fay"] = { "Southwestern Fars", 5228140, "ira-swi", "Arab", } m["faz"] = { "Northwestern Fars", 7060307, "ira-swi", } m["fbl"] = { "Bikolano ng Kanlurang Albay", --TLCHANGE 18603801, "phi", "Latn", english_name = "West Albay Bikol", --TLCHANGE } m["fcs"] = { "Wikang Senyas ng Quebec", --TLCHANGE 13193, "sgn", "Latn", -- when documented english_name = "Quebec Sign Language", --TLCHANGE spanish_name = "Lengua de signos quebequés", --TLCHANGE } m["fer"] = { "Feroge", 35287, "nic-ser", "Latn", } m["ffi"] = { "Foia Foia", 8564176, "paa-wig", "Latn", } -- "ffm" is treated as "ff", see [[WT:LT]] m["fgr"] = { "Fongoro", 3437645, "csu", "Latn", } m["fia"] = { "Nobiin", 36503, "nub", "Latn, Arab, Copt", ancestors = "onw", translit = { Copt = "Copt-translit", }, sort_key = { Copt = "Copt-sortkey", }, } m["fie"] = { "Fyer", 56273, "cdc-wst", "Latn", } m["fif"] = { "Faifi", 85760309, "sem-cen", -- conservatively putting undifferentiated sem-cen, there's debate over if it's OSA or Arabic "Arab", -- or IPA/Latn; mostly it is unwritten -- ancestors = "sem-srb", if one accepts the view that like Razihi it is sem-osa } -- "fil" is treated as "tl", see [[WT:LT]] m["fip"] = { "Fipa", 667747, "bnt-mwi", "Latn", } m["fir"] = { "Firan", 3915847, "nic-plc", "Latn", } m["fit"] = { "Meänkieli", 13357, "urj-fin", "Latn", ancestors = "fi", } m["fiw"] = { "Fiwaga", 5456292, "ngf-eku", "Latn", } m["fkk"] = { "Kirya-Konzel", 6416310, "cdc-cbm", "Latn", } m["fkv"] = { "Kven", 165795, "urj-fin", "Latn", ancestors = "fi", } m["fla"] = { "Montana Salish", 3111983, "sal", "Latn", } m["flh"] = { "Foau", 5463819, "paa-elp", "Latn", } m["fli"] = { "Fali", 56244, "cdc-cbm", "Latn", } m["fll"] = { "Hilagang Fali", --TLCHANGE 12952419, "alv-fli", "Latn", english_name = "North Fali", --TLCHANGE } m["fln"] = { "Flinders Island", 3915702, "aus-pmn", "Latn", } m["flr"] = { "Fuliiru", 7166821, "bnt-shh", "Latn", } m["fly"] = { "Tsotsitaal", 12643960, "crp", "Latn", ancestors = "af", } m["fmp"] = { "Fe'fe'", 35276, "bai", "Latn", } m["fmu"] = { "Far Western Muria", 42589412, "dra-mur", "Deva", } m["fng"] = { "Fanagalo", 35727, "crp", "Latn", ancestors = "zu", } m["fni"] = { "Fania", 317642, "alv-bua", "Latn", } m["fod"] = { "Foodo", 5465566, "alv-gng", "Latn", } m["foi"] = { "Foi", 5464146, "ngf-eku", "Latn", } m["fom"] = { "Foma", 5464911, "bnt-ske", "Latn", ancestors = "khy", } m["fon"] = { "Fon", 33291, "alv-gbe", "Latn", } m["for"] = { "Fore", 3077126, "ngf-fgi", "Latn", } m["fos"] = { "Siraya", 716604, "map", "Latn", } m["fpe"] = { "Pichinglis", 35288, "crp", "Latn", ancestors = "en", } m["fqs"] = { "Fas", 56320, "paa-fas", "Latn", } -- "frc" is treated as "fr" (or as etymology-only), see [[WT:LT]] m["frd"] = { "Fordata", 5468035, "poz-cet", "Latn", } m["frm"] = { "Gitnang Pranses", --TLCHANGE 1473289, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], english_name = "Middle French", --TLCHANGE spanish_name = "Francés medio", --TLCHANGE } m["fro"] = { "Lumang Pranses", --TLCHANGE 35222, "roa-oil", "Latn, Hebr", sort_key = { Latn = s["roa-oil-sortkey"], }, -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] english_name = "Old French", --TLCHANGE spanish_name = "Francés antiguo", --TLCHANGE } m["frp"] = { "Prangko-Probensal", --TLCHANGE 15087, "roa-grh", "Latn", ancestors = "frp-old", sort_key = { remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer .. c.cedilla .. "'", from = {"æ", "œ"}, to = {"ae", "oe"} }, english_name = "Franco-Provençal", --TLCHANGE spanish_name = "Franco-provenzal", --TLCHANGE } m["frq"] = { "Forak", 5467173, "ngf-war", "Latn", } m["frr"] = { "North Frisian", 28224, "gmw-fri", "Latn", } -- "frs" is not used, see [[WT:LT]] m["frt"] = { "Fortsenal", 2666835, "poz-vnn", "Latn", } m["fse"] = { "Wikang Senyas ng Pinlandes", --TLCHANGE 33225, "sgn", "Latn", -- when documented english_name = "Finnish Sign Language", --TLCHANGE } m["fsl"] = { "Wikang Senyas ng Pranses", --TLCHANGE 33302, "sgn-fsl", "Latn", -- when documented english_name = "French Sign Language", --TLCHANGE } m["fss"] = { "Wikang Senyas ng Pinlandes-Suweko", --TLCHANGE 5450448, "sgn", "Latn", -- when documented english_name = "Finnish-Swedish Sign Language", --TLCHANGE } -- "fub" is treated as "ff", see [[WT:LT]] -- "fuc" is treated as "ff", see [[WT:LT]] m["fud"] = { "East Futuna", 35334, "poz-pnp", "Latn", } -- "fue" is treated as "ff", see [[WT:LT]] -- "fuf" is treated as "ff", see [[WT:LT]] -- "fuh" is treated as "ff", see [[WT:LT]] -- "fui" is treated as "ff", see [[WT:LT]] m["fuj"] = { "Ko", 35693, "alv-hei", "Latn", } m["fum"] = { "Fum", 11011870, "nic-nka", "Latn", } m["fun"] = { "Fulniô", 774441, "qfa-iso", "Latn", } -- "fuq" is treated as "ff", see [[WT:LT]] m["fur"] = { "Priyulano", 33441, "roa-rhe", ancestors = "fur-old", "Latn", } m["fut"] = { "Futuna-Aniwa", 3064409, "poz-pnp", "Latn", } m["fuu"] = { "Furu", 3441160, "csu-bkr", "Latn", } -- "fuv" is treated as "ff", see [[WT:LT]] m["fuy"] = { "Fuyug", 3073472, "qfa-dis", -- Papuan; isolate per Glottolog and Usher (2020), only tentatively retained in putative Goilalan family -- within TNG by Ross (2005) "Latn", } m["fvr"] = { "Fur", 33364, "ssa-fur", "Latn", } m["fwa"] = { "Fwâi", 3091331, "poz-cln", "Latn", } m["fwe"] = { "Fwe", 5511159, "bnt-bot", "Latn", } return require("Module:languages").finalizeData(m, "language") az5x46ordtziryz9m1kuqgqsk8vbibv Module:languages/data/3/p 828 32645 178461 175663 2026-10-27T02:05:19Z GinawaSaHapon 3989 178461 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["pab"] = { "Pareci", 3504312, "awd", "Latn", } m["pac"] = { "Pacoh", 3441136, "mkh-kat", "Latn", } m["pad"] = { "Paumarí", 389827, "auf", "Latn", } m["pae"] = { "Pagibete", 7124357, "bnt-bta", "Latn", } m["paf"] = { "Paranawát", 12953806, "tup-gua", "Latn", } m["pag"] = { "Pangasinan", --"Pangasinan" 33879, "phi", "Latn, Tglg", strip_diacritics = { Latn = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer}, }, is_official_kwf_name = "https://kwfwikaatkultura.ph/pangasinan/", --TLCHANGE english_name = "Pangasinan", --TLCHANGE } m["pah"] = { "Tenharim", 10266010, "tup-gua", "Latn", } m["pai"] = { "Pe", 3914871, "nic-tar", "Latn", } m["pak"] = { "Parakanã", 12953804, "tup-gua", "Latn", } m["pal"] = { "Middle Persian", 32063, "ira-swi", "Latn, Phli, pal-Avst, Mani, Phlp, Phlv", -- Latn for translit; Phlv not in Unicode translit = { Phli = "Phli-translit", ["pal-Avst"] = "Avst-translit", -- Mani translit in [[Module:scripts/data]] }, ancestors = "peo", } m["pam"] = { "Kapampangan", --"Kapampangan", 36121, "phi", "Latn, Kulit", strip_diacritics = { Latn = {remove_diacritics = c.grave .. c.acute .. c.circ} }, standard_chars = { Latn = "AaBbDdEeGgHhIiKkLlMmNnOoPpRrSsTtUuWwYy", c.punc }, sort_key = { Latn = "tl-sortkey" }, is_official_kwf_name = "https://kwfwikaatkultura.ph/kapampangan/", --TLCHANGE english_name = "Kapampangan", } m["pao"] = { "Northern Paiute", 3360656, "azc-num", "Latn", } m["pap"] = { "Papyamento", --TLCHANGE 33856, "crp", "Latn", ancestors = "pt", english_name = "Papiamentu", --TLCHANGE spanish_name = "Papiamento", --TLCHANGE } m["paq"] = { "Parya", 1135134, "inc-cen", } m["par"] = { "Panamint", 33926, "azc-num", "Latn", } m["pas"] = { "Papasena", 7132508, "paa-clp", "Latn", } m["pau"] = { "Palauan", 33776, "poz", "Latn, Kana", sort_key = { Kana = "Kana-sortkey" }, } m["pav"] = { "Wari'", 3027909, "sai-cpc", "Latn", } m["paw"] = { "Pawnee", 56751, "cdd", "Latn", strip_diacritics = {remove_diacritics = c.acute}, } m["pax"] = { "Pankararé", 25559779, nil, "Latn", } m["pay"] = { "Pech", 4898889, "cba", "Latn", } m["paz"] = { "Pankararú", 7131310, nil, "Latn", } m["pbb"] = { "Páez", 33677, nil, "Latn", } m["pbc"] = { "Patamona", 3915921, "sai-pem", "Latn", } m["pbe"] = { "Mezontla Popoloca", 42365630, "omq-pop", "Latn", } m["pbf"] = { "Coyotepec Popoloca", 5180100, "omq-pop", "Latn", } m["pbg"] = { "Paraujano", 3501747, "awd-taa", "Latn", } m["pbh"] = { "Panare", 56610, "sai-ven", "Latn", } m["pbi"] = { "Podoko", 3515096, "cdc-cbm", "Latn", } m["pbl"] = { "Mak (Nigeria)", 3915349, "alv-bwj", "Latn", } m["pbm"] = { "Puebla Mazatec", 31102530, "omq-maz", "Latn", } m["pbn"] = { "Kpasam", 3914902, "alv-mye", "Latn", } m["pbo"] = { "Papel", 36314, "alv-pap", "Latn", } m["pbp"] = { "Badyara", 35095, "alv-ten", "Latn", } m["pbr"] = { "Pangwa", 3847550, "bnt-bki", "Latn", } m["pbs"] = { "Central Pame", 3361763, "omq", "Latn", } m["pbv"] = { "Pnar", 3501850, "aav-pkl", "Latn", } m["pby"] = { "Pyu (New Guinea)", 2567925, "qfa-dis", -- Papuan; isolate per Glottolog, in a putative Arai-Samaia family in Usher (2020) "Latn", } m["pca"] = { "Santa Inés Ahuatempan Popoloca", 42365276, "omq-pop", "Latn", } m["pcb"] = { "Pear", 6583669, "mkh-pea", "Khmr", } m["pcc"] = { "Bouyei", 35100, "tai-nor", "Latn, Hani", sort_key = { Hani = "Hani-sortkey" }, } m["pcd"] = { "Picard", 34024, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["pce"] = { "Ruching Palaung", 12953798, "mkh-pal", "Mymr", } m["pcf"] = { "Paliyan", 7127643, "dra-tam", } m["pcg"] = { "Paniya", 7131211, "dra-mal", } m["pch"] = { "Pardhan", 7133207, "dra-gon", } m["pci"] = { "Duruwa", 56753, "dra-pgd", "Deva, Orya", } m["pcj"] = { "Parenga", 3111396, "mun", } m["pck"] = { "Paite", 12952337, "tbq-kuk", } m["pcl"] = { "Pardhi", 7136554, "inc-bhi", } m["pcm"] = { "Nigerian Pidgin", 33655, "crp", "Latn", ancestors = "en", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron .. c.macronbelow}, sort_key = { remove_diacritics = c.tilde, from = {"ẹ", "gb", "kp", "ọ", "sh", "zh"}, to = {"e" .. p[1], "g" .. p[1], "k" .. p[1], "o" .. p[1], "s" .. p[1], "z" .. p[1]} }, } m["pcn"] = { "Piti", 3913375, "nic-kne", "Latn", } m["pcp"] = { "Pacahuara", 2591165, "sai-pan", "Latn", } m["pcw"] = { "Pyapun", 3438807, nil, "Latn", } m["pda"] = { "Anam", 3501930, "ngf-pom", "Latn", } m["pdc"] = { "Pennsylvania German", 22711, "gmw-hgm", "Latn", ancestors = "gmw-rfr", } m["pdi"] = { "Pa Di", 3359940, nil, "Latn", } m["pdn"] = { "Fedan", 7206699, "poz-ocw", "Latn", } m["pdo"] = { "Padoe", 3360370, "poz-btk", "Latn", } m["pdt"] = { "Plautdietsch", 1751432, "gmw-lgm", "Latn", ancestors = "nds-de", } m["pdu"] = { "Kayan", 7123283, "kar", "Latn", } m["pea"] = { "Peranakan Indonesian", 653415, "crp", "Latn", ancestors = "ms", } m["peb"] = { "Eastern Pomo", 3396032, "nai-pom", "Latn", } m["ped"] = { "Mala (New Guinea)", 11732569, "ngf-kau", "Latn", } m["pee"] = { "Taje", 12953902, nil, "Latn", } m["pef"] = { "Northeastern Pomo", 3396018, "nai-pom", "Latn", } m["peg"] = { "Pengo", 56758, "dra-kki", "Orya", translit = "kxv-translit", } m["peh"] = { "Bonan", 32983, "xgn-shr", "Latn", } m["pei"] = { "Chichimeca-Jonaz", 3915427, "omq-otp", "Latn", } m["pej"] = { "Northern Pomo", 3396021, "nai-pom", "Latn", } m["pek"] = { "Penchal", 3374631, "poz-aay", "Latn", } m["pel"] = { "Pekal", 3241781, nil, "Latn", } m["pem"] = { "Phende", 7162372, "bnt-pen", "Latn", } m["peo"] = { "Old Persian", 35225, "ira-swi", "Xpeo, Latn", translit = "peo-translit", } m["pep"] = { "Kunja", 6444807, "paa-ton", "Latn", } m["peq"] = { "Southern Pomo", 3396023, "nai-pom", "Latn", } -- "pes" is treated as "fa" (or as etymology-only), see [[WT:LT]] m["pev"] = { "Pémono", 3439012, "sai-map", "Latn", } m["pex"] = { "Petats", 3376353, "poz-ocw", "Latn", } m["pey"] = { "Petjo", 940486, nil, "Latn", } m["pez"] = { "Eastern Penan", 18638342, "poz-swa", "Latn", } m["pfa"] = { "Pááfang", 3063517, "poz-mic", "Latn", } m["pfe"] = { "Peere", 36377, "alv-dur", "Latn", } m["pga"] = { "Juba Arabic", 1262143, "crp", "Latn", ancestors = "apd", } m["pgd"] = { "Gandhari", 3124623, "inc-mid", "Deva, Khar", ancestors = "inc-ash", translit = "Khar-translit", } m["pgg"] = { "Pangwali", 13600429, "him", "Deva, Takr", translit = "hi-translit", } m["pgi"] = { "Pagi", 7124354, "paa-bew", "Latn", } m["pgk"] = { "Rerep", 586907, "poz-vnc", "Latn", } m["pgl"] = { "Primitive Irish", 3320030, "cel-gae", "Ogam, Latn", translit = "pgl-translit", } m["pgn"] = { "Paelignian", 65455883, "itc-sbl", "Ital, Latn", -- Ital translit in [[Module:scripts/data]] display_text = { Latn = s["itc-Latn-displaytext"] }, strip_diacritics = { Latn = s["itc-Latn-stripdiacritics"] }, sort_key = { Latn = s["itc-Latn-sortkey"] }, } m["pgs"] = { "Pangseng", 3914027, "alv-mum", "Latn", } m["pgu"] = { "Pagu", 7124462, "paa-gto", "Latn", } m["pgz"] = { "Papua New Guinean Sign Language", 25044405, "sgn", } m["pha"] = { "Pa-Hng", 2625410, "hmn", } m["phd"] = { "Phudagi", 7188289, } m["phg"] = { "Phuong", 7188376, "mkh-kat", } m["phh"] = { "Phukha", 7188298, "tbq-phw", } m["phk"] = { "Phake", 7675798, "tai-swe", "Mymr", translit = "aio-phk-translit", display_text = s["phk-displaytext"], strip_diacritics = s["phk-stripdiacritics"], } m["phl"] = { "Palula", 2449549, "inc-dng", "Latn, ur-Arab", strip_diacritics = { -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه"; hamzatu l-waṣli to a regular alif from = {"هٔ", "ۂ", "ٱ"}, to = {"ہ", "ہ", "ا"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, } m["phm"] = { "Phimbi", 11007144, "bnt-sna", "Latn", } m["phn"] = { "Phoenician", 36734, "sem-can", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["pho"] = { "Phunoi", 7188361, "tbq-bis", } m["phq"] = { "Phana'", 7180427, "tbq-sil", } m["phr"] = { "Pahari-Potwari", 33739, "inc-pan", "pa-Arab, Guru", translit = { Guru = "Guru-translit", ["pa-Arab"] = "pa-Arab-translit", }, strip_diacritics = { ["pa-Arab"] = { remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna, from = {"ݨ", "ࣇ"}, to = {"ن", "ل"} }, } } m["pht"] = { "Phu Thai", 3626597, "tai-swe", "Thai", } m["phu"] = { "Phuan", 3915665, } m["phv"] = { "Pahlavani", 7124567, } m["phw"] = { "Phangduwali", 12953036, "sit-kie", ancestors = "ybh", } m["pia"] = { "Pima Bajo", 3388544, "azc-pim", "Latn", } m["pib"] = { "Yine", 3135432, "awd", "Latn", } m["pic"] = { "Pinji", 36296, "bnt-tso", "Latn", } m["pid"] = { "Piaroa", 3382207, nil, "Latn", } m["pie"] = { "Piro", 7198055, "nai-kta", "Latn", } m["pif"] = { "Pingelapese", 36421, "poz-mic", "Latn", } m["pig"] = { "Pisabo", 966883, "sai-pan", "Latn", } m["pih"] = { "Pitcairn-Norfolk", 36554, "crp", "Latn", ancestors = "en", } m["pii"] = { "Pini", 10631925, } m["pij"] = { "Pijao", 7193519, } m["pil"] = { "Yom", 36893, "nic-yon", } m["pim"] = { "Powhatan", 2270532, "alg-eas", "Latn", } m["pin"] = { "Piame", 7190042, "paa-sep", "Latn", } m["pio"] = { "Piapoco", 3382208, "awd-nwk", "Latn", } m["pip"] = { "Pero", 2411063, "cdc-wst", } m["pir"] = { "Piratapuyo", 3389119, "sai-tuc", "Latn", } m["pis"] = { "Pijin", 36699, "crp", "Latn", ancestors = "en", } m["pit"] = { "Pitta-Pitta", 6433116, "aus-kar", "Latn", } m["piu"] = { "Pintupi-Luritja", 2591175, "aus-pam", "Latn", } m["piv"] = { "Pileni", 2976736, "poz-pnp", "Latn", } m["piw"] = { "Pimbwe", 3894132, "bnt-mwi", } m["pix"] = { "Piu", 7199578, } m["piy"] = { "Piya-Kwonci", 3440492, } m["piz"] = { "Pije", 3388339, "poz-cln", "Latn", } m["pjt"] = { "Pitjantjatjara", 2982063, "aus-pam", "pjt-Latn", } m["pkb"] = { "Kipfokomo", 7208693, "bnt-sab", "Latn", } m["pkc"] = { "Baekje", 4841264, "qfa-kor", "Hani, Kana", sort_key = { Hani = "Hani-sortkey", Kana = "Kana-sortkey" }, } m["pkg"] = { "Pak-Tong", 3360711, } m["pkh"] = { "Pankhu", 7130962, "tbq-kuk", } m["pkn"] = { "Pakanha", 954916, "aus-pmn", "Latn", } m["pko"] = { "Pökoot", 36323, "sdv-kln", "Latn", } m["pkp"] = { "Pukapukan", 36447, "poz-pnp", "Latn", } m["pkr"] = { "Attapady Kurumba", 16835180, "dra-imd", "Mlym", -- Mlym translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission) } m["pks"] = { "Pakistan Sign Language", 22964057, "sgn", } m["pkt"] = { "Maleng", 6583562, "mkh-vie", } m["pku"] = { "Paku", 2932604, "poz-bre", "Latn", } m["pla"] = { "Miani", 12952844, "ngf-kau", "Latn", } m["plb"] = { "Polonombauk", 7225957, "poz-vnn", "Latn", } m["plc"] = { "Palaw-an Sentral", --"Central Palawano", 12953795, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Central Palawano", --TLCHANGE } m["ple"] = { "Palu'e", 2196866, "poz-cet", "Latn", } m["plg"] = { "Pilagá", 2748259, "sai-guc", "Latn", } m["plh"] = { "Paulohi", 7155331, "poz-cma", } m["plj"] = { "Polci", 3914383, } m["plk"] = { "Kohistani Shina", 12953882, "inc-shn", "ur-Arab, Latn", } m["pll"] = { "Shwe Palaung", 27941664, "mkh-pal", "Mymr", } m["pln"] = { "Palenquero", 36665, "crp", "Latn", ancestors = "es", } m["plo"] = { "Oluta Popoluca", 5908687, "nai-miz", "Latn", } m["plq"] = { "Palaic", 36582, "ine-ana", "Xsux", } m["plr"] = { "Palaka", 36346, "alv-snf", "Latn", } m["pls"] = { "San Marcos Tlalcoyalco Popoloca", 12641692, "omq-pop", "Latn", } m["plu"] = { "Palikur", 3073448, "awd", "Latn", } m["plv"] = { "Palaw-an Timog Kanluran", --"Southwest Palawano", 15614922, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Southwest Palawano", --TLCHANGE } m["plw"] = { "Palaw-an Brooke's Point", --"Brooke's Point Palawano", 12953796, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Brooke's Point Palawano", --TLCHANGE } m["ply"] = { "Bolyu", 3361723, "mkh-pkn", "Latn", } m["plz"] = { "Paluan", 7128795, nil, "Latn", } m["pma"] = { "Paamese", 3130286, "poz-vnc", "Latn", } m["pmb"] = { "Pambia", 36267, "znd", "Latn", } m["pmd"] = { "Pallanganmiddang", 7127734, "aus-pam", "Latn", } m["pme"] = { "Pwaamèi", 3411152, "poz-cln", "Latn", } m["pmf"] = { "Pamona", 3513320, "poz-kal", "Latn", } m["pmi"] = { "Northern Pumi", 3403245, "sit-qia", } m["pmj"] = { "Southern Pumi", 3403246, "sit-qia", } m["pmk"] = { "Pamlico", 111366045, "alg-eas", "Latn", } m["pml"] = { "Sabir", 636479, "crp", "Latn", ancestors = "lij-old, pro, vec-old", } m["pmm"] = { "Pol", 36408, "bnt-kak", "Latn", } m["pmn"] = { "Pam", 7129017, "alv-mbm", } m["pmo"] = { "Pom", 7227178, "poz-hce", "Latn", } m["pmq"] = { "Northern Pame", 3361762, "omq", "Latn", } m["pmr"] = { "Manat", 3450824, "ngf-sog", "Latn", } m["pms"] = { "Piedmontes", 15085, "roa-git", ancestors = "pms-old", "Latn", } m["pmt"] = { "Tuamotuan", 36763, "poz-pep", "Latn", } m["pmu"] = { "Mirpur Panjabi", 6874480, } m["pmw"] = { "Plains Miwok", 3391031, "nai-utn", "Latn", } m["pmx"] = { "Poumei Naga", 12952910, "tbq-anp", } m["pmy"] = { "Papuan Malay", 12473446, "crp", "Latn", ancestors = "ms", } m["pmz"] = { "Southern Pame", 3361765, "omq", "Latn", } m["pna"] = { "Punan Bah-Biau", 4842201, "poz-bnn", "Latn", } m["pnc"] = { "Pannei", 7131391, } m["pnd"] = { "Mpinda", 63308194, "bnt-kmb", } m["pne"] = { "Western Penan", 12953808, "poz-swa", "Latn", } m["png"] = { "Pongu", 36282, "nic-shi", } m["pnh"] = { "Penrhyn", 3130301, "poz-pep", "Latn", } m["pni"] = { "Aoheng", 4778608, "poz", "Latn", } m["pnj"] = { "Pinjarup", 33103591, } m["pnk"] = { "Paunaka", 2064378, "awd", "Latn", } m["pnl"] = { "Paleni", 7127118, "alv-wan", "Latn", } m["pnm"] = { "Punan Batu", 7259892, } m["pnn"] = { "Pinai-Hagahai", 5638511, "paa-pia", "Latn", } m["pno"] = { "Panobo", 3141869, "sai-pan", "Latn", } m["pnp"] = { "Pancana", 7130204, } m["pnq"] = { "Pana (West Africa)", 7129739, "nic-gnn", "Latn", } m["pnr"] = { "Panim", 11732562, "ngf-gum", "Latn", } m["pns"] = { "Ponosakan", 7227956, "phi", "Latn", } m["pnt"] = { "Pontic Greek", 36748, "grk", "Grek, Latn, Cyrl", ancestors = "gkm", translit = { Grek = "el-translit" }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["pnu"] = { "Jiongnai Bunu", 56325, "hmn", } m["pnv"] = { "Pinigura", 10631927, "aus-psw", "Latn", } m["pnw"] = { "Panyjima", 3913830, "aus-nga", "Latn", } m["pnx"] = { "Phong-Kniang", 3914627, "mkh", } m["pny"] = { "Pinyin", 36250, "nic-nge", "Latn", } m["pnz"] = { "Pana (Central Africa)", 36241, "alv-mbm", "Latn", } m["poc"] = { "Poqomam", 36416, "myn", "Latn", } m["poe"] = { "San Juan Atzingo Popoloca", 12953819, "omq-pop", "Latn", } m["pof"] = { "Poke", 7208577, "bnt-ske", } m["pog"] = { "Potiguára", 56722, "tup-gua", "Latn", } m["poh"] = { "Poqomchi'", 36414, "myn", "Latn", } m["poi"] = { "Highland Popoluca", 7511556, "nai-miz", "Latn", } m["pok"] = { "Pokangá", 25559704, "sai-tuc", "Latn", } m["pom"] = { "Southeastern Pomo", 3396025, "nai-pom", "Latn", } m["pon"] = { "Pohnpeian", 28422, "poz-mic", "Latn", } m["poo"] = { "Central Pomo", 3396020, "nai-pom", "Latn", } m["pop"] = { "Pwapwâ", 3411153, "poz-cln", "Latn", } m["poq"] = { "Texistepec Popoluca", 5908707, "nai-miz", "Latn", } m["pos"] = { "Sayula Popoluca", 5908722, "nai-miz", "Latn", } m["pot"] = { "Potawatomi", 56749, "alg", "Latn", } m["pov"] = { "Guinea-Bissau Creole", 33339, "crp", "Latn", ancestors = "pt", } m["pow"] = { "San Felipe Otlaltepec Popoloca", 25559598, "omq-pop", "Latn", } m["pox"] = { "Polabian", 36741, "zlw-lch", "Latn", } m["poy"] = { "Pogolo", 2429648, "bnt-kil", } m["ppa"] = { "Pao", 7132069, } m["ppe"] = { "Papi", 7132809, } m["ppi"] = { "Paipai", 56726, "nai-yuc", "Latn", } m["ppk"] = { "Uma", 7881036, "poz-kal", "Latn", } m["ppl"] = { "Pipil", 1186896, "azc-nah", "Latn", strip_diacritics = {remove_diacritics = c.acute .. c.macron}, } m["ppm"] = { "Papuma", 7133239, "poz-hce", "Latn", } m["ppn"] = { "Papapana", 3362757, "poz-ocw", "Latn", } m["ppo"] = { "Folopa", 5464843, "paa-teb", "Latn", } m["ppq"] = { "Pei", 7160903, "paa-wal", "Latn", } m["pps"] = { "San Luís Temalacayuca Popoloca", 25559602, "omq-pop", "Latn", } m["ppt"] = { "Pa", 3504757, "paa-kae", "Latn", } m["ppu"] = { "Papora", 2094884, "map", "Latn", } m["pqa"] = { "Pa'a", 3441315, "cdc-wst", } m["pqm"] = { "Malecite-Passamaquoddy", 3183144, "alg-eas", "Latn", } m["pra"] = { "Prakrit", 192170, "inc-mid", "Brah, Deva, Gujr, Knda", ancestors = "inc-ash", translit = { -- Brah translit in [[Module:scripts/data]] Deva = "pra-Deva-translit", Gujr = "sa-Gujr-translit", Knda = "pra-Knda-translit", }, strip_diacritics = { -- FIXME: separate by script from = {"ऎ", "ऒ", u(0x0946), u(0x094A), "य़", "ಯ಼", u(0x11071), u(0x11072), u(0x11073), u(0x11074)}, to = {"ए", "ओ", u(0x0947), u(0x094B), "य", "ಯ", "𑀏", "𑀑", u(0x11042), u(0x11044)} } , } m["prc"] = { "Parachi", 2640637, "ira-orp", "Arab", } -- "prd" is not included, see [[WT:LT]] m["pre"] = { "Principense", 36520, "crp", "Latn", ancestors = "pt", } m["prf"] = { "Paranan", --"Paranan" 7135433, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/paranan/", --TLCHANGE english_name = "Paranan", --TLCHANGE } m["prg"] = { "Old Prussian", 35501, "bat-wes", "Latn", } m["prh"] = { "Porohanon", --"Porohanon" 6583710, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/porohanon/", --TLCHANGE english_name = "Porohanon", --TLCHANGE } m["pri"] = { "Paicî", 732131, "poz-cln", "Latn", } m["prk"] = { "Parauk", 3363719, "mkh-pal", "Latn", } m["prl"] = { "Peruvian Sign Language", 3915508, "sgn", } m["prm"] = { "Kibiri", 56745, "qfa-iso", -- Papuan; isolate in Glottolog and Wurm; suggested grouping with Kiwaian languages by Ross based only on 1sg and 2sg pronouns "Latn", } m["prn"] = { "Prasuni", 32689, "nur-nor", } m["pro"] = { "Old Occitan", 2779185, "roa-ocr", "Latn", sort_key = {remove_diacritics = c.cedilla}, } -- "prp" is not included, see [[WT:LT]] m["prq"] = { "Perené Ashéninka", 3450601, "awd", "Latn", } m["prr"] = { "Puri", 7261687, } -- "prs" is treated as "fa" (or as etymology-only), see [[WT:LT]] m["prt"] = { "Phai", 7180184, "mkh", } m["pru"] = { "Puragi", 7260800, "ngf-sbh", "Latn", } m["prw"] = { "Parawen", 7136291, "ngf-num", "Latn", } m["prx"] = { "Purik", 567905, "sit-lab", } m["prz"] = { "Providencia Sign Language", 3322084, "sgn", } m["psa"] = { "Asue Awyu", 11266334, "ngf-awy", "Latn", } m["psc"] = { "Persian Sign Language", 7170221, "sgn", } m["psd"] = { "Plains Indian Sign Language", 2380124, "sgn", } m["pse"] = { "Central Malay", -- This does not mean the central of Malaysia. It is spoken in Indonesia. 3367751, "poz-mly", "Latn, Rjng", } m["psg"] = { "Penang Sign Language", 4924925, "sgn", } m["psh"] = { "Southwest Pashayi", 16112270, "inc-pas", "fa-Arab", } m["psi"] = { "Southeast Pashayi", 23713536, "inc-pas", "fa-Arab", } m["psl"] = { "Puerto Rican Sign Language", 7258608, "sgn-fsl", } m["psm"] = { "Pauserna", 2912846, "tup-gua", "Latn", } m["psn"] = { "Panasuan", 7130113, "poz", } m["pso"] = { "Polish Sign Language", 3915194, "sgn-gsl", } m["psp"] = { "Wikang Senyas ng mga Pilipino", --TLCHANGE 3551357, "sgn-fsl", is_official_kwf_name = "https://www.facebook.com/reel/911167531341993", --TLCHANGE english_name = "Philippine Sign Language", --TLCHANGE } m["psq"] = { "Pasi", 7142091, "paa-sep", "Latn", } m["psr"] = { "Portuguese Sign Language", 3915472, "sgn", } m["pss"] = { "Kaulong", 3194294, "poz-ocw", } m["psw"] = { "Port Sandwich", 3398324, "poz-vnc", "Latn", } m["psy"] = { "Piscataway", 3504233, "alg-eas", } m["pta"] = { "Pai Tavytera", 7124619, "tup-gua", "Latn", } m["pth"] = { "Pataxó Hã-Ha-Hãe", 7144304, } m["pti"] = { "Pintiini", 10632026, "aus-pam", "Latn", } m["ptn"] = { "Patani", 7144242, "poz-hce", "Latn", } m["pto"] = { "Zo'é", 8073148, "tup-gua", "Latn", } m["ptp"] = { "Patep", 3368679, "poz-ocw", "Latn", } m["ptq"] = { "Pattapu", 60785085, "dra-tam", } m["ptr"] = { "Piamatsina", 7190040, "poz-vnn", "Latn", } m["ptt"] = { "Enrekang", 12953520, nil, "Latn", } m["ptu"] = { "Bambam", 4853321, "poz-ssw", "Latn", } m["ptv"] = { "Port Vato", 3398323, "poz-vnc", "Latn", } m["ptw"] = { "Pentlatch", 2069475, "sal", "Latn", } m["pty"] = { "Pathiya", 7144790, "dra-mal", } m["pua"] = { "Purepecha", 16114351, "qfa-iso", "Latn", sort_key = {remove_diacritics = c.acute}, } m["pub"] = { "Purum", 6400562, "tbq-kuk", "Latn", } m["puc"] = { "Punan Merap", 7259895, "poz", "Latn", } m["pud"] = { "Punan Aput", 4782333, "poz-swa", "Latn", } m["pue"] = { "Puelche", 33660, } m["puf"] = { "Punan Merah", 7259894, "poz-swa", "Latn", } m["pug"] = { "Phuie", 36375, "nic-gnw", } m["pui"] = { "Puinave", 3027918, nil, "Latn", } m["puj"] = { "Punan Tubu", 7259896, "poz-swa", "Latn", } m["pum"] = { "Puma", 33736, "sit-kic", } m["puo"] = { "Puoc", 6440803, "mkh", "Latn", } m["pup"] = { "Pulabu", 7259163, "ngf-rai", "Latn", } m["puq"] = { "Puquina", 1207739, } m["pur"] = { "Puruborá", 7261619, "tup", } m["put"] = { "Putoh", 12953832, "poz-swa", "Latn", } m["puu"] = { "Punu", 36401, "bnt-sir", "Latn", } m["puw"] = { "Puluwat", 36397, "poz-mic", "Latn", } m["pux"] = { "Puare", 3507983, "paa-shi", "Latn", } m["puy"] = { "Purisimeño", 2967638, "nai-chu", "Latn", } m["pwa"] = { "Pawaia", 7156099, "qfa-dis", -- Papuan; isolate in Glottolog; unclassified in Pawley and Hammarström (2018); sister to the Teberan -- languages by Usher (2020); tentatively TNG by Ross (2005) "Latn", } m["pwb"] = { "Panawa", 47385077, "nic-jer", "Latn", ancestors = "jer", } m["pwg"] = { "Gapapaiwa", 3095245, "poz-ocw", "Latn", } m["pwi"] = { "Patwin", 3370188, "nai-wtq", "Latn", } m["pwm"] = { "Molbog", --"Molbog" 6895718, "poz-san", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/molbog/", --TLCHANGE english_name = "Molbog", --TLCHANGE } m["pwn"] = { "Paiwan", 715755, "map", "Latn", } m["pwo"] = { "Western Pwo", 7988202, "kar", "Mymr", } m["pwr"] = { "Powari", 12640277, "inc-hie", "Deva", } m["pww"] = { "Northern Pwo", 7058885, "kar", "Thai", } m["pxm"] = { "Quetzaltepec Mixe", 6842374, "nai-miz", "Latn", } m["pye"] = { "Pye Krumen", 11157382, "kro-grb", } m["pym"] = { "Fyam", 3914025, "nic-ple", "Latn", } m["pyn"] = { "Poyanáwa", 3401023, "sai-pan", } m["pys"] = { "Paraguayan Sign Language", 7134698, "sgn", } m["pyu"] = { "Puyuma", 716690, "map", "Latn", } m["pyx"] = { "Pyu (Myanmar)", 36259, "sit", } m["pyy"] = { "Pyen", 7262966, "tbq-bis", } m["pzh"] = { "Pazeh", 36435, "map", "Latn", } m["pzn"] = { "Para Naga", 7133667, "sit-aao", } return require("Module:languages").finalizeData(m, "language") 9mxgsowzudp9tafo406gxpxne5m47lw 178466 178461 2026-10-27T02:12:02Z GinawaSaHapon 3989 178466 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["pab"] = { "Pareci", 3504312, "awd", "Latn", } m["pac"] = { "Pacoh", 3441136, "mkh-kat", "Latn", } m["pad"] = { "Paumarí", 389827, "auf", "Latn", } m["pae"] = { "Pagibete", 7124357, "bnt-bta", "Latn", } m["paf"] = { "Paranawát", 12953806, "tup-gua", "Latn", } m["pag"] = { "Pangasinan", --"Pangasinan" 33879, "phi", "Latn, Tglg", strip_diacritics = { Latn = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer}, }, is_official_kwf_name = "https://kwfwikaatkultura.ph/pangasinan/", --TLCHANGE english_name = "Pangasinan", --TLCHANGE } m["pah"] = { "Tenharim", 10266010, "tup-gua", "Latn", } m["pai"] = { "Pe", 3914871, "nic-tar", "Latn", } m["pak"] = { "Parakanã", 12953804, "tup-gua", "Latn", } m["pal"] = { "Middle Persian", 32063, "ira-swi", "Latn, Phli, pal-Avst, Mani, Phlp, Phlv", -- Latn for translit; Phlv not in Unicode translit = { Phli = "Phli-translit", ["pal-Avst"] = "Avst-translit", -- Mani translit in [[Module:scripts/data]] }, ancestors = "peo", } m["pam"] = { "Kapampangan", --"Kapampangan", 36121, "phi", "Latn, Kulit", strip_diacritics = { Latn = {remove_diacritics = c.grave .. c.acute .. c.circ} }, standard_chars = { Latn = "AaBbDdEeGgHhIiKkLlMmNnOoPpRrSsTtUuWwYy", c.punc }, sort_key = { Latn = "tl-sortkey" }, is_official_kwf_name = "https://kwfwikaatkultura.ph/kapampangan/", --TLCHANGE english_name = "Kapampangan", } m["pao"] = { "Northern Paiute", 3360656, "azc-num", "Latn", } m["pap"] = { "Papyamento", --TLCHANGE 33856, "crp", "Latn", ancestors = "pt", english_name = "Papiamentu", --TLCHANGE spanish_name = "Papiamento", --TLCHANGE } m["paq"] = { "Parya", 1135134, "inc-cen", } m["par"] = { "Panamint", 33926, "azc-num", "Latn", } m["pas"] = { "Papasena", 7132508, "paa-clp", "Latn", } m["pau"] = { "Palauan", 33776, "poz", "Latn, Kana", sort_key = { Kana = "Kana-sortkey" }, } m["pav"] = { "Wari'", 3027909, "sai-cpc", "Latn", } m["paw"] = { "Pawnee", 56751, "cdd", "Latn", strip_diacritics = {remove_diacritics = c.acute}, } m["pax"] = { "Pankararé", 25559779, nil, "Latn", } m["pay"] = { "Pech", 4898889, "cba", "Latn", } m["paz"] = { "Pankararú", 7131310, nil, "Latn", } m["pbb"] = { "Páez", 33677, nil, "Latn", } m["pbc"] = { "Patamona", 3915921, "sai-pem", "Latn", } m["pbe"] = { "Mezontla Popoloca", 42365630, "omq-pop", "Latn", } m["pbf"] = { "Coyotepec Popoloca", 5180100, "omq-pop", "Latn", } m["pbg"] = { "Paraujano", 3501747, "awd-taa", "Latn", } m["pbh"] = { "Panare", 56610, "sai-ven", "Latn", } m["pbi"] = { "Podoko", 3515096, "cdc-cbm", "Latn", } m["pbl"] = { "Mak (Nigeria)", 3915349, "alv-bwj", "Latn", } m["pbm"] = { "Puebla Mazatec", 31102530, "omq-maz", "Latn", } m["pbn"] = { "Kpasam", 3914902, "alv-mye", "Latn", } m["pbo"] = { "Papel", 36314, "alv-pap", "Latn", } m["pbp"] = { "Badyara", 35095, "alv-ten", "Latn", } m["pbr"] = { "Pangwa", 3847550, "bnt-bki", "Latn", } m["pbs"] = { "Central Pame", 3361763, "omq", "Latn", } m["pbv"] = { "Pnar", 3501850, "aav-pkl", "Latn", } m["pby"] = { "Pyu (New Guinea)", 2567925, "qfa-dis", -- Papuan; isolate per Glottolog, in a putative Arai-Samaia family in Usher (2020) "Latn", } m["pca"] = { "Santa Inés Ahuatempan Popoloca", 42365276, "omq-pop", "Latn", } m["pcb"] = { "Pear", 6583669, "mkh-pea", "Khmr", } m["pcc"] = { "Bouyei", 35100, "tai-nor", "Latn, Hani", sort_key = { Hani = "Hani-sortkey" }, } m["pcd"] = { "Picard", 34024, "roa-oil", "Latn", sort_key = s["roa-oil-sortkey"], } m["pce"] = { "Ruching Palaung", 12953798, "mkh-pal", "Mymr", } m["pcf"] = { "Paliyan", 7127643, "dra-tam", } m["pcg"] = { "Paniya", 7131211, "dra-mal", } m["pch"] = { "Pardhan", 7133207, "dra-gon", } m["pci"] = { "Duruwa", 56753, "dra-pgd", "Deva, Orya", } m["pcj"] = { "Parenga", 3111396, "mun", } m["pck"] = { "Paite", 12952337, "tbq-kuk", } m["pcl"] = { "Pardhi", 7136554, "inc-bhi", } m["pcm"] = { "Nigerian Pidgin", 33655, "crp", "Latn", ancestors = "en", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron .. c.macronbelow}, sort_key = { remove_diacritics = c.tilde, from = {"ẹ", "gb", "kp", "ọ", "sh", "zh"}, to = {"e" .. p[1], "g" .. p[1], "k" .. p[1], "o" .. p[1], "s" .. p[1], "z" .. p[1]} }, } m["pcn"] = { "Piti", 3913375, "nic-kne", "Latn", } m["pcp"] = { "Pacahuara", 2591165, "sai-pan", "Latn", } m["pcw"] = { "Pyapun", 3438807, nil, "Latn", } m["pda"] = { "Anam", 3501930, "ngf-pom", "Latn", } m["pdc"] = { "Pennsylvania German", 22711, "gmw-hgm", "Latn", ancestors = "gmw-rfr", } m["pdi"] = { "Pa Di", 3359940, nil, "Latn", } m["pdn"] = { "Fedan", 7206699, "poz-ocw", "Latn", } m["pdo"] = { "Padoe", 3360370, "poz-btk", "Latn", } m["pdt"] = { "Plautdietsch", 1751432, "gmw-lgm", "Latn", ancestors = "nds-de", } m["pdu"] = { "Kayan", 7123283, "kar", "Latn", } m["pea"] = { "Peranakan Indonesian", 653415, "crp", "Latn", ancestors = "ms", } m["peb"] = { "Eastern Pomo", 3396032, "nai-pom", "Latn", } m["ped"] = { "Mala (New Guinea)", 11732569, "ngf-kau", "Latn", } m["pee"] = { "Taje", 12953902, nil, "Latn", } m["pef"] = { "Northeastern Pomo", 3396018, "nai-pom", "Latn", } m["peg"] = { "Pengo", 56758, "dra-kki", "Orya", translit = "kxv-translit", } m["peh"] = { "Bonan", 32983, "xgn-shr", "Latn", } m["pei"] = { "Chichimeca-Jonaz", 3915427, "omq-otp", "Latn", } m["pej"] = { "Northern Pomo", 3396021, "nai-pom", "Latn", } m["pek"] = { "Penchal", 3374631, "poz-aay", "Latn", } m["pel"] = { "Pekal", 3241781, nil, "Latn", } m["pem"] = { "Phende", 7162372, "bnt-pen", "Latn", } m["peo"] = { "Old Persian", 35225, "ira-swi", "Xpeo, Latn", translit = "peo-translit", } m["pep"] = { "Kunja", 6444807, "paa-ton", "Latn", } m["peq"] = { "Southern Pomo", 3396023, "nai-pom", "Latn", } -- "pes" is treated as "fa" (or as etymology-only), see [[WT:LT]] m["pev"] = { "Pémono", 3439012, "sai-map", "Latn", } m["pex"] = { "Petats", 3376353, "poz-ocw", "Latn", } m["pey"] = { "Petjo", 940486, nil, "Latn", } m["pez"] = { "Eastern Penan", 18638342, "poz-swa", "Latn", } m["pfa"] = { "Pááfang", 3063517, "poz-mic", "Latn", } m["pfe"] = { "Peere", 36377, "alv-dur", "Latn", } m["pga"] = { "Juba Arabic", 1262143, "crp", "Latn", ancestors = "apd", } m["pgd"] = { "Gandhari", 3124623, "inc-mid", "Deva, Khar", ancestors = "inc-ash", translit = "Khar-translit", } m["pgg"] = { "Pangwali", 13600429, "him", "Deva, Takr", translit = "hi-translit", } m["pgi"] = { "Pagi", 7124354, "paa-bew", "Latn", } m["pgk"] = { "Rerep", 586907, "poz-vnc", "Latn", } m["pgl"] = { "Primitive Irish", 3320030, "cel-gae", "Ogam, Latn", translit = "pgl-translit", } m["pgn"] = { "Paelignian", 65455883, "itc-sbl", "Ital, Latn", -- Ital translit in [[Module:scripts/data]] display_text = { Latn = s["itc-Latn-displaytext"] }, strip_diacritics = { Latn = s["itc-Latn-stripdiacritics"] }, sort_key = { Latn = s["itc-Latn-sortkey"] }, } m["pgs"] = { "Pangseng", 3914027, "alv-mum", "Latn", } m["pgu"] = { "Pagu", 7124462, "paa-gto", "Latn", } m["pgz"] = { "Papua New Guinean Sign Language", 25044405, "sgn", } m["pha"] = { "Pa-Hng", 2625410, "hmn", } m["phd"] = { "Phudagi", 7188289, } m["phg"] = { "Phuong", 7188376, "mkh-kat", } m["phh"] = { "Phukha", 7188298, "tbq-phw", } m["phk"] = { "Phake", 7675798, "tai-swe", "Mymr", translit = "aio-phk-translit", display_text = s["phk-displaytext"], strip_diacritics = s["phk-stripdiacritics"], } m["phl"] = { "Palula", 2449549, "inc-dng", "Latn, ur-Arab", strip_diacritics = { -- character "ۂ" code U+06C2 to "ه" and "هٔ" (U+0647 + U+0654) to "ه"; hamzatu l-waṣli to a regular alif from = {"هٔ", "ۂ", "ٱ"}, to = {"ہ", "ہ", "ا"}, remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna .. c.superalef }, } m["phm"] = { "Phimbi", 11007144, "bnt-sna", "Latn", } m["phn"] = { "Phoenician", 36734, "sem-can", "Phnx", -- Phnx translit in [[Module:scripts/data]] } m["pho"] = { "Phunoi", 7188361, "tbq-bis", } m["phq"] = { "Phana'", 7180427, "tbq-sil", } m["phr"] = { "Pahari-Potwari", 33739, "inc-pan", "pa-Arab, Guru", translit = { Guru = "Guru-translit", ["pa-Arab"] = "pa-Arab-translit", }, strip_diacritics = { ["pa-Arab"] = { remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna, from = {"ݨ", "ࣇ"}, to = {"ن", "ل"} }, } } m["pht"] = { "Phu Thai", 3626597, "tai-swe", "Thai", } m["phu"] = { "Phuan", 3915665, } m["phv"] = { "Pahlavani", 7124567, } m["phw"] = { "Phangduwali", 12953036, "sit-kie", ancestors = "ybh", } m["pia"] = { "Pima Bajo", 3388544, "azc-pim", "Latn", } m["pib"] = { "Yine", 3135432, "awd", "Latn", } m["pic"] = { "Pinji", 36296, "bnt-tso", "Latn", } m["pid"] = { "Piaroa", 3382207, nil, "Latn", } m["pie"] = { "Piro", 7198055, "nai-kta", "Latn", } m["pif"] = { "Pingelapese", 36421, "poz-mic", "Latn", } m["pig"] = { "Pisabo", 966883, "sai-pan", "Latn", } m["pih"] = { "Pitcairn-Norfolk", 36554, "crp", "Latn", ancestors = "en", } m["pii"] = { "Pini", 10631925, } m["pij"] = { "Pijao", 7193519, } m["pil"] = { "Yom", 36893, "nic-yon", } m["pim"] = { "Powhatan", 2270532, "alg-eas", "Latn", } m["pin"] = { "Piame", 7190042, "paa-sep", "Latn", } m["pio"] = { "Piapoco", 3382208, "awd-nwk", "Latn", } m["pip"] = { "Pero", 2411063, "cdc-wst", } m["pir"] = { "Piratapuyo", 3389119, "sai-tuc", "Latn", } m["pis"] = { "Pijin", 36699, "crp", "Latn", ancestors = "en", } m["pit"] = { "Pitta-Pitta", 6433116, "aus-kar", "Latn", } m["piu"] = { "Pintupi-Luritja", 2591175, "aus-pam", "Latn", } m["piv"] = { "Pileni", 2976736, "poz-pnp", "Latn", } m["piw"] = { "Pimbwe", 3894132, "bnt-mwi", } m["pix"] = { "Piu", 7199578, } m["piy"] = { "Piya-Kwonci", 3440492, } m["piz"] = { "Pije", 3388339, "poz-cln", "Latn", } m["pjt"] = { "Pitjantjatjara", 2982063, "aus-pam", "pjt-Latn", } m["pkb"] = { "Kipfokomo", 7208693, "bnt-sab", "Latn", } m["pkc"] = { "Baekje", 4841264, "qfa-kor", "Hani, Kana", sort_key = { Hani = "Hani-sortkey", Kana = "Kana-sortkey" }, } m["pkg"] = { "Pak-Tong", 3360711, } m["pkh"] = { "Pankhu", 7130962, "tbq-kuk", } m["pkn"] = { "Pakanha", 954916, "aus-pmn", "Latn", } m["pko"] = { "Pökoot", 36323, "sdv-kln", "Latn", } m["pkp"] = { "Pukapukan", 36447, "poz-pnp", "Latn", } m["pkr"] = { "Attapady Kurumba", 16835180, "dra-imd", "Mlym", -- Mlym translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission) } m["pks"] = { "Pakistan Sign Language", 22964057, "sgn", } m["pkt"] = { "Maleng", 6583562, "mkh-vie", } m["pku"] = { "Paku", 2932604, "poz-bre", "Latn", } m["pla"] = { "Miani", 12952844, "ngf-kau", "Latn", } m["plb"] = { "Polonombauk", 7225957, "poz-vnn", "Latn", } m["plc"] = { "Palaw-an Sentral", --"Central Palawano", 12953795, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Central Palawano", --TLCHANGE } m["ple"] = { "Palu'e", 2196866, "poz-cet", "Latn", } m["plg"] = { "Pilagá", 2748259, "sai-guc", "Latn", } m["plh"] = { "Paulohi", 7155331, "poz-cma", } m["plj"] = { "Polci", 3914383, } m["plk"] = { "Kohistani Shina", 12953882, "inc-shn", "ur-Arab, Latn", } m["pll"] = { "Shwe Palaung", 27941664, "mkh-pal", "Mymr", } m["pln"] = { "Palenquero", 36665, "crp", "Latn", ancestors = "es", } m["plo"] = { "Oluta Popoluca", 5908687, "nai-miz", "Latn", } m["plq"] = { "Palaic", 36582, "ine-ana", "Xsux", } m["plr"] = { "Palaka", 36346, "alv-snf", "Latn", } m["pls"] = { "San Marcos Tlalcoyalco Popoloca", 12641692, "omq-pop", "Latn", } m["plu"] = { "Palikur", 3073448, "awd", "Latn", } m["plv"] = { "Palaw-an Timog Kanluran", --"Southwest Palawano", 15614922, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Southwest Palawano", --TLCHANGE } m["plw"] = { "Palaw-an Brooke's Point", --"Brooke's Point Palawano", 12953796, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/palaw-an/", --TLCHANGE english_name = "Brooke's Point Palawano", --TLCHANGE } m["ply"] = { "Bolyu", 3361723, "mkh-pkn", "Latn", } m["plz"] = { "Paluan", 7128795, nil, "Latn", } m["pma"] = { "Paamese", 3130286, "poz-vnc", "Latn", } m["pmb"] = { "Pambia", 36267, "znd", "Latn", } m["pmd"] = { "Pallanganmiddang", 7127734, "aus-pam", "Latn", } m["pme"] = { "Pwaamèi", 3411152, "poz-cln", "Latn", } m["pmf"] = { "Pamona", 3513320, "poz-kal", "Latn", } m["pmi"] = { "Northern Pumi", 3403245, "sit-qia", } m["pmj"] = { "Southern Pumi", 3403246, "sit-qia", } m["pmk"] = { "Pamlico", 111366045, "alg-eas", "Latn", } m["pml"] = { "Sabir", 636479, "crp", "Latn", ancestors = "lij-old, pro, vec-old", } m["pmm"] = { "Pol", 36408, "bnt-kak", "Latn", } m["pmn"] = { "Pam", 7129017, "alv-mbm", } m["pmo"] = { "Pom", 7227178, "poz-hce", "Latn", } m["pmq"] = { "Northern Pame", 3361762, "omq", "Latn", } m["pmr"] = { "Manat", 3450824, "ngf-sog", "Latn", } m["pms"] = { "Piedmontes", 15085, "roa-git", ancestors = "pms-old", "Latn", } m["pmt"] = { "Tuamotuan", 36763, "poz-pep", "Latn", } m["pmu"] = { "Mirpur Panjabi", 6874480, } m["pmw"] = { "Plains Miwok", 3391031, "nai-utn", "Latn", } m["pmx"] = { "Poumei Naga", 12952910, "tbq-anp", } m["pmy"] = { "Papuan Malay", 12473446, "crp", "Latn", ancestors = "ms", } m["pmz"] = { "Southern Pame", 3361765, "omq", "Latn", } m["pna"] = { "Punan Bah-Biau", 4842201, "poz-bnn", "Latn", } m["pnc"] = { "Pannei", 7131391, } m["pnd"] = { "Mpinda", 63308194, "bnt-kmb", } m["pne"] = { "Western Penan", 12953808, "poz-swa", "Latn", } m["png"] = { "Pongu", 36282, "nic-shi", } m["pnh"] = { "Penrhyn", 3130301, "poz-pep", "Latn", } m["pni"] = { "Aoheng", 4778608, "poz", "Latn", } m["pnj"] = { "Pinjarup", 33103591, } m["pnk"] = { "Paunaka", 2064378, "awd", "Latn", } m["pnl"] = { "Paleni", 7127118, "alv-wan", "Latn", } m["pnm"] = { "Punan Batu", 7259892, } m["pnn"] = { "Pinai-Hagahai", 5638511, "paa-pia", "Latn", } m["pno"] = { "Panobo", 3141869, "sai-pan", "Latn", } m["pnp"] = { "Pancana", 7130204, } m["pnq"] = { "Pana (West Africa)", 7129739, "nic-gnn", "Latn", } m["pnr"] = { "Panim", 11732562, "ngf-gum", "Latn", } m["pns"] = { "Ponosakan", 7227956, "phi", "Latn", } m["pnt"] = { "Pontic Greek", 36748, "grk", "Grek, Latn, Cyrl", ancestors = "gkm", translit = { Grek = "el-translit" }, -- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["pnu"] = { "Jiongnai Bunu", 56325, "hmn", } m["pnv"] = { "Pinigura", 10631927, "aus-psw", "Latn", } m["pnw"] = { "Panyjima", 3913830, "aus-nga", "Latn", } m["pnx"] = { "Phong-Kniang", 3914627, "mkh", } m["pny"] = { "Pinyin", 36250, "nic-nge", "Latn", } m["pnz"] = { "Pana (Central Africa)", 36241, "alv-mbm", "Latn", } m["poc"] = { "Poqomam", 36416, "myn", "Latn", } m["poe"] = { "San Juan Atzingo Popoloca", 12953819, "omq-pop", "Latn", } m["pof"] = { "Poke", 7208577, "bnt-ske", } m["pog"] = { "Potiguára", 56722, "tup-gua", "Latn", } m["poh"] = { "Poqomchi'", 36414, "myn", "Latn", } m["poi"] = { "Highland Popoluca", 7511556, "nai-miz", "Latn", } m["pok"] = { "Pokangá", 25559704, "sai-tuc", "Latn", } m["pom"] = { "Southeastern Pomo", 3396025, "nai-pom", "Latn", } m["pon"] = { "Pohnpeian", 28422, "poz-mic", "Latn", } m["poo"] = { "Central Pomo", 3396020, "nai-pom", "Latn", } m["pop"] = { "Pwapwâ", 3411153, "poz-cln", "Latn", } m["poq"] = { "Texistepec Popoluca", 5908707, "nai-miz", "Latn", } m["pos"] = { "Sayula Popoluca", 5908722, "nai-miz", "Latn", } m["pot"] = { "Potawatomi", 56749, "alg", "Latn", } m["pov"] = { "Kriyolo ng Ginea-Bissau", 33339, "crp", "Latn", ancestors = "pt", } m["pow"] = { "San Felipe Otlaltepec Popoloca", 25559598, "omq-pop", "Latn", } m["pox"] = { "Polabian", 36741, "zlw-lch", "Latn", } m["poy"] = { "Pogolo", 2429648, "bnt-kil", } m["ppa"] = { "Pao", 7132069, } m["ppe"] = { "Papi", 7132809, } m["ppi"] = { "Paipai", 56726, "nai-yuc", "Latn", } m["ppk"] = { "Uma", 7881036, "poz-kal", "Latn", } m["ppl"] = { "Pipil", 1186896, "azc-nah", "Latn", strip_diacritics = {remove_diacritics = c.acute .. c.macron}, } m["ppm"] = { "Papuma", 7133239, "poz-hce", "Latn", } m["ppn"] = { "Papapana", 3362757, "poz-ocw", "Latn", } m["ppo"] = { "Folopa", 5464843, "paa-teb", "Latn", } m["ppq"] = { "Pei", 7160903, "paa-wal", "Latn", } m["pps"] = { "San Luís Temalacayuca Popoloca", 25559602, "omq-pop", "Latn", } m["ppt"] = { "Pa", 3504757, "paa-kae", "Latn", } m["ppu"] = { "Papora", 2094884, "map", "Latn", } m["pqa"] = { "Pa'a", 3441315, "cdc-wst", } m["pqm"] = { "Malecite-Passamaquoddy", 3183144, "alg-eas", "Latn", } m["pra"] = { "Prakrit", 192170, "inc-mid", "Brah, Deva, Gujr, Knda", ancestors = "inc-ash", translit = { -- Brah translit in [[Module:scripts/data]] Deva = "pra-Deva-translit", Gujr = "sa-Gujr-translit", Knda = "pra-Knda-translit", }, strip_diacritics = { -- FIXME: separate by script from = {"ऎ", "ऒ", u(0x0946), u(0x094A), "य़", "ಯ಼", u(0x11071), u(0x11072), u(0x11073), u(0x11074)}, to = {"ए", "ओ", u(0x0947), u(0x094B), "य", "ಯ", "𑀏", "𑀑", u(0x11042), u(0x11044)} } , } m["prc"] = { "Parachi", 2640637, "ira-orp", "Arab", } -- "prd" is not included, see [[WT:LT]] m["pre"] = { "Principense", 36520, "crp", "Latn", ancestors = "pt", } m["prf"] = { "Paranan", --"Paranan" 7135433, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/paranan/", --TLCHANGE english_name = "Paranan", --TLCHANGE } m["prg"] = { "Old Prussian", 35501, "bat-wes", "Latn", } m["prh"] = { "Porohanon", --"Porohanon" 6583710, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/porohanon/", --TLCHANGE english_name = "Porohanon", --TLCHANGE } m["pri"] = { "Paicî", 732131, "poz-cln", "Latn", } m["prk"] = { "Parauk", 3363719, "mkh-pal", "Latn", } m["prl"] = { "Peruvian Sign Language", 3915508, "sgn", } m["prm"] = { "Kibiri", 56745, "qfa-iso", -- Papuan; isolate in Glottolog and Wurm; suggested grouping with Kiwaian languages by Ross based only on 1sg and 2sg pronouns "Latn", } m["prn"] = { "Prasuni", 32689, "nur-nor", } m["pro"] = { "Lumang Oksitano", 2779185, "roa-ocr", "Latn", sort_key = {remove_diacritics = c.cedilla}, } -- "prp" is not included, see [[WT:LT]] m["prq"] = { "Perené Ashéninka", 3450601, "awd", "Latn", } m["prr"] = { "Puri", 7261687, } -- "prs" is treated as "fa" (or as etymology-only), see [[WT:LT]] m["prt"] = { "Phai", 7180184, "mkh", } m["pru"] = { "Puragi", 7260800, "ngf-sbh", "Latn", } m["prw"] = { "Parawen", 7136291, "ngf-num", "Latn", } m["prx"] = { "Purik", 567905, "sit-lab", } m["prz"] = { "Providencia Sign Language", 3322084, "sgn", } m["psa"] = { "Asue Awyu", 11266334, "ngf-awy", "Latn", } m["psc"] = { "Persian Sign Language", 7170221, "sgn", } m["psd"] = { "Plains Indian Sign Language", 2380124, "sgn", } m["pse"] = { "Central Malay", -- This does not mean the central of Malaysia. It is spoken in Indonesia. 3367751, "poz-mly", "Latn, Rjng", } m["psg"] = { "Penang Sign Language", 4924925, "sgn", } m["psh"] = { "Southwest Pashayi", 16112270, "inc-pas", "fa-Arab", } m["psi"] = { "Southeast Pashayi", 23713536, "inc-pas", "fa-Arab", } m["psl"] = { "Puerto Rican Sign Language", 7258608, "sgn-fsl", } m["psm"] = { "Pauserna", 2912846, "tup-gua", "Latn", } m["psn"] = { "Panasuan", 7130113, "poz", } m["pso"] = { "Polish Sign Language", 3915194, "sgn-gsl", } m["psp"] = { "Wikang Senyas ng mga Pilipino", --TLCHANGE 3551357, "sgn-fsl", is_official_kwf_name = "https://www.facebook.com/reel/911167531341993", --TLCHANGE english_name = "Philippine Sign Language", --TLCHANGE } m["psq"] = { "Pasi", 7142091, "paa-sep", "Latn", } m["psr"] = { "Portuguese Sign Language", 3915472, "sgn", } m["pss"] = { "Kaulong", 3194294, "poz-ocw", } m["psw"] = { "Port Sandwich", 3398324, "poz-vnc", "Latn", } m["psy"] = { "Piscataway", 3504233, "alg-eas", } m["pta"] = { "Pai Tavytera", 7124619, "tup-gua", "Latn", } m["pth"] = { "Pataxó Hã-Ha-Hãe", 7144304, } m["pti"] = { "Pintiini", 10632026, "aus-pam", "Latn", } m["ptn"] = { "Patani", 7144242, "poz-hce", "Latn", } m["pto"] = { "Zo'é", 8073148, "tup-gua", "Latn", } m["ptp"] = { "Patep", 3368679, "poz-ocw", "Latn", } m["ptq"] = { "Pattapu", 60785085, "dra-tam", } m["ptr"] = { "Piamatsina", 7190040, "poz-vnn", "Latn", } m["ptt"] = { "Enrekang", 12953520, nil, "Latn", } m["ptu"] = { "Bambam", 4853321, "poz-ssw", "Latn", } m["ptv"] = { "Port Vato", 3398323, "poz-vnc", "Latn", } m["ptw"] = { "Pentlatch", 2069475, "sal", "Latn", } m["pty"] = { "Pathiya", 7144790, "dra-mal", } m["pua"] = { "Purepecha", 16114351, "qfa-iso", "Latn", sort_key = {remove_diacritics = c.acute}, } m["pub"] = { "Purum", 6400562, "tbq-kuk", "Latn", } m["puc"] = { "Punan Merap", 7259895, "poz", "Latn", } m["pud"] = { "Punan Aput", 4782333, "poz-swa", "Latn", } m["pue"] = { "Puelche", 33660, } m["puf"] = { "Punan Merah", 7259894, "poz-swa", "Latn", } m["pug"] = { "Phuie", 36375, "nic-gnw", } m["pui"] = { "Puinave", 3027918, nil, "Latn", } m["puj"] = { "Punan Tubu", 7259896, "poz-swa", "Latn", } m["pum"] = { "Puma", 33736, "sit-kic", } m["puo"] = { "Puoc", 6440803, "mkh", "Latn", } m["pup"] = { "Pulabu", 7259163, "ngf-rai", "Latn", } m["puq"] = { "Puquina", 1207739, } m["pur"] = { "Puruborá", 7261619, "tup", } m["put"] = { "Putoh", 12953832, "poz-swa", "Latn", } m["puu"] = { "Punu", 36401, "bnt-sir", "Latn", } m["puw"] = { "Puluwat", 36397, "poz-mic", "Latn", } m["pux"] = { "Puare", 3507983, "paa-shi", "Latn", } m["puy"] = { "Purisimeño", 2967638, "nai-chu", "Latn", } m["pwa"] = { "Pawaia", 7156099, "qfa-dis", -- Papuan; isolate in Glottolog; unclassified in Pawley and Hammarström (2018); sister to the Teberan -- languages by Usher (2020); tentatively TNG by Ross (2005) "Latn", } m["pwb"] = { "Panawa", 47385077, "nic-jer", "Latn", ancestors = "jer", } m["pwg"] = { "Gapapaiwa", 3095245, "poz-ocw", "Latn", } m["pwi"] = { "Patwin", 3370188, "nai-wtq", "Latn", } m["pwm"] = { "Molbog", --"Molbog" 6895718, "poz-san", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/molbog/", --TLCHANGE english_name = "Molbog", --TLCHANGE } m["pwn"] = { "Paiwan", 715755, "map", "Latn", } m["pwo"] = { "Western Pwo", 7988202, "kar", "Mymr", } m["pwr"] = { "Powari", 12640277, "inc-hie", "Deva", } m["pww"] = { "Northern Pwo", 7058885, "kar", "Thai", } m["pxm"] = { "Quetzaltepec Mixe", 6842374, "nai-miz", "Latn", } m["pye"] = { "Pye Krumen", 11157382, "kro-grb", } m["pym"] = { "Fyam", 3914025, "nic-ple", "Latn", } m["pyn"] = { "Poyanáwa", 3401023, "sai-pan", } m["pys"] = { "Paraguayan Sign Language", 7134698, "sgn", } m["pyu"] = { "Puyuma", 716690, "map", "Latn", } m["pyx"] = { "Pyu (Myanmar)", 36259, "sit", } m["pyy"] = { "Pyen", 7262966, "tbq-bis", } m["pzh"] = { "Pazeh", 36435, "map", "Latn", } m["pzn"] = { "Para Naga", 7133667, "sit-aao", } return require("Module:languages").finalizeData(m, "language") hrl3v1sdrx92h76pwn42f0e4rbja7r4 Module:languages/data/3/l 828 32646 178460 175589 2026-10-27T01:52:03Z GinawaSaHapon 3989 178460 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["laa"] = { "Subanën Lapuyan", --TLCHANGE 12635302, "phi", is_official_kwf_name = "https://kwfwikaatkultura.ph/subanen-2/", --TLCHANGE english_name = "Lapuyan Subanun", --TLCHANGE } m["lab"] = { "Linear A", nil, "qfa-unc", -- undeciphered "Lina", } m["lac"] = { "Lacandon", 35766, "myn", "Latn", } m["lad"] = { "Ladino", 36196, "roa-cas", "Hebr, Latn, Cyrl", -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["lae"] = { "Pattani", 7148323, "sit-whm", } m["laf"] = { "Lafofa", 35711, "alv", } m["lag"] = { "Langi", 584983, "bnt-mra", } m["lah"] = { "Lahnda", 1334774, "inc-pan", "pa-Arab", } m["lai"] = { "Lambya", 6481626, "bnt-mby", "Latn", } m["laj"] = { "Lango (Uganda)", 35670, "sdv-los", "Latn", } m["lak"] = { "Laka", 6474529, -- also Q55616620 "csu-sar", -- formerly classified as "alv-mbm"; see [[w:Lau Laka language]] } m["lam"] = { "Lamba", 36098, "bnt-sbi", "Latn", } m["lan"] = { "Laru", 3913987, "nic-knj", "Latn", } m["lap"] = { "Kabba-Laka", 6474528, "csu-sar", "Latn", } m["laq"] = { "Qabiao", 3436700, "qfa-kra", } m["lar"] = { "Larteh", 35639, "alv-gng", "Latn", } m["las"] = { "Gur Lama", 35652, "nic-gne", "Latn", } m["lau"] = { "Laba", 12952694, "paa-lla", "Latn", } m["law"] = { "Lauje", 6498258, "poz", "Latn", } m["lax"] = { "Tiwa", 7810466, "tbq-bdg", "Latn, as-Beng", } m["lay"] = { "Lama Bai", 6480756, "sit-nba", "Hani, Latn", sort_key = {Hani = "Hani-sortkey"}, } m["laz"] = { "Aribwatsa", 3502104, "poz-ocw", "Latn", } m["lbb"] = { "Label", 3214296, "poz-ocw", "Latn", } m["lbc"] = { "Lakkia", 3027879, "qfa-tak", } m["lbe"] = { "Lak", 36206, "cau-nec", "Cyrl, Latn, Arab, Geor", translit = { Cyrl = "lbe-translit", -- Geor translit in [[Module:scripts/data]] }, override_translit = true, display_text = {Cyrl = s["cau-Cyrl-displaytext"]}, strip_diacritics = { Cyrl = s["cau-Cyrl-stripdiacritics"], Latn = s["cau-Latn-stripdiacritics"], }, sort_key = "lbe-sortkey", } m["lbf"] = { "Tinani", 784502, "sit-whm", } m["lbg"] = { "Laopang", 12952711, "tbq-bis", } m["lbi"] = { "La'bi", 6460637, "alv-mbm", } m["lbj"] = { "Ladakhi", 35833, "sit-lab", "Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["lbk"] = { "Finontok", --"Central Bontoc", 63257803, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/finontok/", --TLCHANGE english_name = "Central Bontoc", --TLCHANGE } m["lbl"] = { "Bikol Libon", --TLCHANGE 18664462, "phi", "Latn", english_name = "Libon Bikol", --TLCHANGE } m["lbm"] = { "Lodhi", 6666374, "mun", } m["lbn"] = { "Lamet", 3216723, "mkh-pal", "Laoo, Latn", } m["lbo"] = { "Laven", 6298648, "mkh-ban", "Latn", } m["lbq"] = { "Wampar", 7966946, "poz-ocw", "Latn", } m["lbr"] = { "Kahilagaang Lorung", --TLCHANGE 6668040, "sit-kie", "Deva", english_name = "Northern Lorung", --TLCHANGE } m["lbs"] = { "Libyan Sign Language", 11775688, "sgn", } m["lbt"] = { "Lachi", 6583606, "qfa-kra", } m["lbu"] = { "Labu", 6467660, "poz-ocw", "Latn", } m["lbv"] = { "Lavatbura-Lamusong", 2405981, "poz-ocw", "Latn", } m["lbw"] = { "Tolaki", 3033597, "poz-btk", "Latn", } m["lbx"] = { "Lawangan", 3120345, "poz-bre", "Latn", } m["lby"] = { "Lamu-Lamu", 6482727, nil, "Latn", } m["lbz"] = { "Lardil", 3915688, "aus-tnk", "Latn", } m["lcc"] = { "Legenyem", 12952713, "poz-hce", "Latn", } m["lcd"] = { "Lola", 6668867, "poz-cet", "Latn", } m["lce"] = { "Loncong", 3058192, } m["lcf"] = { "Lubu", 3264685, } m["lch"] = { "Luchazi", 3265143, "bnt-clu", } m["lcl"] = { "Lisela", 6558753, "poz-cma", "Latn", } m["lcm"] = { "Tungag", 3542085, "poz-ocw", "Latn", } m["lcp"] = { "Kanluraning Lawa", --TLCHANGE 18644465, "mkh-pal", "Thai", sort_key = "Thai-sortkey", english_name = "Western Lawa", --TLCHANGE } m["lcq"] = { "Luhu", 6699890, "poz-cma", "Latn", } m["lcs"] = { "Lisabata-Nuniali", 6558534, } m["lda"] = { "Kla", 63257856, "dmn-mda", "Latn", } m["ldb"] = { "Idun", 3914441, "nic-plc", "Latn", } m["ldd"] = { "Luri (Nigeria)", 4701277, "cdc-wst", } m["ldg"] = { "Lenyima", 3914423, "nic-uce", "Latn", } m["ldh"] = { "Lamja-Dengsa-Tola", 11001739, "nic-dak", } m["ldj"] = { "Lemoro", 3912761, "nic-jer", } m["ldk"] = { "Leelau", 3914465, "alv-bwj", } m["ldl"] = { "Kaan", 3914501, "alv-yun", } m["ldm"] = { "Landoma", 35568, "alv-mel", } m["ldn"] = { "Láadan", 35757, "art", "Latn", type = "appendix-constructed", } m["ldo"] = { "Loo", 3915378, "alv-bwj", } m["ldp"] = { "Tso", 3913953, "alv-wjk", } m["ldq"] = { "Lufu", 35796, "nic-ykb", "Latn", } m["lea"] = { "Lega-Shabunda", 12952719, "bnt-lgb", } m["leb"] = { "Lala-Bisa", 6480112, "bnt-sbi", } m["lec"] = { "Leco", 2625398, "qfa-iso", } m["led"] = { "Lendu", 523823, "csu-lnd", "Latn", } m["lee"] = { "Lyélé", 3089032, "nic-gnn", } m["lef"] = { "Lelemi", 35585, "alv-ntg", } m["leh"] = { "Lenje", 6522666, "bnt-bot", } m["lei"] = { "Lemio", 6521165, "ngf-rai", "Latn", } m["lej"] = { "Lengola", 6522474, "bnt-leb", } m["lek"] = { "Leipon", 3229216, "poz-aay", "Latn", } m["lel"] = { "Lele (Congo)", 56733, "bnt-bsh", } m["lem"] = { "Nomaande", 13479983, "nic-mbw", "Latn", } m["len"] = { "Honduran Lenca", 36189, "nai-len", "Latn", } m["leo"] = { "Mengisa", 1345684, "nic-mba", ancestors = "bag", } m["lep"] = { "Lepcha", 35990, "sit", "Lepc", translit = "lep-translit", } m["leq"] = { "Lembena", 6521067, "ngf-enc", "Latn", } m["ler"] = { "Lenkau", 3229472, "poz-aay", "Latn", } m["les"] = { "Lese", 11033939, "csu-mle", } m["let"] = { "Lesing-Gelimi", 12635445, "poz-ocw", "Latn", } m["leu"] = { "Kara (New Guinea)", 3192889, "poz-ocw", "Latn", } m["lev"] = { "Lamma", 6583582, "paa-alp", "Latn", } m["lew"] = { -- this code was basically assigned as a catch-all for things that aren't brs, kzf or unz "Ledo Kaili", 35877, "poz-kal", "Latn", } m["lex"] = { "Luang", 6695015, "poz-tim", "Latn", } m["ley"] = { "Lemolang", 3033560, "poz-ssw", } m["lez"] = { "Lezgi", 31746, "cau-esm", "Cyrl, Latn, Arab", translit = "lez-translit", override_translit = true, display_text = {Cyrl = s["cau-Cyrl-displaytext"]}, strip_diacritics = { Cyrl = s["cau-Cyrl-stripdiacritics"], Latn = s["cau-Latn-stripdiacritics"], }, } m["lfa"] = { "Lefa", 35643, "bnt-baf", } m["lfn"] = { "Lingua Franca Nova", 146803, "art", "Latn, Cyrl", type = "appendix-constructed", } m["lga"] = { "Lungga", 3267590, "poz-ocw", "Latn", } m["lgb"] = { "Laghu", 3216169, "poz-ocw", "Latn", } m["lgg"] = { "Lugbara", 3272737, "csu-mma", "Latn", strip_diacritics = { remove_diacritics = c.acute .. c.grave, from = { "ä", "ɛ", "ë", "ï", "ɔ", "ö" }, to = { "a", "e", "i", "i", "o", "u" }, }, } m["lgh"] = { "Laghuu", 6472114, "tbq-muj", } m["lgi"] = { "Lengilu", 6522465, "poz-swa", "Latn", } m["lgk"] = { "Neverver", 3241515, "poz-vnc", "Latn", } m["lgl"] = { "Wala", 3565284, "poz-sls", } m["lgm"] = { "Lega-Mwenga", 14916883, "bnt-lgb", } m["lgn"] = { "Opuuo", 3354339, "ssa-kom", } m["lgq"] = { "Logba", 35813, "alv-ntg", "Latn", } m["lgr"] = { "Lengo", 3229454, "poz-sls", "Latn", } m["lgs"] = { "Guinea-Bissau Sign Language", 5616441, "sgn", } m["lgt"] = { "Pahi", 7124545, "paa-sep", "Latn", } m["lgu"] = { "Longgu", 3259105, "poz-sls", } m["lgz"] = { "Ligenza", 5531038, "bnt-bun", } m["lha"] = { "Laha (Vietnam)", 3112363, "qfa-kra", } m["lhh"] = { "Laha (Indonesia)", 6473107, "poz-cma", "Latn", } m["lhi"] = { "Lahu Shi", 25559457, "tbq-lho", } m["lhl"] = { "Lahul Lohar", 12953672, } m["lhn"] = { "Lahanan", 12953660, "poz-bnn", "Latn", } m["lhp"] = { "Lhokpu", 3436603, "sit-dhi", } m["lhs"] = { "Mlahsö", 3393063, "sem-cna", "Syrc", } m["lht"] = { "Lo-Toga", 3257566, "poz-vnn", "Latn", } m["lhu"] = { "Lahu", 35780, "tbq-lho", "Latn", } m["lia"] = { "West-Central Limba", 32867815, "alv-lim", } m["lib"] = { "Likum", 3240737, "poz-aay", "Latn", } m["lic"] = { "Hlai", 934738, "qfa-lic", "Latn", } m["lid"] = { "Nyindrou", 3346666, "poz-aay", "Latn", } m["lie"] = { "Likila", 11011614, "bnt-ngn", } m["lif"] = { "Limbu", 56477, "sit-kir", "Limb, Latn, Deva", translit = "lif-translit", } m["lig"] = { "Ligbi", 33594, "dmn-jje", } m["lih"] = { "Lihir", 6546938, "poz-ocw", "Latn", } m["lii"] = { "Lingkhim", 12635536, } m["lij"] = { "Liguryo", 36106, "roa-git", ancestors = "lij-old", "Latn", } m["lik"] = { "Lika", 1530394, "bnt-boa", } m["lil"] = { "Lillooet", 34154, "sal", "Latn", } m["lio"] = { "Liki", 4261493, "poz-ocw", "Latn", } m["lip"] = { "Sekpele", 36257, "alv-ntg", } m["liq"] = { "Libido", 35691, "cus-hec", } m["lir"] = { "Liberian Kreyol", 6541128, "crp", "Latn", ancestors = "en", } m["lis"] = { "Lisu", 56480, "tbq-lso", "Lisu, Latn", override_translit = true, -- Lisu translit, sort_key in [[Module:scripts/data]] } m["liu"] = { "Logorik", 6667811, "sdv-daj", } m["liv"] = { "Livonian", 33698, "urj-fin", "Latn", display_text = { from = {"'"}, to = {"’"} }, strip_diacritics = { remove_diacritics = "'’" .. u(0x2019), from = {"Ǭ", "ǭ"}, to = {"Ō", "ō"} }, sort_key = { from = { "ā", "ä", "ǟ", "ḑ", "ē", "ī", "ļ", "ņ", "ō", "ȯ", "ȱ", "õ", "ȭ", "ö", "ȫ", "ŗ", "š", "ț", "ū", "ü", "ṻ", "ȳ", "ž", }, to = { "a" .. p[1], "a" .. p[2], "a" .. p[3], "d" .. p[1], "e" .. p[1], "i" .. p[1], "l" .. p[1], "n" .. p[1], "o" .. p[1], "o" .. p[2], "o" .. p[3], "o" .. p[4], "o" .. p[5], "o" .. p[6], "o" .. p[7], "r" .. p[1], "s" .. p[1], "t" .. p[1], "u" .. p[1], "u" .. p[2], "u" .. p[3], "y" .. p[1], "z" .. p[1], } } } m["liw"] = { "Col", 2981948, } m["lix"] = { "Liabuku", 13580912, } m["liy"] = { "Banda-Bambari", 11051591, "bad-cnt", "Latn", } m["liz"] = { "Libinza", 4914576, "bnt-zbi", } m["lja"] = { "Golpa", 50934920, "aus-yol", "Latn", } m["lje"] = { "Rampi", 7290041, "poz", } m["lji"] = { "Laiyolo", 6474218, "poz-wot", "Latn", } m["ljl"] = { "Li'o", 2697010, "poz", "Latn", } m["ljp"] = { "Lampung Api", 49215, "poz-lgx", "Latn", } m["ljw"] = { "Yirandali", 17059380, } m["ljx"] = { "Yuru", 63257867, } m["lka"] = { "Lakalei", 12952700, "poz-tim", "Latn", } m["lkb"] = { "Kabras", 63257894, "bnt-msl", ancestors = "luy", } m["lkc"] = { "Kucong", 6441572, "tbq-lho", } m["lkd"] = { "Lakondê", 20527166, "sai-nmk", "Latn", } m["lke"] = { "Kenyi", 12952628, "bnt-nyg", } m["lkh"] = { "Lakha", 56606, "sit-tib", } m["lki"] = { "Laki", 56483, "ku", "fa-Arab", translit = "lki-translit", strip_diacritics = {remove_diacritics = c.kasra .. c.sukun}, } m["lkj"] = { "Remun", 7312239, "poz-mly", "Latn", } m["lkl"] = { "Laeko-Libuat", 3504331, "paa-trr", "Latn", } m["lkm"] = { "Kalaamaya", 6349988, } m["lkn"] = { "Lakon", 3216494, "poz-vnn", "Latn", } m["lko"] = { "Khayo", 6401095, "bnt-msl", } m["lkr"] = { "Päri", 36487, "sdv-lon", } m["lks"] = { "Kisa", 63259208, "bnt-msl", ancestors = "luy", } m["lkt"] = { "Lakota", 33537, "sio-dkt", "Latn", } m["lku"] = { "Kungkari", 6444526, } m["lky"] = { "Lokoya", 56687, "sdv-lma", } m["lla"] = { "Lala-Roba", 3914878, "alv-yun", } m["llb"] = { "Lolo", 11006056, "bnt-mak", ancestors = "vmw", } m["llc"] = { "Lele (Guinea)", 6520837, "dmn-mok", "Latn", } m["lld"] = { "Ladin", 36202, "roa-rhe", "Latn", } m["lle"] = { "Lele (New Guinea)", 3229269, "poz-aay", "Latn", } m["llf"] = { "Hermit", 3134240, "poz-aay", "Latn", } m["llg"] = { "Lole", 6668883, "poz-tim", } m["llh"] = { "Lamu", 6482736, "tbq-lso", } m["lli"] = { "Teke-Laali", 36543, "bnt-nze", } m["llj"] = { "Ladji-Ladji", 6512694, "aus-pam", "Latn", } m["llk"] = { "Lelak", 3229263, "poz-swa", "Latn", } m["lll"] = { "Lilau", 6547570, "paa-mon", "Latn", } m["llm"] = { "Lasalimu", 6492774, } m["lln"] = { "Lele (Chad)", 1641493, "cdc-est", } -- llo: retired by ISO in 2019 as duplicate of ngt (Kriang); removed from Wiktionary 2026-02-01 m["llp"] = { "North Efate", 3580152, "poz-vnc", "Latn", } m["llq"] = { "Lolak", 12953679, "phi", } m["lls"] = { "Lithuanian Sign Language", 3915480, "sgn", } m["llu"] = { "Lau", 3218574, "poz-sls", "Latn", } m["llx"] = { "Lauan", 35682, "poz-pcc", "Latn", } m["lma"] = { "East Limba", 11034212, "alv-lim", } m["lmb"] = { "Merei", 12952843, "poz-vnn", "Latn", } m["lmc"] = { "Limilngan", 6549414, nil, "Latn", } m["lmd"] = { "Lumun", 35777, "alv-tal", } m["lme"] = { "Pévé", 56249, "cdc-mas", "Latn", } m["lmf"] = { "Timog Lembata", --TLCHANGE 7567815, english_name = "South Lembata", --TLCHANGE } m["lmg"] = { "Lamogai", 278365, "poz-ocw", "Latn", } m["lmh"] = { "Lambichhong", 6481472, "sit-kie", ancestors = "ybh", } m["lmi"] = { "Lombi", 11259563, "csu-maa", } m["lmj"] = { "Kanlurang Lembata", --TLCHANGE 6864697, english_name = "West Lembata", --TLCHANGE } m["lmk"] = { "Lamkang", 12952703, "tbq-kuk", } m["lml"] = { "Raga", 3063193, "poz-vnn", "Latn", } m["lmn"] = { "Lambadi", 33474, "raj", "Latn", } m["lmo"] = { "Lombard", 33754, "roa-git", ancestors = "lmo-old", "Latn", } m["lmp"] = { "Limbum", 35801, "nic-nka", "Latn", } m["lmq"] = { "Lamatuka", 6480982, } m["lmr"] = { "Lamalera", 6480787, } m["lmu"] = { "Lamenu", 740604, "poz-vnc", "Latn", } m["lmv"] = { "Lomaiviti", 3130221, "poz-pcc", "Latn", } m["lmw"] = { "Lake Miwok", 3216471, "nai-utn", "Latn", } m["lmx"] = { "Laimbue", 6473933, "nic-rnw", } m["lmy"] = { "Laboya", 6481538, "poz-cet", "Latn", sort_key = "lmy-sortkey", } -- Lumbee [lmz] is spurious m["lna"] = { "Langbashe", 11137550, "bad", } m["lnb"] = { "Mbalanhu", 12952830, "bnt-ova", } m["lnd"] = { "Lun Bawang", 13479839, "poz-swa", "Latn", } m["lnh"] = { "Lanoh", 6487291, "mkh-asl", } m["lni"] = { "Daantanai'", 5207384, "paa-sbo", "Latn", } m["lnj"] = { "Linngithigh", 3915694, "aus-pmn", "Latn", } m["lnl"] = { "South Central Banda", 41354532, "bad", } m["lnm"] = { "Pondi", 6485678, "paa-wke", "Latn", } m["lnn"] = { "Lorediakarkar", 6680287, "poz-vnn", "Latn", } m["lno"] = { "Lango (Sudan)", 223306, "sdv-lma", } m["lns"] = { "Lamnso'", 35788, "nic-rng", } m["lnu"] = { "Longuda", 35797, "alv-bam", "Latn", } m["lnw"] = { "Lanima", 56825017, "aus-pam", "Latn", } m["loa"] = { "Loloda", 6669025, "paa-lla", "Latn", } m["lob"] = { "Lobi", 35807, } m["loc"] = { "Onhan", --"Inonhan", 2400870, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/onhan/", --TLCHANGE english_name = "Inonhan", --TLCHANGE } m["lod"] = { "Berawan", 4891018, "poz-swa", "Latn", } m["loe"] = { "Saluan", 12953867, "poz", "Latn", } m["lof"] = { "Logol", 35779, "alv-hei", } m["log"] = { "Logo", 2613477, "csu-mma", } m["loh"] = { "Narim", 56353, "sdv", } m["loi"] = { "Lomakka", 3913961, "alv-kul", } m["loj"] = { "Lou", 3260104, "poz-aay", "Latn", } m["lok"] = { "Loko", 3914912, "dmn-msw", "Latn", } m["lol"] = { "Mongo", 112893, "bnt-mon", "Latn", } m["lom"] = { "Loma", 35885, "dmn-msw", "Latn, Loma" } m["lon"] = { "Malawi Lomwe", 10975286, "bnt-mak", "Latn", } m["loo"] = { "Lombo", 11167192, "bnt-ske", } m["lop"] = { "Lopa", 3914875, } m["loq"] = { "Lobala", 4849710, "bnt-ngn", } m["lor"] = { "Téén", 36467, "alv-kul", } m["los"] = { "Loniu", 3259202, "poz-aay", "Latn", } m["lot"] = { "Lotuko", 56672, "sdv-lma", } m["lou"] = { "Louisiana Creole", 1185127, "crp", "Latn", ancestors = "fr", sort_key = s["roa-oil-sortkey"], } m["lov"] = { "Lopi", 12952740, "tbq-tal", } m["low"] = { "Tampias Lobu", 12953674, } m["lox"] = { "Loun", 6689636, "poz-cet", "Latn", } m["loz"] = { "Lozi", 33628, "bnt-sts", "Latn", } m["lpa"] = { "Lelepa", 3229273, "poz-vnc", "Latn", } m["lpe"] = { "Lepki", 4259152, "paa-lmu", "Latn", } m["lpn"] = { "Long Phuri Naga", 6673049, "sit-aao", } m["lpo"] = { "Lipo", 56921, "tbq-llo", "Plrd", } m["lpx"] = { "Lopit", 56684, "sdv-lma", } m["lra"] = { "Rara Bakati'", 3419746, "day", } m["lrc"] = { "Northern Luri", 19933293, "ira-swi", "fa-Arab", ancestors = "pal", } m["lre"] = { "Laurentian", 1790301, "iro-nor", "Latn", } m["lrg"] = { "Laragia", 2591193, } m["lri"] = { "Marachi", 6754565, "bnt-msl", } m["lrk"] = { "Loarki", 6663513, } m["lrl"] = { "Larestani", 33468, "ira-swi", "fa-Arab", } m["lrm"] = { "Marama", 6325931, "bnt-msl", ancestors = "luy", } m["lrn"] = { "Lorang", 6678781, } m["lro"] = { "Laro", 35687, "alv-hei", } m["lrr"] = { "Katimugang Lorung", --TLCHANGE 12952742, "sit-kie", english_name = "Southern Lorung", --TLCHANGE } m["lrt"] = { "Larantuka Malay", 6488691, "poz-mly", "Latn", } m["lrv"] = { "Larëvat", 3217892, "poz-vnc", "Latn", } m["lrz"] = { "Lemerig", 2028448, "poz-vnn", "Latn", } m["lsa"] = { "Lasgerdi", 3218296, "ira-kms", "Arab", } m["lsd"] = { "Lishana Deni", 3436461, "sem-nna", "Hebr", -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["lse"] = { "Lusengo", 6683546, "bnt-zbi", } m["lsh"] = { "Lish", 6558822, "sit-khc", } m["lsi"] = { "Lashi", 6493203, "tbq-brm", "Latn", } m["lsl"] = { "Latvian Sign Language", 6497414, "sgn", } m["lsm"] = { "Saamia", 3739441, "bnt-msl", } m["lsn"] = { "Tibetan Sign Language", 15936110, "sgn", } m["lso"] = { "Laos Sign Language", 6488022, "sgn", } m["lsp"] = { "Panamanian Sign Language", 7129968, "sgn", } m["lsr"] = { "Aruop", 3450566, "paa-pal", "Latn", } m["lss"] = { "Lasi", 12953669, "inc-snd", "Arab", ancestors = "sd", } m["lst"] = { "Trinidad and Tobago Sign Language", 7842495, "sgn", } m["lsv"] = { "Sivia Sign Language", 55558911, "sgn", } m["lsy"] = { "Mauritian Sign Language", 6793754, "sgn", } m["ltc"] = { "Gitnang Tsino", --TLCHANGE 2016252, "zhx", "Hant, Phag, Tang", translit = {Hant = "zh-translit"}, -- Tang translit in [[Module:scripts/data]]; NOTE: Previously not present, presumably an accidental omission. sort_key = {Hant = "Hani-sortkey"}, english_name = "Middle Chinese", --TLCHANGE } m["ltg"] = { "Latgalian", 36212, "bat-eas", "Latn", } m["lti"] = { "Leti", 3236912, "poz-tim", "Latn", } m["ltn"] = { "Latundê", 63259736, "sai-nmk", "Latn", } m["lto"] = { "Olutsotso", 63259915, "bnt-msl", ancestors = "luy", } m["lts"] = { "Lutachoni", 63283459, "bnt-msl", } m["ltu"] = { "Latu", 6497181, "poz-cma", } m["lua"] = { "Luba-Kasai", 34173, "bnt-lub", "Latn", } m["luc"] = { "Aringa", 56556, "csu-mma", "Latn", } m["lud"] = { "Ludian", 33918, "urj-fin", "Latn", display_text = { from = {"'"}, to = {"ʹ"} }, strip_diacritics = { from = {"'"}, to = {"ʹ"} }, sort_key = { from = { "č", "š", "ž", "ü", "ä", "ö", -- 2 chars "z", "ʹ" -- 1 char }, to = { "c" .. p[1], "s" .. p[1], "s" .. p[3], "y" .. p[1], "y" .. p[2], "y" .. p[3], "s" .. p[2], "y" .. p[4], } }, } m["lue"] = { "Luvale", 33597, "bnt-clu", "Latn", } m["luf"] = { "Laua", 6497673, "paa-mal", "Latn", } m["luh"] = { "Leizhou Min", 1988433, "zhx-nan", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["lui"] = { "Luiseño", 56236, "azc-cup", "Latn", strip_diacritics = {remove_diacritics = c.acute .. c.circ}, } m["luj"] = { "Luna", 11003832, "bnt-lbn", } m["luk"] = { "Lunanakha", 56446, "sit-tib", "Tibt", ancestors = "dz", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["lul"] = { "Olu'bo", 6589401, "csu-mma", } m["lum"] = { "Luimbi", 10963134, "bnt-clu", } m["lun"] = { "Lunda", 33607, "bnt-lun", "Latn", } m["luo"] = { "Luo", 5414796, "sdv-los", "Latn", } m["lup"] = { "Lumbu", 35793, "bnt-sir", } m["luq"] = { "Lucumí", 1768321, "alv-yor", "Latn", ancestors = "yo", sort_key = { remove_diacritics = c.acute, }, } m["lur"] = { "Laura", 2984540, } m["lus"] = { "Mizo", 36147, "tbq-kuk", "Latn", } m["lut"] = { "Lushootseed", 33658, "sal", "Latn", } m["luu"] = { "Lumba-Yakkha", 6703050, "sit-kie", ancestors = "ybh", } m["luv"] = { "Luwati", 33402, "inc-snd", "Khoj", } m["luy"] = { "Luhya", 35893, "bnt-msl", "Latn", } m["luz"] = { "Katimugang Luri", --TLCHANGE 12952748, "ira-swi", "fa-Arab", ancestors = "pal", english_name = "Southern Luri", --TLCHANGE } m["lva"] = { "Maku'a", 35790, "poz-tim", } m["lvi"] = { "Lawi", 6502657, "mkh-ban", "Latn", } m["lvk"] = { "Lavukaleve", 770547, "qfa-dis", -- Papuan; isolate in Glottolog; in the tentative Central Solomons family by Ross (2005) and Pedrós -- (2015) "Latn", } m["lvl"] = { "Lwel", 93936908, "bnt-bdz", "Latn", } m["lvu"] = { "Levuka", 6535860, } m["lwa"] = { "Lwalu", 6706953, "bnt-lbn", } m["lwe"] = { "Lewo Eleng", 6537465, } m["lwg"] = { "Wanga", nil, "bnt-msl", ancestors = "luy", } m["lwh"] = { "White Lachi", 8842956, "qfa-kra", } m["lwl"] = { "Silanganang Lawa", --TLCHANGE 18644464, "mkh-pal", "Thai", sort_key = "Thai-sortkey", english_name = "Eastern Lawa", --TLCHANGE } m["lwm"] = { "Laomian", 19597674, "tbq-bis", } m["lwo"] = { "Luwo", 56362, "sdv-lon", "Latn", } m["lws"] = { "Malawian Sign Language", 47522462, "sgn", } m["lwt"] = { "Lewotobi", 14916885, } m["lwu"] = { "Lawu", 6505073, "tbq-lwo", } m["lww"] = { "Lewo", 3237321, "poz-vnc", "Latn", } m["lya"] = { "Layakha", 56602, "sit-tib", "Tibt", ancestors = "dz", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["lyg"] = { "Lyngngam", 12635902, "aav-pkl", } m["lyn"] = { "Luyana", 3268098, } m["lzh"] = { "Pampanitikang Tsino", --TLCHANGE 37041, "zhx", "Hant", wikimedia_codes = "zh-classical", translit = "zh-translit", sort_key = "Hani-sortkey", english_name = "Literary Chinese", --TLCHANGE } m["lzl"] = { "Litzlitz", 6653424, "poz-vnc", "Latn", } m["lzn"] = { "Leinong Naga", 5924455, "sit-kch", } m["lzz"] = { "Laz", 1160372, "ccs-zan", "Geor, Latn", translit = {Geor = "lzz-translit"}, override_translit = true, strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ}, } return require("Module:languages").finalizeData(m, "language") snfj9gwzq9d5symjca4998c56vth2oj Module:languages/data/3/n 828 32648 178465 178385 2026-10-27T02:10:42Z GinawaSaHapon 3989 178465 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["naa"] = { "Namla", 3508760, "paa-nto", "Latn", } m["nab"] = { "Nambikwara", 2068190, "sai-nmk", "Latn", } m["nac"] = { "Narak", 6965295, "ngf-jim", "Latn", } m["nae"] = { "Naka'ela", 6960073, "poz", "Latn", } m["naf"] = { "Nabak", 11732491, "ngf-san", "Latn", } m["nag"] = { "Naga Pidgin", 3503454, "crp", "Latn", ancestors = "as", } m["nah"] = { "Nahuatl", 13300, "azc-nah", "Latn", } m["naj"] = { "Nalu", 36026, "alv-nal", "Latn", } m["nak"] = { "Nakanai", 6528669, "poz-ocw", "Latn", } m["nal"] = { "Nalik", 3335387, "poz-ocw", "Latn", } m["nam"] = { "Ngan'gityemerri", 3298041, "aus-dal", "Latn", } -- Being converted into the family "Southern Min" ("zhx-nan", which will take the code "nan" once the language can be removed). Retain the name "Min Nan" here to avoid having to move things that are scheduled for deletion anyway. m["nan"] = { "Min Nan", 36495, "zhx-com", "Hants, Latn, Bopo, Kana", wikimedia_codes = "zh-min-nan", generate_forms = "zh-generateforms", sort_key = { Hani = "Hani-sortkey", Kana = "Kana-sortkey" }, } m["nao"] = { "Naaba", 11883865, "sit-tib", ancestors = "xct", } m["nap"] = { "Napolitano", 33845, "roa-itr", ancestors = "nap-old", "Latn", } m["naq"] = { "Khoekhoe", 13301, "khi-khk", "Latn", } m["nar"] = { "Iguta", 5621686, "nic-jer", "Latn", } m["nas"] = { "Nasioi", 56772, "paa-sbo", "Latn", } m["nat"] = { "Hungworo", 3914395, "nic-kmk", "Latn", } m["naw"] = { "Nawuri", 35906, "alv-gng", "Latn", } m["nax"] = { "Nakwi", 3504178, "paa-lma", "Latn", } m["nay"] = { "Ngarrindjeri", 7022091, "aus-pam", "Latn", } m["naz"] = { "Coatepec Nahuatl", 5138605, "azc-nah", "Latn", } m["nba"] = { "Nyemba", 3346655, "bnt-clu", "Latn", ancestors = "lch", } m["nbb"] = { "Ndoe", 36134, "nic-eko", "Latn", } m["nbc"] = { "Chang", 5071694, "sit-kch", "Latn", } m["nbd"] = { "Ngbinda", 11132859, "bnt-boa", "Latn", } m["nbe"] = { "Konyak Naga", 6430448, "sit-kch", "Latn", } m["nbg"] = { "Nagarchal", 13299, "dra-gon", } m["nbh"] = { "Ngamo", 3438705, "cdc-wst", "Latn", } m["nbi"] = { "Mao Naga", 12952905, "tbq-anp", "Latn", } m["nbj"] = { "Ngarinman", 10600380, nil, "Latn", } m["nbk"] = { "Nake", 11732496, "ngf-han", "Latn", } m["nbm"] = { "Ngbaka Ma'bo", 3915331, "nic-nkm", "Latn", } m["nbn"] = { "Kuri", 3200540, "poz", "Latn", } m["nbo"] = { "Nkukoli", 3914482, "nic-uce", "Latn", } m["nbp"] = { "Nnam", 36138, "nic-eko", "Latn", } m["nbq"] = { "Nggem", 12952956, "ngf-dan", "Latn", } m["nbr"] = { "Numana", 5529310, "nic-nin", "Latn", } m["nbs"] = { "Namibian Sign Language", 6961792, "sgn", "Latn", -- when documented } m["nbt"] = { "Na", 12952895, "sit-tan", "Deva, Latn", } m["nbu"] = { "Rongmei Naga", 12952912, "sit-zem", "Latn", } m["nbv"] = { "Ngamambo", 11129694, "nic-mom", "Latn", } m["nbw"] = { "Southern Ngbandi", 17522635, "nic-ngd", "Latn", } m["nby"] = { "Ningera", 11732524, "paa-bew", "Latn", } m["nca"] = { "Iyo", 6101336, "ngf-gmo", "Latn", } m["ncb"] = { "Central Nicobarese", 3335553, "aav-nic", "Deva, Latn", } m["ncc"] = { "Ponam", 3396122, "poz-aay", "Latn", } m["ncd"] = { "Nachering", 6957144, "sit-kic", "Deva", } m["nce"] = { "Yale", 2992915, "qfa-dis", -- Papuan; isolate in Glottolog and Palmer (2018); under proposed Senu River family in Usher (2020) "Latn", } m["ncf"] = { "Notsi", 3344784, "poz-ocw", "Latn", } m["ncg"] = { "Nisga'a", 3342138, "nai-tsi", "Latn", } m["nch"] = { "Central Huasteca Nahuatl", 2194290, "azc-hua", "Latn", } m["nci"] = { "Classical Nahuatl", 559242, "azc-nah", "Latn", strip_diacritics = {remove_diacritics = c.macron}, } m["ncj"] = { "Northern Puebla Nahuatl", 15705671, "azc-nah", "Latn", } m["nck"] = { "Nakara", 6960662, "aus-arn", "Latn", } m["ncl"] = { "Michoacán Nahuatl", 2896217, "azc-nah", "Latn", } m["ncm"] = { "Nambo", 42173731, "paa-nam", "Latn", } m["ncn"] = { "Nauna", 3337158, "poz-aay", "Latn", } m["nco"] = { "Sibe", 56806, "paa-sbo", "Latn", } m["ncr"] = { "Ncane", 11297920, "nic-bbe", "Latn", ancestors = "nhu", } m["ncs"] = { "Nicaraguan Sign Language", 33765, "sgn", "Sgnw", } m["nct"] = { "Chothe Naga", 5105385, "tbq-kuk", "Beng, Latn", } m["ncu"] = { "Chumburung", 35198, "alv-gng", "Latn", } m["ncx"] = { "Central Puebla Nahuatl", 5061727, "azc-nah", "Latn", } m["ncz"] = { "Natchez", 3111838, nil, "Latn", } m["nda"] = { "Ndasa", 35904, "bnt-kel", "Latn", } m["ndb"] = { "Kenswei Nsei", 7067553, "nic-rnn", "Latn", } m["ndc"] = { "Ndau", 13311, "bnt-sho", "Latn", } m["ndd"] = { "Nde-Nsele-Nta", 36131, "nic-eko", "Latn", } m["ndf"] = { "Nadruvian", 6957967, nil, "Latn", } m["ndg"] = { "Ndengereko", 6983726, "bnt-mbi", "Latn", } m["ndh"] = { "Ndali", 6983678, "bnt-run", "Latn", } m["ndi"] = { "Chamba Leko", 36381, "alv-lek", "Latn", } m["ndj"] = { "Ndamba", 6983684, "bnt-kil", "Latn", } m["ndk"] = { "Ndaka", 11164947, "bnt-nya", "Latn", } m["ndl"] = { "Ndolo", 6983788, "bnt-zbi", "Latn", ancestors = "lse", } m["ndm"] = { "Ndam", 56283, "cdc-est", "Latn", } m["ndn"] = { "Ngundi", 35916, "bnt-ngn", "Latn", } m["ndp"] = { "Ndo", 6983774, "csu-mle", "Latn", } m["ndq"] = { "Ndombe", 6983792, "bnt-swb", "Latn", } m["ndr"] = { "Ndoola", 35837, "nic-mmb", "Latn", } m["nds"] = { "Low German", 25433, "gmw-lgm", "Latn", ancestors = "gml", } m["ndt"] = { "Ndunga", 6983857, "nic-mbc", "Latn", } m["ndu"] = { "Dugun", 11015189, "alv-dur", "Latn", } m["ndv"] = { "Ndut", 36028, "alv-cng", "Latn", } m["ndw"] = { "Ndobo", 11008568, "bnt-ngn", "Latn", } m["ndx"] = { "Nduga", 6983833, "ngf-ngn", "Latn", } m["ndy"] = { "Lutos", 6705910, "csu-val", "Latn", } m["ndz"] = { "Ndogo", 35983, "nic-ser", "Latn", } m["nea"] = { "Eastern Ngad'a", 12473454, "poz-cet", "Latn", } m["neb"] = { "Toura", 7853636, "dmn-mda", "Latn", } m["nec"] = { "Nedebang", 4925378, "paa-alp", "Latn", } m["ned"] = { "Nde-Gbite", 11010279, "nic-grf", } m["nee"] = { "Kumak", 3347266, "poz-cln", "Latn", } m["nef"] = { "Nefamese", 6987002, "crp", } m["neg"] = { "Negidal", 33676, "tuw-ewe", "Cyrl", } m["neh"] = { "Nyenkha", 3695185, "sit-ebo", "Tibt, Latn", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["nej"] = { "Neko", 6989840, "ngf-gmo", "Latn", } m["nek"] = { "Neku", 14916900, "poz-cln", } m["nem"] = { "Nemi", 3338008, "poz-cln", "Latn", } m["nen"] = { "Nengone", 3338052, "poz-cln", "Latn", } m["neo"] = { "Ná-Meo", 15977293, "hmn", } m["neq"] = { "North Central Mixe", 25559729, nil, "Latn", } m["ner"] = { "Yahadian", 8046778, nil, "Latn", } m["nes"] = { "Bhoti Kinnauri", 21179921, "sit-las", } m["net"] = { "Nete", 6998869, "ngf-oen", "Latn", } m["neu"] = { "Neo", 606917, "art", "Latn", type = "appendix-constructed", } m["nev"] = { "Nyaheun", 7070801, "mkh-ban", } m["new"] = { "Newar", 33979, "sit-new", "Deva, Newa, Ranj", ancestors = "nwx", translit = { Deva = "new-translit", Newa = "new-Newa-translit", }, } m["nex"] = { "Neme", 12952941, "paa-nam", "Latn", } m["ney"] = { "Neyo", 36410, "kro", } m["nez"] = { "Nez Perce", 3339226, "nai-shp", "Latn", } m["nfa"] = { "Dhao", 2053828, "poz", "Latn", } m["nfd"] = { "Ahwai", 3913957, "nic-plt", "Latn", } m["nfl"] = { "Äiwoo", 56742, "poz-tem", "Latn", } m["nfr"] = { "Nafaanra", 13297, "alv-snf", "Latn", } m["nfu"] = { "Mfumte", 6826794, "nic-nka", "Latn", } m["nga"] = { "Ngbaka", 36022, "gba-eas", "Latn", } m["ngb"] = { "Northern Ngbandi", 17522631, "nic-ngd", "Latn", } m["ngc"] = { "Ngombe (Congo)", 3123524, "bnt-bun", } m["ngd"] = { "Ngando (Central African Republic)", 35910, "bnt-ngn", } m["nge"] = { "Ngemba", 6750551, "nic-nge", "Latn", } m["ngg"] = { -- compare 'aiy' "Ngbaka Manza", 11033316, "gba-eas", "Latn", } m["ngh"] = { "Nǀuu", 2618974, "khi-tuu", "Latn", } m["ngi"] = { "Ngizim", 3914924, "cdc-wst", "Latn", } m["ngj"] = { "Ngie", 36361, "nic-mom", "Latn", } m["ngk"] = { "Ngalkbun", 3913790, "aus-gun", "Latn", } m["ngl"] = { "Lomwe", 35824, "bnt-mak", "Latn", } m["ngm"] = { "Ngatik Men's Creole", 36400, "crp", ancestors = "en, pon", } m["ngn"] = { "Ngwo", 36051, "nic-mom", "Latn", } m["ngo"] = { "Ngoni", 7022547, "bnt-ngu", "Latn", } m["ngp"] = { "Ngulu", 7193332, "bnt-seu", "Latn", } m["ngq"] = { "Ngoreme", 7022573, "bnt-lok", "Latn", } m["ngr"] = { "Nagu", 3063524, "poz-tem", "Latn", } m["ngs"] = { "Gvoko", 3441188, "cdc-cbm", "Latn", } m["ngt"] = { "Ngeq", 25559548, "mkh-kat", } m["ngu"] = { "Guerrero Nahuatl", 5614980, "azc-nah", "Latn", } m["ngv"] = { "Nagumi", 35842, "nic-jrn", } m["ngw"] = { "Ngwaba", 3440480, "cdc-cbm", "Latn", } m["ngx"] = { "Nggwahyi", 56265, "cdc-cbm", "Latn", } m["ngy"] = { "Tibea", 36598, "bnt-baf", "Latn", } m["ngz"] = { "Ngungwel", 35920, "bnt-tkc", "Latn", } m["nha"] = { "Nhanda", 3339380, "aus-psw", "Latn", } m["nhb"] = { "Beng", 3913311, "dmn-nbe", "Latn", } m["nhc"] = { "Tabasco Nahuatl", 6047326, "azc-nah", "Latn", } m["nhd"] = { "Chiripá", 2873230, "gn", "Latn", } m["nhe"] = { "Nahuatl ng Silangang Huasteca", -- "Eastern Huasteca Nahuatl", 4358289, "azc-hua", "Latn", } m["nhf"] = { "Nhuwala", 10600396, "aus-nga", "Latn", } m["nhg"] = { "Tetelcingo Nahuatl", 3450252, "azc-nah", "Latn", } m["nhh"] = { "Nahari", 6583560, "inc-hal", } m["nhi"] = { "Nahuatl ng Zacatlán-Ahuacatlán-Tepetzintla", 12953764, "azc-nah", "Latn", } m["nhk"] = { "Nahuatl ng Cosoleacaque", 12953757, "azc-nah", "Latn", } m["nhm"] = { "Nahuatl ng Morelos", 4800819, "azc-nah", "Latn", } m["nhn"] = { "Gitnang Nahuatl", 6047309, "azc-nah", "Latn", } m["nho"] = { "Takuu", 3409818, "poz-pnp", "Latn", } m["nhp"] = { "Pajapan Nahuatl", 12953760, "azc-nah", "Latn", } m["nhq"] = { "Huaxcaleca Nahuatl", 12953758, "azc-nah", "Latn", } m["nhr"] = { "Naro", 2164778, "khi-kal", "Latn", } m["nht"] = { "Ometepec Nahuatl", 7090132, "azc-nah", "Latn", } m["nhu"] = { "Noone", 36072, "nic-bbe", "Latn", } m["nhv"] = { "Temascaltepec Nahuatl", 2379405, "azc-nah", "Latn", } m["nhw"] = { "Western Huasteca Nahuatl", 2678840, "azc-hua", "Latn", } m["nhx"] = { "Mecayapan Nahuatl", 12953756, "azc-nah", "Latn", } m["nhy"] = { "Northern Oaxaca Nahuatl", 12953763, "azc-nah", "Latn", } m["nhz"] = { "Santa María La Alta Nahuatl", 15705753, "azc-nah", "Latn", } m["nia"] = { "Nias", 2407831, "poz-nws", "Latn", } m["nib"] = { "Nakame", 11732495, "ngf-boa", "Latn", } m["nid"] = { "Ngandi", 7021977, "aus-arn", "Latn", } m["nie"] = { "Niellim", 33662, "alv-bua", } m["nif"] = { "Nek", 6989781, "ngf-boa", "Latn", } m["nig"] = { "Ngalakan", 3913796, "aus-gun", "Latn", } m["nih"] = { "Nyiha", 11128374, "bnt-mby", "Latn", } m["nii"] = { "Nii", 35237, "ngf-wah", "Latn", } m["nij"] = { "Ngaju", 2992872, "poz-brw", "Latn", } m["nik"] = { "Southern Nicobarese", 7570194, "aav-nic", } m["nil"] = { "Nila", 7036821, } m["nim"] = { "Nilamba", 4121200, "bnt-tkm", "Latn", } m["nin"] = { "Ninzo", 3914021, "nic-nin", } m["nio"] = { "Nganasan", 36743, "syd", "Cyrl", translit = "nio-translit", } m["niq"] = { "Nandi", 6956591, "sdv-nma", "Latn", } m["nir"] = { "Nimboran", 301116, "paa-nim", "Latn", } m["nis"] = { "Nimi", 11732523, "ngf-era", "Latn", } m["nit"] = { "Southeastern Kolami", 56767, "dra-knk", "Deva, Telu", translit = { Telu = "te-translit" }, } m["niu"] = { "Niuean", 33790, "poz-ton", "Latn", } m["niv"] = { "Nivkh", 36464, "qfa-iso", "Cyrl, Latn", translit = "niv-translit", strip_diacritics = { from = {"['’]"}, to = {"ʼ"} }, sort_key = "niv-sortkey", } m["niw"] = { "Nimo", 3504126, "paa-lma", "Latn", } m["nix"] = { "Hema", 5710904, "bnt-nyg", "Latn", } m["niy"] = { "Ngiti", 7022396, "csu-lnd", } m["niz"] = { "Ningil", 11732527, "paa-wap", "Latn", } m["nja"] = { "Nzanyi", 3441299, "cdc-cbm", "Latn", } m["njb"] = { "Nocte", 7046410, "sit-tno", } m["njh"] = { "Lotha Naga", 33590, "sit-aao", } m["nji"] = { "Gudanji", 3915692, "aus-mir", "Latn", } m["njj"] = { "Njen", 36112, "nic-mom", "Latn", } m["njl"] = { "Njalgulgule", 7071229, "sdv-daj", } m["njm"] = { "Angami", 56761, "tbq-anp", "Latn", } m["njn"] = { "Liangmai Naga", 14194500, "sit-zem", "Latn", } m["njo"] = { "Ao", 28433, "sit-aao", "Latn", } m["njr"] = { "Njerep", 35844, "nic-mmb", "Latn", } m["njs"] = { "Nisa", 13593518, "paa-egb", "Latn", } m["njt"] = { "Ndyuka-Trio Pidgin", 13591205, "crp", ancestors = "djk, tri", } m["nju"] = { "Ngadjunmaya", 7021846, "aus-pam", "Latn", } m["njx"] = { "Kunyi", 3196559, "bnt-kng", "Latn", } m["njy"] = { "Njyem", 35898, "bnt-ndb", "Latn", } m["njz"] = { "Nyishi", 56870, "sit-tan", "Latn", } m["nka"] = { "Nkoya", 7042633, "bnt-lbn", "Latn", } m["nkb"] = { "Khoibu Naga", 21481876, "sit-mar", } m["nkc"] = { "Nkongho", 35863, "bnt-saw", "Latn", } m["nkd"] = { "Koireng", 6426342, "sit-zem", } m["nke"] = { "Duke", 3041075, "poz-ocw", "Latn", } m["nkf"] = { "Inpui Naga", 21481817, "sit-zem", } m["nkg"] = { "Nekgini", 11732509, "ngf-gmo", "Latn", } m["nkh"] = { "Khezha Naga", 6401519, "tbq-anp", } m["nki"] = { "Thangal Naga", 56374, "sit-zem", } m["nkj"] = { "Nakai", 14916897, "ngf-tna", "Latn", } m["nkk"] = { "Nokuku", 7048122, "poz-vnn", "Latn", } m["nkm"] = { "Namat", 15634505, "paa-nam", "Latn", } m["nkn"] = { "Nkangala", 10962292, "bnt-clu", "Latn", ancestors = "mck", } m["nko"] = { "Nkonya", 35867, "alv-gng", "Latn", } m["nkp"] = { "Niuatoputapu", 3399095, "poz-pnp", "Latn", } m["nkq"] = { "Nkami", 7042522, "alv-gng", "Latn", } m["nkr"] = { "Nukuoro", 2635961, "poz-pnp", "Latn", } m["nks"] = { "North Asmat", 11732049, "ngf-asm", "Latn", } m["nkt"] = { "Nyika", 16917497, "bnt-mwi", "Latn", } m["nku"] = { "Bouna Kulango", 20668241, "alv-kul", } -- nkv is treated as nkt, see [[WT:LT]] m["nkw"] = { "Nkutu", 7193313, "bnt-tet", "Latn", } m["nkx"] = { "Nkoroo", 36000, "ijo", } m["nkz"] = { "Nkari", 11130307, "nic-ief", ancestors = "ibr", } m["nla"] = { "Ngombale", 36292, "bai", "Latn", } m["nlc"] = { "Nalca", 6960839, "ngf-mek", "Latn", } m["nle"] = { "East Nyala", 25559347, "bnt-msl", "Latn", ancestors = "luy", } m["nlg"] = { "Gela", 3063531, "poz-sls", "Latn", } m["nli"] = { "Grangali", 3444203, "inc-kun", "Arab", } m["nlj"] = { "Nyali", 7070830, "bnt-nya", "Latn", } m["nlk"] = { "Ninia Yali", 12953310, "ngf-yal", "Latn", } m["nll"] = { "Nihali", 33904, "qfa-iso", "Deva, Latn", } m["nlm"] = { "Mankiyali", 47522426, "inc-koh", } m["nlo"] = { "Ngul", 35894, "bnt-bdz", "Latn", } m["nlq"] = { "Lao Naga", 63283609, "sit-tno", } m["nlu"] = { "Nchumbulu", 36143, "alv-gng", "Latn", } m["nlv"] = { "Orizaba Nahuatl", 3086050, "azc-nah", "Latn", } m["nlw"] = { "Walangama", 7961277, } m["nlx"] = { "Nahali", 33361, "inc-bhi", } m["nly"] = { "Nyamal", 7070837, "aus-nga", "Latn", } m["nlz"] = { "Nalögo", 20527138, "poz-tem", "Latn", } m["nma"] = { "Maram Naga", 56378, "sit-zem", } m["nmb"] = { "Big Nambas", 2902304, "poz-vnc", "Latn", } m["nmc"] = { "Ngam", 3915446, "csu-sar", "Latn", } m["nmd"] = { "Ndumu", 35901, "bnt-mbt", "Latn", } m["nme"] = { "Mzieme Naga", 6949473, "sit-zem", } m["nmf"] = { "Tangkhul Naga", 7682992, "sit-tng", "Latn, Mtei", } m["nmg"] = { "Kwasio", 34098, "bnt-mnj", "Latn", } m["nmh"] = { "Monsang Naga", 6902496, } m["nmi"] = { "Nyam", 3438738, "cdc-wst", "Latn", } m["nmj"] = { "Ngombe (Central African Republic)", 3913949, "gba-sou", } m["nmk"] = { "Namakura", 3335410, "poz-vnc", "Latn", } m["nml"] = { "Ndemli", 36089, "nic-grf", "Latn", } m["nmm"] = { "Manangba", 6746900, "sit-tam", "Tibt, Deva", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["nmn"] = { "ǃXóõ", 13229, "khi-tuu", "Latn", } m["nmo"] = { "Moyon Naga", 6927748, "tbq-kuk", } m["nmp"] = { "Nimanbur", 16891606, } m["nmq"] = { "Nambya", 11008869, "bnt-sho", "Latn", } m["nmr"] = { "Nimbari", 36069, "alv-lni", } m["nms"] = { "Letemboi", 3236886, "poz-vnc", "Latn", } m["nmt"] = { "Namonuito", 12908815, "poz-mic", } m["nmu"] = { "Northeast Maidu", 3278074, "nai-mdu", "Latn", } m["nmv"] = { "Ngamini", 7021944, "aus-kar", "Latn", } m["nmw"] = { "Nimoa", 7037729, "poz-ocw", "Latn", } m["nmx"] = { "Nama", 20812287, "paa-nam", "Latn", } m["nmy"] = { "Namuyi", 56844, "sit-nax", "Latn", } m["nmz"] = { "Nawdm", 36085, "nic-yon", "Latn", } m["nna"] = { "Nyangumarta", 33653, } m["nnb"] = { "Nande", 3196953, "bnt-glb", "Latn", } m["nnc"] = { "Nancere", 3140491, "cdc-est", "Latn", } m["nnd"] = { "West Ambae", 2841479, "poz-vnn", "Latn", } m["nne"] = { "Ngandyera", 10961003, "bnt-ova", "Latn", } m["nnf"] = { "Ngaing", 11732510, "ngf-gmo", "Latn", } m["nng"] = { "Maring Naga", 12952908, "sit-mar", } m["nnh"] = { "Ngiemboon", 36286, "bai", "Latn", } m["nni"] = { "North Nuaulu", 12952968, "poz-cma", } m["nnj"] = { "Nyangatom", 4662604, "sdv-ttu", } m["nnk"] = { "Nankina", 11732502, "ngf-yup", "Latn", } m["nnl"] = { "Northern Rengma Naga", 7067615, "tbq-anp", } m["nnm"] = { "Namia", 56363, "paa-sep", "Latn", } m["nnn"] = { "Ngete", 56625, "cdc-mas", "Latn", } m["nnp"] = { "Wancho", 7967085, "sit-kch", "Wcho, Deva, Latn", } m["nnq"] = { "Ngindo", 7022366, "bnt-mbi", "Latn", } m["nnr"] = { "Narungga", 13591127, "aus-pam", "Latn", } m["nnt"] = { "Nanticoke", 3915517, "alg-eas", "Latn", } m["nnu"] = { "Dwang", 35258, "alv-gng", "Latn", } m["nnv"] = { "Nukunu", 10604066, nil, "Latn", } m["nnw"] = { "Southern Nuni", 11152248, "nic-gnn", "Latn", } m["nnx"] = { "Ngong", 12952915, } m["nny"] = { -- contrast aus-ynk "Nyangga", 10604331, "aus-tnk", "Latn", } m["nnz"] = { "Nda'nda'", 36016, "bai", "Latn", } m["noa"] = { "Woun Meu", 3111873, "sai-chc", "Latn", } m["noc"] = { "Nuk", 11732534, "ngf-boa", "Latn", } m["nod"] = { "Northern Thai", 565110, "tai-swe", "Lana, Thai", strip_diacritics = {remove_diacritics = c.ZWNJ}, sort_key = { Lana = "Lana-sortkey", Thai = "Thai-sortkey" }, } m["noe"] = { "Nimadi", 3502294, "raj", "Deva", translit = "hi-translit", } m["nof"] = { "Nomane", 11732531, "ngf-sim", "Latn", } m["nog"] = { "Nogai", 33871, "trk-kno", "Cyrl, Arab, Latn", translit = "nog-translit", override_translit = true, } m["noh"] = { "Nomu", 11732532, "ngf-dal", "Latn", } m["noi"] = { "Noiri", 12953774, "inc-bhi", } m["noj"] = { "Nonuya", 5372139, "sai-wit", "Latn", } m["nok"] = { "Nooksack", 3343396, "sal", } m["nol"] = { "Nomlaki", 3343229, "nai-wtq", "Latn", } m["nom"] = { "Nocamán", 7046289, "sai-pan", "Latn", } m["non"] = { "Old Norse", 35505, "gmq", "Latn, Runr", translit = {Runr = "Runr-translit"}, } m["nop"] = { "Numanggang", 7069052, "ngf-boa", "Latn", } m["noq"] = { "Ngongo", 11057478, "bnt-yak", "Latn", } m["nos"] = { "Eastern Nisu", 25559419, "tbq-nis", } m["not"] = { "Nomatsiguenga", 3342992, "awd", "Latn", } m["nou"] = { "Ewage-Notu", 5418860, "ngf-bin", "Latn", } m["nov"] = { "Novial", 36738, "art", "Latn", type = "appendix-constructed" } m["now"] = { "Nyambo", 4967930, "bnt-haj", "Latn", } m["noy"] = { "Noy", 36321, "alv-bua", } m["noz"] = { "Nayi", 3183349, "omv-diz", } m["npa"] = { "Nar Phu", 4926353, "sit-tam", } m["npb"] = { "Nupbikha", 3695201, "sit-ebo", } m["npg"] = { "Ponyo", 7228475, "sit-kch", } m["nph"] = { "Phom", 7187109, "sit-kch", } m["npl"] = { "Southeastern Puebla Nahuatl", 4632950, "azc-nah", "Latn", } m["npn"] = { "Mondropolon", 3320594, "poz-aay", } m["npo"] = { "Pochuri Naga", 7206342, "tbq-anp", } m["nps"] = { "Nipsan", 11732528, "ngf-mek", "Latn", } m["npu"] = { "Puimei Naga", 7259044, "sit-zem", } m["npx"] = { "Noipä", 63283617, "poz-tem", "Latn", } m["npy"] = { "Napu", 12953768, } m["nqg"] = { "Ede Nago", 12952408, "alv-ede", "Latn", } m["nqk"] = { "Kura Ede Nago", 12952409, "alv-ede", } m["nql"] = { "Ngendelengo", 63283693, "bnt-swb", "Latn", } m["nqm"] = { "Ndom", 6983791, "paa-kol", "Latn", } m["nqn"] = { "Nen", 20816352, "paa-nam", "Latn", } m["nqo"] = { "N'Ko", 18546266, "dmn-man", "Nkoo", } m["nqq"] = { "Kyan-Karyaw Naga", 63283784, "sit-tno", } m["nqy"] = { "Akyaung Ari", 4702035, "sit-tng", } m["nra"] = { "Ngom", 36087, "bnt-kel", "Latn", } m["nrb"] = { "Nara", 36179, "sdv-nes", } m["nrc"] = { "Noric", 37023, "cel", "Ital", -- Ital translit in [[Module:scripts/data]] } m["nre"] = { "Southern Rengma Naga", 7313205, "tbq-anp", } m["nrf"] = { "Norman", 33850, "roa-oil", "Latn", wikimedia_codes = "nrm", ancestors = "fro-nor", sort_key = s["roa-oil-sortkey"], } m["nrg"] = { "Narango", 12952929, "poz-vnn", "Latn", } m["nri"] = { "Chokri Naga", 5104247, "tbq-anp", } m["nrk"] = { "Ngarla", 3915860, "aus-nga", "Latn", } m["nrl"] = { "Ngarluma", 7022078, "aus-nga", "Latn", } m["nrm"] = { "Narom", 3336135, "poz-swa", "Latn", } m["nrn"] = { "Norn", 36708, "gmq-ins", "Latn", } m["nrp"] = { "North Picene", 430138, "qfa-unc", -- extinct, might be a hoax "Ital", -- Ital translit in [[Module:scripts/data]] } m["nrr"] = { "Norra", 12952967, "tai", } m["nrt"] = { "Northern Kalapuya", 3192121, "nai-klp", } m["nru"] = { "Narua", 21658869, "sit-nas", "Latn", } m["nrx"] = { "Ngurmbur", 2591251, } m["nrz"] = { "Lala (New Guinea)", 6480151, "poz-ocw", "Latn", } m["nsa"] = { "Sangtam Naga", 7418144, "sit-aao", } m["nsb"] = { "Lower Nossob", 6693681, "khi-tuu", "Latn", } m["nsc"] = { "Nshi", 11129508, "nic-rnn", "Latn", } m["nsd"] = { "Southern Nisu", 63284284, "tbq-nis", } m["nse"] = { "Nsenga", 3081996, "bnt-sna", "Latn", } m["nsg"] = { "Ngasa", 56345, "sdv-lma", } m["nsh"] = { "Ngoshie", 7022582, "nic-mom", "Latn", } m["nsi"] = { "Nigerian Sign Language", 7033021, "sgn", } m["nsk"] = { "Naskapi", 1704302, "alg", "Cans, Latn", ancestors = "cr", translit = "nsk-translit", } m["nsl"] = { "Norwegian Sign Language", 1781613, "sgn", } m["nsm"] = { "Sema", 3478238, "tbq-anp", } m["nsn"] = { "Nehan", 3337774, "poz-ocw", "Latn", } m["nso"] = { "Northern Sotho", 33890, "bnt-sts", "Latn", } m["nsp"] = { "Nepalese Sign Language", 3915492, "sgn", } m["nsq"] = { "Northern Sierra Miwok", 3344226, "nai-utn", "Latn", } m["nsr"] = { "Maritime Sign Language", 3915483, "sgn", } m["nss"] = { "Nali", 3335385, "poz-aay", } m["nst"] = { "Tangsa", 56350, "sit-tno", "Latn, Tnsa", } m["nsu"] = { "Sierra Negra Nahuatl", 63284326, "azc-nah", "Latn", } m["nsv"] = { "Southwestern Nisu", 63308004, "tbq-nis", } m["nsw"] = { "Navut", 3337327, "poz-vnn", "Latn", } m["nsx"] = { "Nsongo", 7067577, "bnt-tmb", "Latn", } m["nsy"] = { "Nasal", 6966574, } m["nsz"] = { "Nisenan", 33665, "nai-mdu", "Latn", } m["ntd"] = { "Northern Tidung", 24938325, "poz-san", } -- ISO merged "nte" into "eko" m["ntg"] = { "Ngantangarra", 33060509, } m["nti"] = { "Natioro", 36140, "alv-wan", } m["ntj"] = { "Ngaanyatjarra", 3915409, "aus-pam", "Latn", } m["ntk"] = { "Ikoma", 5996114, "bnt-lok", "Latn", } m["ntm"] = { "Nateni", 3070731, "nic-grm", "Latn", } m["nto"] = { "Ntomba", 11130292, "bnt-mon", "Latn", } m["ntp"] = { "Northern Tepehuan", 15615651, "azc-pim", "Latn", sort_key = {remove_diacritics = c.acute}, } m["ntr"] = { "Delo", 35195, "nic-gne", "Latn", } m["nts"] = { "Natagaimas", 6967931, } m["ntu"] = { "Natügu", 63308082, "poz-tem", "Latn", } m["ntw"] = { "Nottoway", 3344791, "iro-nor", "Latn", } m["ntx"] = { "Somra", 7560536, "sit-tng", } m["nty"] = { "Mantsi", 56878, "sit-mnz", } m["nua"] = { "Yuanga", 3573088, "poz-cln", "Latn", } m["nuc"] = { "Nukuini", 3346231, } m["nud"] = { "Ngala", 7021893, "paa-ndu", "Latn", } m["nue"] = { "Ngundu", 12952953, "bad-cnt", "Latn", } m["nuf"] = { "Nusu", 56413, "tbq-nus", "Latn", } m["nug"] = { "Nungali", 7069826, "aus-mir", "Latn", } m["nuh"] = { "Ndunda", 3913968, "nic-mmb", "Latn", } m["nui"] = { "Ngumbi", 36459, "bnt-yko", } m["nuj"] = { "Nyole (Uganda)", 3739448, "bnt-msl", "Latn", } m["nuk"] = { "Nootka", 2992876, "wak", "Latn", } m["nul"] = { "Nusa Laut", 7070332, "poz-cma", } m["num"] = { "Niuafo'ou", 36173, "poz-ton", "Latn", } m["nun"] = { "Anong", 2748232, "sit-nng", "Latn", } m["nuo"] = { "Nguôn", 3915785, "mkh-vie", "Latn", sort_key = "vi-sortkey", } m["nup"] = { "Nupe", 36720, "alv-ngb", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.macron .. c.caron}, sort_key = "nup-sortkey", } m["nuq"] = { "Nukumanu", 12909019, "poz-pnp", "Latn", } m["nur"] = { "Nuguria", 7068910, "poz-pnp", "Latn", } m["nus"] = { "Nuer", 33675, "sdv-dnu", "Latn", } m["nut"] = { "Nùng", 72695, "tai", "Latn, Hani", sort_key = {Hani = "Hani-sortkey"}, } m["nuu"] = { "Ngbundu", 11126081, "bad", "Latn", } m["nuv"] = { "Northern Nuni", 11016572, "nic-gnn", "Latn", } m["nuw"] = { "Nguluwan", 6528643, } m["nux"] = { "Mehek", 6809452, "paa-sep", "Latn", } m["nuy"] = { "Nunggubuyu", 1747811, "aus-arn", "Latn", } m["nuz"] = { "Tlamacazapa Nahuatl", 2073277, "azc-nah", "Latn", } m["nvh"] = { "Nasarian", 6966614, "poz-vnc", "Latn", } m["nvm"] = { "Namiae", 12952922, "ngf-koi", "Latn", } m["nvo"] = { "Nyokon", 19573407, "nic-mbw", "Latn", } m["nwa"] = { "Nawathinehena", 6982892, "alg-ara", "Latn", } m["nwb"] = { "Nyabwa", 33664, "kro-wee", } m["nwc"] = { "Classical Newar", 5128301, "sit-new", "Brah, Deva, Newa, Ranj", -- Brah translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission) } m["nwe"] = { "Ngwe", 36181, "bai", "Latn", } m["nwg"] = { "Ngaiawang", 16920653, "aus-pam", "Latn", } m["nwi"] = { "Southwest Tanna", 3504488, "poz-vns", "Latn", } m["nwm"] = { "Nyamusa-Molo", 12747951, "csu-bbk", } m["nwo"] = { "Nauo", 6981305, "aus-pam", "Latn", } m["nwr"] = { "Nawaru", 12638166, "ngf-yar", "Latn", } m["nwx"] = { "Middle Newar", 65455877, "sit-new", "Deva, Newa, Ranj", ancestors = "nwc", } m["nwy"] = { "Nottoway-Meherrin", 65455878, "iro-nor", "Latn", } m["nxa"] = { "Nauete", 6981095, "poz-tim", } m["nxd"] = { "Ngando (Congo)", 3913277, "bnt-ske", } m["nxe"] = { "Nage", 2295569, "poz-cet", } m["nxg"] = { "Ngadha", 1516651, "poz-cet", "Latn", } m["nxi"] = { "Nindi", 7038230, "bnt-mbi", "Latn", } m["nxl"] = { "South Nuaulu", 18544857, "poz-cma", } m["nxm"] = { "Numidian", 35761, "afa", "Tfng, Latn", --Tfng may not support all the needed characters } m["nxn"] = { "Ngawun", 3915711, "aus-pam", "Latn", } m["nxo"] = { "Ndambomo", 6983681, "bnt-kel", "Latn", } m["nxq"] = { "Naxi", 2478711, "sit-nas", "Nkdb, Nkgb, Latn, Lisu", -- Lisu translit, sort_key in [[Module:scripts/data]] } m["nxr"] = { "Ninggerum", 11732526, "ngf-lok", "Latn", } -- nxu (Narau) merged into bpp (Kaure) per ISO 639-3 2020 merger m["nxx"] = { "Nafri", 6958211, "paa-sen", "Latn", } m["nyb"] = { "Nyangbo", 36256, "alv-ktg", "Latn", } m["nyc"] = { "Nyanga-li", 7070876, "bnt-boa", "Latn", } m["nyd"] = { "Nyole (Kenya)", 7071227, "bnt-msl", "Latn", } m["nye"] = { "Nyengo", 7071068, "bnt-clu", "Latn", } m["nyf"] = { "Giryama", 3107606, "bnt-mij", "Latn", } m["nyg"] = { "Nyindu", 11030685, "bnt-shh", "Latn", } m["nyh"] = { "Nyigina", 3913780, "aus-nyu", "Latn", } m["nyi"] = { "Nyimang", 34846, "sdv-nyi", "Latn", } m["nyj"] = { "Nyanga (Congo)", 7070879, "bnt-nyb", "Latn", } m["nyk"] = { "Nyaneka", 10962298, "bnt-swb", "Latn", } m["nyl"] = { "Nyeu", 3033578, "mkh-kat", } m["nym"] = { "Nyamwezi", 4121131, "bnt-tkm", "Latn", } m["nyn"] = { "Nyankole", 13207, "bnt-nyg", "Latn", } m["nyo"] = { "Nyoro", 33794, "bnt-nyg", "Latn", } m["nyp"] = { "Nyang'i", 7070894, "ssa-klk", } m["nys"] = { "Nyunga", 7049771, "aus-pam", "Latn", } m["nyt"] = { "Nyawaygi", 3915783, "aus-dyb", "Latn", } m["nyu"] = { "Nyungwe", 7071318, "bnt-sna", "Latn", } m["nyv"] = { "Nyulnyul", 3442732, "aus-nyu", "Latn", } m["nyw"] = { "Nyaw", 26425602, "tai-nor", -- Chamberlain (1991), but Pittayaporn (2009) suggests tai-swe "Thai, Tayo", -- Thailand sort_key = "Thai-sortkey", -- no effect on Latn } m["nyx"] = { "Nganyaywana", 3913800, "aus-cww", "Latn", } m["nyy"] = { "Nyakyusa", 3272620, "bnt-run", "Latn", } m["nza"] = { "Tigon Mbembe", 36518, "nic-jkn", "Latn", } m["nzb"] = { "Njebi", 35923, "bnt-nze", "Latn", } m["nzd"] = { "Nzadi", 17152586, "bnt-bdz", "Latn", strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron}, } m["nzi"] = { "Nzima", 36337, "alv-ctn", "Latn", } m["nzk"] = { "Nzakara", 3913339, "znd", "Latn", } m["nzm"] = { "Zeme Naga", 21491053, "sit-zem", } m["nzs"] = { "New Zealand Sign Language", 36239, "sgn", } m["nzu"] = { "Central Teke", 36473, "bnt-tkc", "Latn", } m["nzy"] = { "Nzakambay", 36374, "alv-mbm", "Latn", } m["nzz"] = { "Nanga Dama Dogon", 6963443, "nic-nwa", } return require("Module:languages").finalizeData(m, "language") iudjlhktzp7uuktnpwqql35p3qylbr0 Module:languages/data/3/s 828 32650 178468 175570 2026-10-27T02:13:39Z GinawaSaHapon 3989 178468 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["saa"] = { "Saba", 3914885, "cdc-est", "Latn", } m["sab"] = { "Buglere", 3368506, "cba", "Latn", } m["sac"] = { "Fox", 12714767, "alg-sfk", "Latn", } m["sad"] = { "Sandawe", 34016, "qfa-iso", "Latn", } m["sae"] = { "Sabanê", 3460478, "sai-nmk", "Latn", } m["saf"] = { "Safaliba", 36432, "nic-mre", "Latn", } m["sah"] = { "Yakut", 34299, "trk-nsb", "Cyrl", translit = "sah-translit", override_translit = true, } m["saj"] = { "Sahu", 7399757, "paa-sah", "Latn", } m["sak"] = { "Sake", 36425, "bnt-kel", "Latn", } m["sam"] = { "Samaritan Aramaic", 56612, "sem-arw", "Samr", translit = "Samr-translit", -- Samr strip_diacritics, sort_key in [[Module:scripts/data]] } m["sao"] = { "Sause", 4409155, "qfa-dis", -- isolate per Glottolog, possibly related to Kapauri in a Kapauri-Sause family under Greater Kwerba "Latn", } m["saq"] = { "Samburu", 56536, "sdv-lma", } m["sar"] = { "Saraveca", 3450556, "awd", "Latn", } m["sas"] = { "Sasak", 1294047, "poz-bss", "Latn, Bali, Java", } m["sat"] = { "Santali", 33965, "mun", "Olck", translit = "Olck-translit", override_translit = true, } m["sau"] = { "Saleman", 7404262, "poz-cet", } m["sav"] = { "Saafi-Saafi", 36308, "alv-cng", "Arab, Latn", } m["saw"] = { "Sawi", 677064, "ngf-awd", "Latn", } m["sax"] = { "Sa", 3460352, "poz-vnn", "Latn", } m["say"] = { "Saya", 3914431, "cdc-wst", "Latn", } m["saz"] = { "Saurashtra", 13292, "inc-wes", "Saur, Latn, Taml, Deva", translit = "saz-translit", ancestors = "inc-ogu", } m["sba"] = { "Ngambay", 2372207, "csu-sar", "Latn", } m["sbb"] = { "Simbo", 3484101, "poz-ocw", } m["sbc"] = { "Gele'", 3194847, "poz-aay", "Latn", } m["sbd"] = { "Southern Samo", 33122730, "dmn-sam", "Latn", } m["sbe"] = { "Saliba (New Guinea)", 3469737, "poz-ocw", } m["sbf"] = { "Shabo", 36342, "ssa", "Latn", } m["sbg"] = { "Seget", 7446237, "paa-wbh", "Latn", } m["sbh"] = { "Sori-Harengan", 36515, "poz-aay", "Latn", } m["sbi"] = { "Seti", 7456682, "paa-trr", "Latn", } m["sbj"] = { "Surbakhal", 759995, } m["sbk"] = { "Safwa", 4121160, "bnt-mby", "Latn", } m["sbl"] = { "Sambal Botolan", --TLCHANGE 4095195, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sambal-2/", --TLCHANGE english_name = "Botolan Sambal", --TLCHANGE } m["sbm"] = { "Sagala", 11732610, "bnt-ruv", "Latn", } m["sbn"] = { "Sindhi Bhil", 25559289, "inc-snd", "Arab, Deva, Sind, Guru", ancestors = "sd", } m["sbo"] = { "Sabüm", 7396535, "mkh-asl", } m["sbp"] = { "Sangu (Tanzania)", 7418149, "bnt-bki", "Latn", } m["sbq"] = { "Sirva", 7514337, "ngf-nso", "Latn", } m["sbr"] = { "Sembakung Murut", 7449148, "poz-san", } m["sbs"] = { "Subiya", 6442073, "bnt-bot", "Latn", } m["sbt"] = { "Kimki", 6410160, "qfa-dis", -- Papuan; Glottolog and Foley treat as an isolate, Usher puts in South Pauwasi "Latn", } m["sbu"] = { "Stod Bhoti", 15622700, "sit-las", } m["sbv"] = { "Sabine", 65455885, "itc-sbl", "Latn", display_text = s["itc-Latn-displaytext"], strip_diacritics = s["itc-Latn-stripdiacritics"], sort_key = s["itc-Latn-sortkey"], } m["sbw"] = { "Simba", 36430, "bnt-tso", "Latn", } m["sbx"] = { "Seberuang", 12473470, "poz-mly", } m["sby"] = { "Soli", 7557754, "bnt-bot", "Latn", } m["sbz"] = { "Sara Kaba", 25559318, "csu-kab", "Latn", } m["scb"] = { "Chut", 2967709, "mkh-vie", "Latn", } m["sce"] = { "Dongxiang", 32947, "xgn-shr", "Arab, Latn", } m["scf"] = { "San Miguel Creole French", 12953094, "crp", "Latn", ancestors = "gcf", sort_key = s["roa-oil-sortkey"], } m["scg"] = { "Sanggau", 12473466, "day", } m["sch"] = { "Sakachep", 37054, "tbq-kuk", } m["sci"] = { "Sri Lankan Creole Malay", 1089151, "crp", "Latn", ancestors = "ms", } m["sck"] = { "Sadri", 765922, "inc-bih", "Deva, Kthi", translit = { Deva = "hi-translit", Kthi = "bho-Kthi-translit", }, } m["scl"] = { "Shina", 1353320, "inc-shn", "ur-Arab, Deva", } m["scn"] = { "Sisilyano", --TLCHANGE 33973, "roa-itr", ancestors = "scn-old", "Latn", english_name = "Sicilian", --TLCHANGE spanish_name = "Siciliano", --TLCHANGE } m["sco"] = { "Eskoses", --TLCHANGE 14549, "gmw-ang", "Latn", ancestors = "gmw-msc", english_name = "Scots", --TLCHANGE spanish_name = "Escocés" --TLCHANGE } m["scp"] = { "Yolmo", 22662107, "sit-kyk", "Deva", } m["scq"] = { "Sa'och", 6583617, "mkh-pea", } m["scs"] = { "North Slavey", 20628, "den", "Latn", } m["scu"] = { "Shumcho", 22077739, "sit-kin", } m["scv"] = { "Sheni", 11015820, "nic-jer", "Latn", ancestors = "zir", } m["scw"] = { "Sha", 3438816, "cdc-wst", "Latn", } m["scx"] = { "Sicel", 36667, "itc", "Polyt", -- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["scz"] = { "Shetland", 3069598, "qfa-mix", "Latn", ancestors = "nrn, gmw-msc", standard_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzØøÖüÜü0123456789" .. c.punc, } m["sda"] = { "Toraja-Sa'dan", 36673, "poz-ssw", "Latn", } m["sdb"] = { "Shabak", 3289596, "ira-zgr", ancestors = "hac", } m["sdc"] = { "Sassarese", 845441, "roa-itr", "Latn", } m["sde"] = { "Surubu", 3913336, "nic-kau", "Latn", } m["sdf"] = { "Sarli", 7424256, "ira-zgr", ancestors = "hac", } m["sdg"] = { "Savi", 3474654, "inc-dng", } m["sdh"] = { "Katimugang Kurdo", --TLCHANGE 1496597, "ku", "ku-Arab", translit = "sdh-translit", strip_diacritics = {remove_diacritics = c.kasra .. c.sukun}, english_name = "Southern Kurdish", --TLCHANGE spanish_name = "Kurdo meridional", --TLCHANGE } m["sdj"] = { "Suundi", 7650407, "bnt-kng", "Latn", } m["sdk"] = { "Sos Kundi", 7563811, "paa-nnd", "Latn", } m["sdl"] = { "Saudi Arabian Sign Language", 3504160, "sgn", } m["sdm"] = { "Semandang", 7449012, "day", } m["sdn"] = { "Gallurese", 612220, "roa-itr", "Latn", ancestors = "co", } m["sdo"] = { "Bukar-Sadung Bidayuh", 2927799, "day", "Latn", } m["sdp"] = { "Sherdukpen", 7494785, "sit-khm", } m["sdr"] = { "Oraon Sadri", 12953860, "inc-bih", } m["sds"] = { "Tunisian Berber", 5329732, "ber", } m["sdu"] = { "Sarudu", 7424700, "poz-cet", } m["sdx"] = { "Sibu Melanau", 18642842, "poz-bnn", } m["sea"] = { "Semai", 3135426, "mkh-asl", "Latn", } -- seb is a duplicate code of spp m["sec"] = { "Sechelt", 7442898, "sal", "Latn", } m["sed"] = { "Sedang", 56448, "mkh-nbn", "Latn", } m["see"] = { "Seneca", 1185133, "iro-nor", "Latn", } m["sef"] = { "Cebaara", 10975121, "alv-snr", "Latn", } m["seg"] = { "Segeju", 17584599, "bnt-mij", "Latn", } m["seh"] = { "Sena", 2964008, "bnt-sna", "Latn", } m["sei"] = { "Seri", 36583, "qfa-iso", "Latn", } m["sej"] = { "Sene", 7450252, "ngf-ehu", "Latn", } m["sek"] = { "Sekani", 28562, "ath-nor", "Latn", } m["sen"] = { "Nanerige", 36002, "alv-sma", } m["seo"] = { "Asaba", 7630513, "qfa-dis", -- Papuan; isolate or unclassified in Glottolog; Sepik language in Foley (2018) "Latn", } m["sep"] = { "Sicite", 56787, "alv-sma", } m["seq"] = { "Senara", -- not to be confused with Syenara (shz) 35210, "alv-snr", } m["ser"] = { "Serrano", 3479942, "azc-tak", "Latn", } m["ses"] = { "Koyraboro Senni", 35655, "son", "Latn", } m["set"] = { "Sentani", 3441672, "paa-sen", "Latn", } m["seu"] = { "Serui-Laut", 7455503, "poz-hce", "Latn", } m["sev"] = { "Nyarafolo", 36306, "alv-snr", } m["sew"] = { "Sewa Bay", 7458126, "poz-ocw", } m["sey"] = { "Secoya", 3477218, "sai-tuc", "Latn", } m["sez"] = { "Senthang Chin", 7451223, "tbq-kuk", } m["sfb"] = { "French Belgian Sign Language", 3217332, "sgn", } m["sfe"] = { "G̓insëlug̓ën Sub̓anën", --TLCHANGE 63311321, "phi", "Latn", is_official_kwf_name = "https://www.facebook.com/share/p/17hXPKnTmP/", --TLCHANGE english_name = "Eastern Subanun", --TLCHANGE } m["sfm"] = { "Small Flowery Miao", 7542773, "hmn", } m["sfs"] = { "South African Sign Language", 3322093, "sgn", } m["sfw"] = { "Sehwi", 36593, "alv-ctn", "Latn", } m["sga"] = { "Lumang Irlandes", 35308, "cel-gae", "Latn, Ogam", strip_diacritics = {remove_diacritics = c.dotabove .. c.diaer .. "·"}, sort_key = "sga-sortkey", standard_chars = "AaÁáBbCcDdEeÉéFfGgHhIiÍíLlMmNnOoÓóPpRrSsTtUuÚú0123456789ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔ" .. c.punc, } m["sgb"] = { "Ayta Mag-antsi", --"Mag-Anchi Ayta", 4356243, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/ayta-mag-antsi/", --TLCHANGE english_name = "Mag-Anchi Ayta" --TLCHANGE } m["sgc"] = { "Kipsigis", 56339, "sdv-nma", } m["sgd"] = { "Surigawnon", --"Surigaonon", 34140, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/surigawnon-2/", --TLCHANGE english_name = "Surigaonon" --TLCHANGE } m["sge"] = { "Segai", 7446180, } m["sgg"] = { "Swiss-German Sign Language", 35150, "sgn", } m["sgh"] = { "Shughni", 34053, "ira-shr", "Latn, Cyrl", translit = "sgh-translit", override_translit = true, } m["sgi"] = { "Suga", 36475, "nic-mmb", "Latn", } m["sgk"] = { "Sangkong", 2945610, "tbq-bis", } m["sgm"] = { "Singa", 7522797, "bnt-lok", "Latn", } m["sgp"] = { "Singpho", 7524158, "sit-jnp", "Latn", } m["sgr"] = { "Sangisari", 3394363, "ira-kms", "Arab", } m["sgs"] = { "Samogitian", 213434, "bat-eas", "Latn", wikimedia_codes = "bat-smg", ancestors = "olt", display_text = "lt-common", strip_diacritics = "lt-common", sort_key = "lt-common", } m["sgt"] = { "Brokpake", 56603, "sit-tib", "Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["sgu"] = { "Salas", 7403694, "poz-cma", } m["sgw"] = { "Sebat Bet Gurage", 2707343, "sem-eth", "Ethi", } m["sgx"] = { "Sierra Leone Sign Language", 7511448, "sgn", } m["sgy"] = { "Sanglechi", 3472220, "ira-sgi", } m["sgz"] = { "Sursurunga", 36511, "poz-ocw", "Latn", } m["sha"] = { "Shall-Zwall", 3915355, "nic-beo", } m["shb"] = { "Ninam", 3436586, "sai-ynm", "Latn", } m["shc"] = { "Sonde", 7560881, "bnt-pen", "Latn", } m["shd"] = { "Kundal Shahi", 6444265, "inc-shn", "Arab", } m["she"] = { "Sheko", 3183355, "omv-diz", } m["shg"] = { "Shua", 3501092, "khi-kal", "Latn", } m["shh"] = { "Shoshone", 33811, "azc-num", "Latn", } m["shi"] = { "Tashelhit", 34152, "ber", "Latn, Arab, Tfng, Hebr", ancestors = "shi-med", translit = { Tfng = "Tfng-translit", }, strip_diacritics = { Arab = "ar-stripdiacritics", }, -- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["shj"] = { "Shatt", 56344, "sdv-daj", } m["shk"] = { "Shilluk", 36486, "sdv-lon", "Latn", } m["shl"] = { "Shendu", 22074616, "tbq-kuk", } m["shm"] = { "Shahrudi", 7462280, "xme-ttc", "fa-Arab, Latn", ancestors = "xme-ttc-cen", } m["shn"] = { "Shan", 56482, "tai-swe", "Mymr", translit = "shn-translit", sort_key = { from = {"[ၢႃ]", "ဵ", "ႅ", "ႇ", "ႈ", "း", "ႉ", "ႊ"}, to = {"ာ", "ေ", "ႄ", "႒", "႓", "႔", "႕", "႖"} }, } m["sho"] = { "Shanga", 3913931, "dmn-bbu", "Latn", } m["shp"] = { "Shipibo-Conibo", 2671988, "sai-pan", "Latn", } m["shq"] = { "Sala", 10961665, "bnt-bot", "Latn", } m["shr"] = { "Shi", 3481999, "bnt-shh", "Latn", } m["shs"] = { "Shuswap", 3482685, "sal", "Latn", } m["sht"] = { "Shasta", 56396, "nai-shs", "Latn", } m["shu"] = { "Arabe Tsadyano", --TLCHANGE 56497, "sem-arb", "Arab", strip_diacritics = { remove_diacritics = c.kashida .. c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.superalef, from = {u(0x0671)}, to = {u(0x0627)} }, english_name = "Chadian Arabic", --TLCHANGE spanish_name = "Árabe chadiano", --TLCHANGE } m["shv"] = { "Shehri", 33445, "sem-sar", "Arab, Latn", } m["shw"] = { "Shwai", 36527, "alv-hei", } m["shx"] = { "She", 2605689, "hmn", } m["shy"] = { "Tachawit", 33274, "ber", "Tfng, Arab, Latn", translit = "Tfng-translit", } m["shz"] = { "Syenara", -- not to be confused with Senara (seq) 36316, "alv-snr", } m["sia"] = { "Akkala Sami", 35241, "smi", "Cyrl, Latn", translit = "sia-translit", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = "'ˈ"}, } m["sib"] = { "Sebop", 7442799, "poz-swa", "Latn", } m["sid"] = { "Sidamo", 33786, "cus-hec", "Latn, Ethi", } m["sie"] = { "Simaa", 7517329, "bnt-kav", "Latn", } m["sif"] = { "Siamou", 36252, } m["sig"] = { "Paasaal", 36426, "nic-sis", "Latn", } m["sih"] = { "Sîshëë", 8072753, "poz-cln", "Latn", } m["sii"] = { "Shom Peng", 1039346, "aav", } m["sij"] = { "Numbami", 3346277, "poz-ocw", "Latn", } m["sik"] = { "Sikiana", 3443734, "sai-prk", "Latn", } m["sil"] = { "Tumulung Sisaala", 25383006, "nic-sis", "Latn", } m["sim"] = { "Mende (New Guinea)", 7446815, "paa-sep", "Latn", } m["sip"] = { "Sikkimese", 35285, "sit-tib", "Tibt", ancestors = "xct", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["siq"] = { "Sonia", 7561770, "ngf-bos", "Latn", } m["sir"] = { "Siri", 3438729, "cdc-wst", "Latn", } m["sis"] = { "Siuslaw", 2315424, } m["siu"] = { "Sinagen", 7521655, "paa-wap", "Latn", } m["siv"] = { "Sumariup", 7636966, "paa-sep", "Latn", } m["siw"] = { "Siwai", 7532519, "paa-sbo", "Latn", } m["six"] = { "Sumau", 7637021, "ngf-pek", "Latn", } m["siy"] = { "Sivandi", 13269, "xme", "fa-Arab, Latn", ancestors = "xme-mid", } m["siz"] = { "Siwi", 36814, "ber", "Tfng, Arab, Latn", } m["sja"] = { "Epena", 3055682, "sai-chc", "Latn", } m["sjb"] = { "Sajau Basap", 4684353, "poz-bnn", } m["sjc"] = { "Shaojiang Min", 3431451, "zhx-inm", "Hants", generate_forms = "zh-generateforms", sort_key = "Hani-sortkey", } m["sjd"] = { "Kildin Sami", 33656, "smi", "Cyrl", translit = "sjd-translit", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = "'ˈ"}, } m["sje"] = { "Pite Sami", 56314, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = c.macron .. "'ˈ"}, sort_key = "sje-sortkey", } m["sjg"] = { "Assangori", 3502255, "sdv-tmn", } m["sjk"] = { "Kemi Sami", 35871, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = "'ˈ"}, } m["sjl"] = { "Miji", 6845470, "sit-hrs", } m["sjm"] = { "Jama Mapun", --"Mapun", 3287253, "poz-sbj", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/jama-mapun/", --TLCHANGE english_name = "Mapun" --TLCHANGE } m["sjn"] = { "Sindarin", 56437, "art", "Latn, Teng", type = "appendix-constructed", } m["sjo"] = { "Xibe", 13223, "tuw-jrc", "sjo-Mong", ancestors = "mnc", } m["sjp"] = { "Surjapuri", 7645351, "inc-krd", "Deva, as-Beng, Kthi", } m["sjr"] = { "Siar-Lak", 3482907, "poz-ocw", } m["sjs"] = { "Senhaja de Srair", 56744, "ber", "Latn, Tfng, Arab", strip_diacritics = { Arab = "ar-stripdiacritics", }, translit = { Tfng = "Tfng-translit", } } m["sjt"] = { "Ter Sami", 36656, "smi", "Cyrl, Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = "'ˈ"}, translit = "sjt-translit", } m["sju"] = { "Ume Sami", 56415, "smi", "Latn", strip_diacritics = {remove_diacritics = c.macron .. "'ˈ"}, display_text = { from = {"'"}, to = {"ˈ"} }, sort_key = "sju-sortkey", } m["sjw"] = { "Shawnee", 2669206, "alg", "Latn", } -- [ska] Skagit is treated as part of [lut] Lushootseed m["skb"] = { "Saek", 36437, "tai-nor", "Thai", sort_key = "Thai-sortkey", } m["skc"] = { "Ma Manda", 6720783, "ngf-era", "Latn", } m["skd"] = { "Southern Sierra Miwok", 3492334, "nai-utn", "Latn", } m["ske"] = { "Ske", 7534244, "poz-vnn", "Latn", } m["skf"] = { "Mekéns", 3304806, "tup", "Latn", } m["skh"] = { "Sikule", 3121081, "poz-nws", } m["ski"] = { "Sika", 33960, "poz-cet", "Latn", } m["skj"] = { -- compare 'ths' "Seke", 30226846, "sit-tam", } m["skk"] = { "Sok", 12953887, "mkh-ban", } m["skm"] = { "Sakam", 6448517, "ngf-uru", "Latn", } m["skn"] = { "Kolibugan", --"Kolibugan Subanon", 18755617, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/kolibugan/", --TLCHANGE english_name = "Kolibugan Subanon" --TLCHANGE } m["sko"] = { "Seko Tengah", 15613270, "poz", } m["skp"] = { "Sekapan", 7447132, "poz-bnn", } m["skq"] = { "Sininkere", 3914896, "dmn-snb", "Latn", } m["skr"] = { "Saraiki", 33902, "inc-pan", "pa-Arab, Mult, Deva", strip_diacritics = {remove_diacritics = c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.nunghunna}, translit = { ["pa-Arab"] = "pa-Arab-translit", Deva = "hi-translit", Mult = "Mult-translit", }, } m["sks"] = { "Maia", 12952760, "ngf-kau", "Latn", } m["skt"] = { "Sakata", 36691, "bnt-bnm", "Latn", } m["sku"] = { "Sakao", 3298421, "poz-vnn", "Latn", } m["skv"] = { "Skou", 3915200, "paa-isk", "Latn", } m["skw"] = { "Skepi Creole Dutch", 2522153, "crp", "Latn", ancestors = "nl", } m["skx"] = { "Seko Padang", 15613282, "poz-ssw", "Latn", } m["sky"] = { "Sikaiana", 7439242, "poz-pnp", "Latn", } m["skz"] = { "Sekar", 7447136, "poz-cet", } m["slc"] = { "Saliba (Colombia)", 3441097, nil, "Latn", } m["sld"] = { "Sisaala", 11020264, "nic-sis", "Latn", } m["sle"] = { "Sholaga", 7500203, "dra-kan", "Knda", -- Knda translit in [[Module:scripts/data]] } m["slf"] = { "Swiss-Italian Sign Language", 12953479, "sgn", } m["slg"] = { "Selungai Murut", 7448844, "poz-san", } -- [slh] Southern Puget Sound Salish is treated as part of [lut] Lushootseed -- "sli" "Silesian German" IS SUBSUMED INTO "gmw-ecg" "East Central German" m["slj"] = { "Salumá", 7406296, "sai-prk", "Latn", } m["sll"] = { "Salt-Yui", 7405785, "ngf-sim", "Latn", } m["slm"] = { "Sama Pangutaran", --"Pangutaran Sama", 3362086, "poz-sbj", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sama-2/", --TLCHANGE english_name = "Pangutaran Sama" --TLCHANGE } m["sln"] = { "Salinan", 1568938, "qfa-iso", "Latn", } m["slp"] = { "Lamaholot", 6480777, "poz-cet", "Latn", } m["slr"] = { "Salar", 33963, "trk-ogz", "Arab, Latn", ancestors = "trk-eog", } m["sls"] = { "Singapore Sign Language", 7512563, "sgn", } m["slt"] = { "Sila", 7514021, "tbq-sil", } m["slu"] = { "Selaru", 7447500, "poz-cet", "Latn", } m["slw"] = { "Sialum", 7506694, "ngf-ehu", "Latn", } m["slx"] = { "Salampasu", 7403607, "bnt-lun", "Latn", } m["sly"] = { "Selayar", 7447520, "poz-ssw", } m["slz"] = { "Ma'ya", 2291492, "poz-hce", "Latn", } m["sma"] = { "Southern Sami", 13293, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = "'ˈ"}, sort_key = "sma-sortkey", } m["smb"] = { "Simbari", 7517427, "ngf-bsi", "Latn", } m["smc"] = { "Som", 7559081, "ngf-uru", "Latn", } m["smd"] = { "Sama", 6407456, "bnt-kmb", "Latn", } m["smf"] = { "Auwe", 3502072, "paa-war", "Latn", ancestors = "dnd", } m["smg"] = { "Simbali", 56692, "paa-bai", "Latn", } m["smh"] = { "Samei", 7409269, "tbq-axi", } m["smj"] = { "Lule Sami", 56322, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = c.macron .. "'ˈ"}, sort_key = "smj-sortkey", } m["smk"] = { "Bolinaw", --"Bolinao", 2669235, "phi", "Latn, Tglg", is_official_kwf_name = "https://kwfwikaatkultura.ph/bolinaw/", --TLCHANGE english_name = "Bolinao" --TLCHANGE } m["sml"] = { "Sama Sentral", --"Central Sama", 3470593, "poz-sbj", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sama-2/", --TLCHANGE english_name = "Central Sama" --TLCHANGE } m["smm"] = { "Musasa", 6940122, "inc-bih", } m["smn"] = { "Inari Sami", 33462, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = c.dotbelow .. "'ˈ"}, sort_key = "smn-sortkey", } m["smp"] = { "Samaritan Hebrew", 56502, "sem-can", "Samr", translit = "Samr-translit", -- Samr strip_diacritics, sort_key in [[Module:scripts/data]] ancestors = "hbo", } m["smq"] = { "Samo", 7409884, "ngf-est", "Latn", } m["smr"] = { "Simeulue", 2992833, "poz-nws", "Latn", } m["sms"] = { "Skolt Sami", 13271, "smi", "Latn", display_text = { from = {"'"}, to = {"ˈ"} }, strip_diacritics = {remove_diacritics = c.dotbelow .. "'ˈ"}, sort_key = "sms-sortkey", } m["smt"] = { "Simte", 7521268, "tbq-kuk", } m["smu"] = { "Somray", 6583612, "mkh-pea", } m["smv"] = { "Samvedi", 6345632, "inc-sou", } m["smw"] = { "Sumbawa", 3182585, "poz-bss", "Latn", } m["smx"] = { "Samba", 11120157, "bnt-pen", "Latn", } m["smy"] = { "Semnani", 14531212, "xme", "fa-Arab, Latn", } m["smz"] = { "Simeku", 7517534, "paa-sbo", "Latn", } m["snb"] = { "Sebuyau", 7442836, "poz-mly", "Latn", } m["snc"] = { "Sinaugoro", 4170719, "poz-ocw", "Latn", } m["sne"] = { "Bau Bidayuh", 2891938, "day", "Latn", } m["snf"] = { "Noon", 36304, "alv-cng", "Latn", } m["sng"] = { "Sanga (Congo)", 3438316, "bnt-lub", "Latn", } m["sni"] = { "Sensi", 7451029, "sai-pan", "Latn", } m["snj"] = { "Riverain Sango", 25559751, "crp", "Latn", ancestors = "ngb", } m["snk"] = { "Soninke", 36660, "dmn-snb", "Latn", } m["snl"] = { "Sangirë", --"Sangil", 3472206, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sangire-2/", --TLCHANGE english_name = "Sangil" --TLCHANGE } m["snm"] = { "Southern Ma'di", 15637273, "csu-mma", } m["snn"] = { "Siona", 3485116, "sai-tuc", "Latn", } -- [sno] Snohomish is treated as part of [lut] Lushootseed m["snp"] = { "Siane", 7506812, "ngf-gor", "Latn", } m["snq"] = { "Sangu (Gabon)", 36609, "bnt-sir", "Latn", } m["snr"] = { "Sihan", 7513400, "ngf-gum", "Latn", } m["sns"] = { "Nahavaq", 2160435, "poz-vnc", "Latn", } m["snu"] = { "Senggi", 7929052, "paa-war", "Latn", } m["snv"] = { "Sa'ban", 3474891, "poz-swa", "Latn", } m["snw"] = { "Selee", 36272, "alv-ntg", "Latn", } m["snx"] = { "Sam", 7408387, "ngf-min", "Latn", } m["sny"] = { "Saniyo-Hiyewe", 7418302, "paa-sep", "Latn", } m["snz"] = { "Kou", 7525035, -- also 4803639 "ngf-eva", "Latn", } m["soa"] = { "Thai Song", 7709159, "tai-swe", "Tavt, Thai", --translit = "Tavt-translit", sort_key = { from = {"([ꪵꪶꪹꪻꪼ])([ꪀ-ꪯ])", "([เแโใไ])([ก-ฮ])"}, to = {"%2%1", "%2%1"} }, } m["sob"] = { "Sobei", 3121035, "poz-ocw", "Latn", } m["soc"] = { "Soko", 7555138, "bnt-ske", "Latn", } m["sod"] = { "Songoora", 7561296, "bnt-lgb", "Latn", } m["soe"] = { "Songomeno", 5713543, "bnt-bsh", "Latn", } m["sog"] = { "Sogdian", 205979, "ira-sgc", "Sogd, Mani, Syrc, Sogo", translit = { Sogd = "Sogd-translit", -- Mani translit in [[Module:scripts/data]] Sogo = "Sogo-translit", }, } m["soh"] = { "Aka (Sudan)", 3450949, "sdv-eje", "Latn", } m["soi"] = { "Sonha", 12953890, "inc-eas", } m["sok"] = { "Sokoro", 3441303, "cdc-est", "Latn", } m["sol"] = { "Solos", 3489591, "poz-ocw", } m["soo"] = { "Nsong", 12953148, "bnt-bdz", "Latn", } m["sop"] = { "Songe", 3130911, "bnt-lbn", "Latn", } m["soq"] = { "Kanasi", 11732656, "ngf-dag", "Latn", } m["sor"] = { "Somrai", 3123566, "cdc-est", "Latn", } m["sos"] = { "Seenku", 36274, "dmn-smg", } m["sou"] = { "Southern Thai", 56508, "tai-swe", "Thai", sort_key = "Thai-sortkey", } m["sov"] = { "Sonsorolese", 13281, "poz-mic", "Latn", } m["sow"] = { "Sowanda", 7571845, "paa-war", "Latn", } m["sox"] = { "Swo", 36604, "bnt-mka", "Latn", } m["soy"] = { "Miyobe", 35913, "alv-sav", "Latn", } m["soz"] = { "Temi", 13278, "bnt-kka", "Latn", } m["spb"] = { "Sepa (Indonesia)", 18603687, "poz-cma", "Latn", } m["spc"] = { "Sapé", 2888158, nil, "Latn", } m["spd"] = { "Saep", 7398312, "ngf-yag", "Latn", } m["spe"] = { "Sepa (New Guinea)", 7451725, "poz-ocw", "Latn", } m["spg"] = { "Sian", 7506806, "poz-bnn", } m["spi"] = { "Saponi", 3915418, "paa-rsa", "Latn", } m["spk"] = { "Sengo", 7450584, "paa-nnd", "Latn", } m["spl"] = { "Selepet", 7447917, "ngf-kab", "Latn", } m["spm"] = { "Sepen", 4701931, "paa-rub", "Latn", } m["spn"] = { "Sanapaná", 3033556, "sai-mas", "Latn", } m["spo"] = { "Spokane", 3493704, "sal", } m["spp"] = { "Supyire", 56284, "alv-sma", "Latn", } m["spr"] = { "Saparua", 7420921, "poz-cma", "Latn", } m["sps"] = { "Saposa", 3473187, "poz-ocw", } m["spt"] = { "Spiti Bhoti", 22080879, "sit-las", } m["spu"] = { "Sapuan", 7421168, "mkh-ban", } m["spv"] = { "Sambalpuri", 6433240, "inc-eas", "Orya", translit = "or-translit", ancestors = "or", } m["spx"] = { "Katimugang Piseno", --TLCHANGE 36688, "itc-sbl", "Ital, Latn", -- Ital translit in [[Module:scripts/data]] display_text = { Latn = s["itc-Latn-displaytext"] }, strip_diacritics = { Latn = s["itc-Latn-stripdiacritics"], }, sort_key = { Latn = s["itc-Latn-sortkey"], }, english_name = "South Picene", --TLCHANGE spanish_name = "Piceno meridional", --TLCHANGE } m["spy"] = { "Sabaot", 7395896, "sdv-kln", } m["sqa"] = { "Shama-Sambuga", 3914392, "nic-kmk", "Latn", } m["sqh"] = { "Shau", 3913925, "nic-jer", "Latn", } m["sqk"] = { "Albanian Sign Language", 4709168, "sgn", } m["sqm"] = { "Suma", 11008431, "gba-wes", } m["sqn"] = { "Susquehannock", 3505736, "iro-nor", } m["sqo"] = { "Sorkhei", 3491964, "ira-kms", } m["sqq"] = { "Sou", 16979751, "mkh-ban", } m["sqr"] = { "Arabe Sisilyano", --TLCHANGE 1069489, "sem-arb", "Arab", english_name = "Siculo-Arabic", --TLCHANGE spanish_name = "Árabe siciliano", --TLCHANGE } m["sqs"] = { "Sri Lankan Sign Language", 3915466, "sgn", } m["sqt"] = { "Soqotri", 13283, "sem-sar", "Arab, Latn", } m["squ"] = { "Squamish", 2484579, "sal", "Latn", } m["sra"] = { "Saruga", 7424699, "ngf-han", "Latn", } m["srb"] = { "Sora", 13284, "mun", "Sora, Latn, Orya", } m["sre"] = { "Sara", 33957, "day", } m["srf"] = { "Nafi", 6958174, "poz-ocw", } m["srg"] = { "Sulod", 7636489, "phi", } m["srh"] = { "Sarikoli", 33873, "ira-shr", "Latn, ug-Arab, Cyrl", } m["sri"] = { "Siriano", 3485264, "sai-tuc", "Latn", } m["srk"] = { "Serudung Murut", 7455497, "poz-san", } m["srl"] = { "Isirawa", 4203802, "paa-gkw", "Latn", } m["srm"] = { "Saramaccan", 33779, "crp", "Latn", ancestors = "en, pt", } m["srn"] = { "Sranan Tongo", 33989, "crp", "Latn", ancestors = "en", } m["srq"] = { "Sirionó", 3027953, "tup-gua", "Latn", } m["srr"] = { "Serer", 36284, "alv-fwo", "Latn", } m["srs"] = { "Tsuut'ina", 20825, "ath-nor", "Latn", } m["srt"] = { "Sauri", 7427547, "paa-egb", "Latn", } m["sru"] = { "Suruí", 7646993, "tup", "Latn", } m["srv"] = { "Katimugang Sorsoganon", --TLCHANGE 18755610, "phi", "Latn", english_name = "Waray Sorsogon", --TLCHANGE is_official_kwf_name = "https://kwfwikaatkultura.ph/ortograpiyang-sorsoganon/" --TLCHANGE } m["srw"] = { "Serua", 14916905, "poz-cet", } m["srx"] = { "Sirmauri", 7530505, "him", } m["sry"] = { "Sera", 7452602, "poz-ocw", "Latn", } m["srz"] = { "Shahmirzadi", 12953126, "ira-msh", "fa-Arab", } m["ssb"] = { "Sinama", --"Southern Sama", 3470594, "poz-sbj", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sama-2/", --TLCHANGE english_name = "Southern Sama" --TLCHANGE } m["ssc"] = { "Suba-Simbiti", 7630687, "bnt-lok", "Latn", } m["ssd"] = { "Siroi", 10771067, "ngf-rai", "Latn", } m["sse"] = { "Sama Bangingi", --"Balangingi", 2880535, "poz-sbj", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/sama-2/", --TLCHANGE english_name = "Balangingi" --TLCHANGE } m["ssf"] = { "Thao", 676492, "map", "Latn", } m["ssg"] = { "Seimat", 3182581, "poz-aay", "Latn", } m["ssh"] = { "Arabe Shihhi", --TLCHANGE 56571, "sem-arb", "Arab", strip_diacritics = { remove_diacritics = c.kashida .. c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.superalef, from = {u(0x0671)}, to = {u(0x0627)} }, english_name = "Shihhi Arabic", --TLCHANGE spanish_name = "Árabe shiji" --TLCHANGE } m["ssi"] = { "Sansi", 3309366, "inc-nwe", } m["ssj"] = { "Sausi", 7427605, "ngf-eva", "Latn", } m["ssk"] = { "Sunam", 11002210, "sit-kin", } m["ssl"] = { "Western Sisaala", 11154776, "nic-sis", "Latn", } m["ssm"] = { "Semnam", 7449713, "mkh-asl", "Latn", } m["sso"] = { "Sissano", 7530937, "poz-ocw", "Latn", } m["ssp"] = { "Spanish Sign Language", 3100814, "sgn", } m["ssq"] = { "So'a", 7572120, "poz-cet", "Latn", } m["ssr"] = { "Swiss-French Sign Language", 12953483, "sgn", } m["sss"] = { "Sô", 3082037, "mkh-kat", } m["sst"] = { "Sinasina", 7521813, "ngf-sim", "Latn", } m["ssu"] = { "Susuami", 7649752, "ngf-woj", "Latn", } m["ssv"] = { "Shark Bay", 7489783, "poz-vnn", "Latn", } m["ssx"] = { "Samberigi", 7409020, "ngf-sak", "Latn", } m["ssy"] = { "Saho", 36353, "cus-eas", "Latn, Ethi, Arab", } m["ssz"] = { "Sengseng", 7450601, "poz-ocw", "Latn", } m["stb"] = { "Subanën Tuboy-Salog", --TLCHANGE 12953892, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/subanen-2/", --TLCHANGE english_name = "Northern Subanen" --TLCHANGE } m["std"] = { "Sentinelese", 568377, "qfa-unc", -- presumed Ongan } m["ste"] = { "Liana-Seti", 6539924, "poz-cma", } m["stf"] = { "Seta", 7456326, "paa-trr", "Latn", } m["stg"] = { "Trieng", 22694648, "mkh-ban", } m["sth"] = { "Shelta", 36705, "qfa-mix", "Latn", ancestors = "ga, en", } m["sti"] = { "Bulo Stieng", 15771431, "mkh-ban", "Khmr, Latn", } m["stj"] = { "Matya Samo", 10974879, "dmn-sam", "Latn", } m["stk"] = { "Arammba", 3502094, "paa-ton", "Latn", } m["stm"] = { "Setaman", 7456333, "ngf-mok", "Latn", } m["stn"] = { "Owa", 1324132, "poz-sls", "Latn", } m["sto"] = { "Stoney", 3033570, "sio-dkt", "Latn", } m["stp"] = { "Southeastern Tepehuan", 12953917, "azc-pim", "Latn", } m["stq"] = { "Saterland Frisian", 27154, "gmw-fri", "Latn", } m["str"] = { "Saanich", 36444, "sal", "Latn", } m["sts"] = { "Shumashti", 33777, "inc-kun", "Arab", } m["stt"] = { "Budeh Stieng", 12953891, "mkh-ban", } m["stu"] = { "Samtao", 25559550, "mkh-pal", } m["stv"] = { "Silt'e", 33880, "sem-eth", "Ethi", } m["stw"] = { "Satawalese", 28477, "poz-mic", "Latn", } m["sty"] = { "Siberian Tatar", 4418344, "trk-kno", "Cyrl", } m["sua"] = { "Sulka", 7636341, "qfa-iso", -- Papuan; isolate in Glottolog and Palmer (2018) "Latn", } m["sub"] = { "Suku", 12953160, "bnt-yak", "Latn", } m["suc"] = { "Subanën Siocon", --TLCHANGE 16113894, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/subanen-2/", --TLCHANGE english_name = "Western Subanon", --TLCHANGE } m["sue"] = { "Suena", 7634386, "ngf-nbi", "Latn", } m["sug"] = { "Suganga", 7634706, "ngf-msu", "Latn", } m["sui"] = { "Suki", 2089984, "ngf-gsu", "Latn", } m["suk"] = { "Sukuma", 2638144, "bnt-tkm", "Latn", } m["suo"] = { "Bouni", 65043887, "paa-pio", "Latn", } m["suq"] = { "Suri", 5364172, "sdv", } m["sur"] = { "Mwaghavul", 3440486, "cdc-wst", "Latn", } m["sus"] = { "Susu", 33990, "dmn-sya", "Latn", } m["sut"] = { "Subtiaba", 3915405, "omq", "Latn", } m["suv"] = { "Puroik", 56408, "sit-khb", "Beng, Deva, Latn", ancestors = "sit-khp-pro", } m["suw"] = { "Sumbwa", 7637055, "bnt-glb", "Latn", } m["sux"] = { "Sumerian", 36790, "qfa-iso", "Xsux, Latn", } m["suy"] = { "Suyá", 3505859, "sai-nje", "Latn", } m["suz"] = { "Sunwar", 56549, "sit-kiw", "Deva, Sunu" } m["sva"] = { "Svan", 34067, "ccs", "Geor, Cyrl", translit = { Geor = "sva-translit", }, override_translit = true, } m["svb"] = { "Ulau-Suain", 7878769, "poz-ocw", "Latn", } m["svc"] = { "Vincentian Creole English", 3501785, "crp", "Latn", ancestors = "en", } m["sve"] = { "Serili", 7454834, "poz-tim", } m["svk"] = { "Slovakian Sign Language", 7541557, "sgn", } m["svm"] = { "Slavomolisano", 36254, "zls", "Latn", ancestors = "sh", } m["svs"] = { "Savosavo", 3130296, "qfa-dis", -- Papuan; isolate in Glottolog; in the tentative Central Solomons family by Ross (2005) and Pedrós -- (2015) "Latn", } m["svx"] = { "Skalvian", 3486125, "bat-wes", "Latn", } m["swb"] = { "Maore Comorian", 34075, "bnt-com", "Latn", sort_key = "bnt-com-sortkey", } m["swf"] = { "Sere", 7453056, "nic-ser", "Latn", } m["swg"] = { "Swabian", 327274, "gmw-hgm", "Latn", ancestors = "gsw", } m["swi"] = { "Sui", 3112388, "qfa-kms", "Latn, Shui, Hani", sort_key = {Hani = "Hani-sortkey"}, } m["swj"] = { "Sira", 36599, "bnt-sir", "Latn", } m["swl"] = { "Swedish Sign Language", 36558, "sgn", } m["swm"] = { "Samosa", 7410037, "ngf-nwh", "Latn", } m["swn"] = { "Sokna", 2988323, "ber", } m["swo"] = { "Shanenawa", 61974839, "sai-pan", "Latn", } m["swp"] = { "Suau", 3502368, "poz-ocw", } m["swq"] = { "Sharwa", 56791, "cdc-cbm", "Latn", } m["swr"] = { "Saweru", 3474649, "paa-ysa", "Latn", } m["sws"] = { "Seluwasan", 7448845, "poz-cet", } m["swt"] = { "Sawila", 7428639, "paa-alp", "Latn", } m["swu"] = { "Suwawa", 7650588, "phi", } m["sww"] = { "Sowa", 7571843, "poz-vnn", "Latn", } m["swx"] = { "Suruahá", 3114402, "auf", } m["swy"] = { "Sarua", 56261, "cdc-est", "Latn", } m["sxb"] = { "Suba", 33916, "bnt-lok", "Latn", } m["sxc"] = { "Sicanian", 36335, "qfa-unc", -- extinct, lack of data; only names deciphered "Polyt", } m["sxe"] = { "Sighu", 36431, "bnt-kel", "Latn", } m["sxg"] = { "Shixing", 56337, "sit-nax", "Latn", } m["sxk"] = { "Southern Kalapuya", 3192122, "nai-klp", } m["sxl"] = { "Selonian", 36491, "bat-eas", "Latn", } m["sxm"] = { "Samre", 6583615, "mkh-pea", } m["sxn"] = { "Sangir", 25714758, "phi", "Latn", } m["sxo"] = { "Sorothaptic", 2762254, } m["sxr"] = { "Saaroa", 716599, "map", "Latn", } m["sxs"] = { "Sasaru", 3913384, "alv-yek", "Latn", } -- "sxu" "Upper Saxon" IS SUBSUMED INTO "gmw-ecg" "East Central German" m["sxw"] = { "Saxwe Gbe", 7428892, "alv-pph", "Latn", } m["sya"] = { "Siang", 3482903, } m["syb"] = { "Subanën Sindangan", --TLCHANGE 12953893, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/subanen-2/", --TLCHANGE english_name = "Central Subanen" --TLCHANGE } m["syc"] = { "Classical Syriac", 33538, "sem-are", "Syrc", strip_diacritics = {remove_diacritics = c.macron .. c.diaer .. c.macronbelow .. u(0x0730) .. "-" .. u(0x0748)}, } m["syi"] = { "Seki", 36547, "bnt-kel", "Latn", } m["syk"] = { "Sukur", 56292, "cdc-cbm", "Latn", } m["syl"] = { "Sylheti", 2044560, "inc-bas", "Sylo, Beng", ancestors = "inc-obn", translit = "syl-translit", } m["sym"] = { "Maya Samo", 10950421, "dmn-sam", "Latn", } m["syn"] = { "Senaya", 33914, "sem-nna", } m["syo"] = { "Suoy", 7641864, "mkh-pea", } m["sys"] = { "Sinyar", 56840, "csu", "Latn", } m["syw"] = { "Kagate", 12952538, "sit-kyk", "Deva", } m["syx"] = { "Osamayi", 7408415, "bnt-kel", "Latn", } m["syy"] = { "Al-Sayyid Bedouin Sign Language", 2915457, "sgn", } m["sza"] = { "Semelai", 3111827, "mkh-asl", "Latn", } m["szb"] = { "Ngalum", 11732516, "ngf-okk", "Latn", } m["szc"] = { "Semaq Beri", 7449119, "mkh-asl", } m["szd"] = { "Seru", 7455488, "poz-bnn", "Latn", } m["sze"] = { "Seze", 373683, "omv-mao", "Latn", } m["szg"] = { "Sengele", 7450555, "bnt-mon", "Latn", } m["szl"] = { "Silesyo", --TLCHANGE 30319, "zlw-lch", "Latn", ancestors = "zlw-opl", english_name = "Silesian", --TLCHANGE spanish_name = "Silesio" --TLCHANGE } m["szn"] = { "Sula", 3503403, "poz-cma", "Latn", } m["szp"] = { "Suabo", 7630429, "ngf-sbh", "Latn", } m["szv"] = { "Isubu", 35431, "bnt-saw", "Latn", } m["szw"] = { "Sawai", 3447258, "poz-hce", "Latn", } m["szy"] = { "Sakizaya", 718269, "map", "Latn", } return require("Module:languages").finalizeData(m, "language") qas2uldpydm8eusyuzplx1vhqn5c0ur Module:quote 828 33065 178479 178376 2026-10-27T03:14:31Z GinawaSaHapon 3989 178479 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun .. "s" local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun .. "s" add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "in " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export aer3nzwf22gf7ncdb46c9i9fglmzcl3 178487 178479 2026-10-27T03:30:06Z GinawaSaHapon 3989 178487 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun .. "s" local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun .. "s" add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export rteqlrg9flrq87dv2jnc1x5odcwk91r 178516 178487 2026-10-27T06:16:32Z GinawaSaHapon 3989 178516 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks fofr a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun .. "s" local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun .. "s" add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("patnugot", "patnugot ni") add_sg_and_pl_authorlike("nagkompila", "kinompila ni") add_sg_and_pl_authorlike("direktor", "direksiyon ni") add_authorlike("titik", nil, " (titik)", nil, " nagsulat") add_authorlike("nagsalin ng titik", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("kompositor", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("patnugot", "patnugot ni") add_sg_and_pl_authorlike("nagkompila", "kinompila ni") add_sg_and_pl_authorlike("direktor", "direksiyon ni") add_authorlike("titik", nil, " (titik)", nil, " nagsulat") add_authorlike("nagsalin ng titik", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("kompositor", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export p6pjl741gfs359y7ann1hbrsshkjjt2 178517 178516 2026-10-27T06:29:38Z GinawaSaHapon 3989 Tanggalin ang pagbabagong [[Special:Diff/178516|178516]] ni [[Special:Contributions/GinawaSaHapon|GinawaSaHapon]] ([[User talk:GinawaSaHapon|Usapan]]) 178517 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("di-kilala" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export 3flgko8c5rny0u9500ays35etk03mij 178518 178517 2026-10-27T06:30:17Z GinawaSaHapon 3989 178518 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun .. "s" local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun .. "s" add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export rteqlrg9flrq87dv2jnc1x5odcwk91r 178519 178518 2026-10-27T06:37:05Z GinawaSaHapon 3989 178519 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> sa |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) -- if sgval and plval then -- error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) -- end if sgval or plval then local verbed_by = verbed .. " ni " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("patnugot", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export 7wfjnesfmylvxygbgk4lnbc4z8t6cny 178520 178519 2026-10-27T06:40:03Z GinawaSaHapon 3989 178520 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> sa |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) -- if sgval and plval then -- error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) -- end if sgval or plval then local verbed_by = verbed local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export 6ez2swrxry8yuk71qb76wrqjrrcuoxb 178521 178520 2026-10-27T06:40:40Z GinawaSaHapon 3989 178521 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" local string_pattern_escape_module = "Module:string/patternEscape" local string_replacement_escape_module = "Module:string/replacementEscape" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) end local function find_best_script_without_lang(...) find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang return find_best_script_without_lang(...) end local function find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) -- pluralize = require(en_utilities_module).pluralize return ... end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function shallow_copy(...) shallow_copy = require(table_module).shallowCopy return shallow_copy(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) end -- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space. local function ine(arg) if not arg then return nil elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Apendise:Glosaryo#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate, need_date = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "di-kilalang may-akda" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> sa |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "at" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "kasama si " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) -- if sgval and plval then -- error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) -- end if sgval or plval then local verbed_by = verbed .. " " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("sa ") -- tl change: in author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("sa ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "at") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "at") if format_as_cite then if role then if actor then add_with_sep(actor .. " bilang ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end else if role then add_with_sep("sinalita ni " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") author_outputted = false add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin") add_sg_and_pl_authorlike("editor", "patnugot ni") add_sg_and_pl_authorlike("compiler", "kinompila ni") add_sg_and_pl_authorlike("director", "direksiyon ni") add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat") add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik") add_authorlike("composer", nil, " (musika)", nil, " kompositor") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog local langs = format_langs(args[1] or args.lang) if langs then add(" (sa wikang " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep("ika-" .. edition .. " labas") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "bilang") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "bilang") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "sa wikang " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "sinipi sa wikang " .. format_langs(quotelang)) end insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "sa wikang " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "at") if artist then add_with_sep("itinanghal ni " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "at") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("binanggit sa " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "at") if source then add_with_sep("nagmula sa " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "at") local origtype = a("deriv") or "salin" if original or by then add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "sa " .. format_langs(origlang) end if origworklang then origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "at") if formatted_date_published then add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or "")) elseif platform then add_with_sep("sa pamamagitan ng " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " ang orihinal] sa ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then local megalodon_date = string.sub(archiveurl, 22, 25) .. "-" .. string.sub(archiveurl, 27, 28) .. "-" .. string.sub(archiveurl, 29, 30) add(format_date(megalodon_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "bahagi ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", eksena: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "pahina", ", ") handle_numeric_param("column", a("column_prefix") or "hanay", ", ") handle_numeric_param("line", a("line_prefix") or "linya", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("nilathala bilang") else add("muling nilathala") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not termlang and "" or (#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, termlang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following: ** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export 8q8mb7syrv6kcwj1f293gga1lnbexqm Module:languages/data/3/d 828 33071 178464 176479 2026-10-27T02:09:38Z GinawaSaHapon 3989 178464 Scribunto text/plain local m_langdata = require("Module:languages/data") -- 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 local c = m_langdata.chars local p = m_langdata.puaChars local s = m_langdata.shared local m = {} m["daa"] = { "Dangaléat", 942591, "cdc-est", "Latn", } m["dac"] = { "Dambi", 12629491, "poz-ocw", "Latn", } m["dad"] = { "Marik", 6763404, "poz-ocw", "Latn", } m["dae"] = { "Duupa", 35263, "alv-dur", "Latn", } m["dag"] = { "Dagbani", 32238, "nic-dag", "Latn", } m["dah"] = { "Gwahatike", 5623246, "ngf-war", "Latn", } m["dai"] = { "Day", 35163, "alv-mbd", "Latn", } m["daj"] = { "Dar Fur Daju", 56370, "sdv-daj", "Latn", } m["dak"] = { "Dakota", 530384, "sio-dkt", "Latn", } m["dal"] = { "Dahalo", 35143, "cus", "Latn", } m["dam"] = { "Damakawa", 1158134, "nic-knn", "Latn", } m["dao"] = { "Daai Chin", 860029, "tbq-kuk", "Latn", } m["daq"] = { "Dandami Maria", 12952805, "dra-mdy", "Deva", } m["dar"] = { "Dargwa", 32332, "cau-drg", "Cyrl, Latn, Arab", translit = {Cyrl = "dar-translit"}, override_translit = true, display_text = {Cyrl = s["cau-Cyrl-displaytext"]}, strip_diacritics = { Cyrl = s["cau-Cyrl-stripdiacritics"], Latn = s["cau-Latn-stripdiacritics"], }, sort_key = { Cyrl = { from = { "къкъ", "хьхь", -- 4 chars "гъ", "гь", "гӏ", "ё", "къ", "кь", "кӏ", "пп", "пӏ", "сс", "тт", "тӏ", "хх", "хъ", "хь", "хӏ", "цц", "цӏ", "чч", "чӏ" -- 2 chars }, to = { "к" .. p[2], "х" .. p[4], "г" .. p[1], "г" .. p[2], "г" .. p[3], "е" .. p[1], "к" .. p[1], "к" .. p[3], "к" .. p[4], "п" .. p[1], "п" .. p[2], "с" .. p[1], "т" .. p[1], "т" .. p[2], "х" .. p[1], "х" .. p[2], "х" .. p[3], "х" .. p[5], "ц" .. p[1], "ц" .. p[2], "ч" .. p[1], "ч" .. p[2] } }, }, } m["das"] = { "Daho-Doo", 3915369, "kro-wee", "Latn", } m["dau"] = { "Dar Sila Daju", 7514020, "sdv-daj", "Latn", } m["dav"] = { "Taita", 2387274, "bnt-cht", "Latn", } m["daw"] = { "Davawenyo", 5228174, "phi", "Latn", } m["dax"] = { "Dayi", 10467281, "aus-yol", "Latn", } m["daz"] = { "Dao", 5221513, "ngf-pan", "Latn", } m["dba"] = { "Bangime", 1982696, "qfa-iso", -- southern Mali "Latn", } m["dbb"] = { "Deno", 56275, "cdc-wst", "Latn", } m["dbd"] = { "Dadiya", 3914436, "alv-wjk", "Latn", } m["dbe"] = { "Dabe", 5207451, "paa-tor", "Latn", } m["dbf"] = { "Edopi", 12953516, "paa-lpl", "Latn", } m["dbg"] = { "Dogul Dom", 3912880, "nic-npd", "Latn", } m["dbi"] = { "Doka", 3913293, "nic-plc", "Latn", } m["dbj"] = { "Ida'an", 3041552, "poz-san", "Latn", } m["dbl"] = { "Dyirbal", 35465, "aus-dyb", "Latn", } m["dbm"] = { "Duguri", 7194057, "nic-jrw", "Latn", } m["dbn"] = { "Duriankere", 5316627, "ngf-sbh", "Latn", } m["dbo"] = { "Dulbu", 5313310, "nic-jrn", "Latn", } m["dbp"] = { "Duwai", 56301, "cdc-wst", "Latn", } m["dbq"] = { "Daba", 3913342, "cdc-cbm", "Latn", } m["dbr"] = { "Dabarre", 3447286, "cus-som", } m["dbt"] = { "Ben Tey", 4886561, "nic-nwa", "Latn", } m["dbu"] = { "Bondum Dom Dogon", 3912758, "nic-npd", "Latn", } m["dbv"] = { "Dungu", 5315230, "nic-kau", "Latn", } m["dbw"] = { "Bankan Tey Dogon", 4856243, "nic-nwa", "Latn", } m["dby"] = { "Dibiyaso", 5272268, "qfa-dis", -- Papuan; isolate per Glottolog, unclassified per Pawley and Hammarström (2018), sometimes classified with Bosavi languages "Latn", } m["dcc"] = { "Deccani", 669431, "inc-hnd", "ur-Arab", ancestors = "ur", } m["dcr"] = { "Negerhollands", 1815830, "crp", "Latn", ancestors = "nl", } m["dda"] = { "Dadi Dadi", 50207890, "aus-pam", "Latn", } m["ddd"] = { "Dongotono", 56676, "sdv-lma", "Latn", } m["dde"] = { "Doondo", 11003401, "bnt-kng", "Latn", } m["ddg"] = { "Fataluku", 35353, "paa-eti", "Latn", } m["ddi"] = { "Diodio", 3028668, "poz-ocw", "Latn", } m["ddj"] = { "Jaru", 3162806, "aus-pam", "Latn", } m["ddn"] = { "Dendi", 35164, "son", "Latn", } m["ddo"] = { "Tsez", 34033, "cau-wts", "Cyrl", translit = "ddo-translit", display_text = {Cyrl = s["cau-Cyrl-displaytext"]}, strip_diacritics = {Cyrl = s["cau-Cyrl-stripdiacritics"]}, } m["ddr"] = { "Dhudhuroa", 5269842, "aus-pam", "Latn", } m["dds"] = { "Donno So Dogon", 1234776, "nic-dge", "Latn", } m["ddw"] = { "Dawera-Daweloor", 5242304, "poz-tim", "Latn", } m["dec"] = { "Dagik", 35125, "alv-tal", "Latn", } m["ded"] = { "Dedua", 5249850, "ngf-huo", "Latn", } m["dee"] = { "Dewoin", 3914892, "kro-wkr", "Latn", } m["def"] = { "Dezfuli", 4115412, "ira-swi", "Arab", } m["deg"] = { "Degema", 35182, "alv-dlt", "Latn", } m["deh"] = { "Dehwari", 5704314, "ira-swi", "fa-Arab", ancestors = "fa", } m["dei"] = { "Demisa", 56380, "paa-egb", "Latn", } -- "dek" is no longer an ISO code; spurious m["dem"] = { "Dem", 5254989, "qfa-dis", -- Papuan; isolate in Glottolog; unclassified in Palmer (2018); grouped with Amung by Usher, ultimately in TNG "Latn", } m["dep"] = { "Pidgin Delaware", 1183938, "crp", "Latn", ancestors = "unm", } -- deq is not included, see [[WT:LT]] m["der"] = { "Deori", 56478, "tbq-bdg", "Beng, Latn", } m["des"] = { "Desano", 962392, "sai-tuc", "Latn", } m["dev"] = { "Domung", 5291378, "ngf-yup", "Latn", } m["dez"] = { "Dengese", 2909984, "bnt-tet", "Latn", } m["dga"] = { "Southern Dagaare", 35159, "nic-mre", "Latn", } m["dgb"] = { "Bunoge", 4985178, "nic-dgw", "Latn", } m["dgc"] = { "Agta Dumagat Casiguran", --"Casiguran Dumagat Agta", 5313599, "phi", "Latn", english_name = "Casiguran Dumagat Agta", --TLCHANGE } m["dgd"] = { "Dagaari Dioula", 11153465, "nic-mre", "Latn", } m["dge"] = { "Degenan", 5251770, "ngf-war", "Latn", } m["dgg"] = { "Doga", 3033726, "poz-ocw", "Latn", } m["dgh"] = { "Dghwede", 56293, "cdc-cbm", "Latn", } m["dgi"] = { "Northern Dagara", 11004218, "nic-mre", "Latn", } m["dgk"] = { "Dagba", 12952357, "csu-sar", "Latn", } m["dgn"] = { "Dagoman", 10465931, "aus-yng", "Latn", } m["dgo"] = { "Hindi Dogri", nil, "him", "Deva, Arab, Takr", ancestors = "doi", } m["dgr"] = { "Dogrib", 20979, "ath-nor", "Latn", } m["dgs"] = { "Dogoso", 35343, "nic-gur", } m["dgt"] = { "Ntra'ngith", 6983809, "aus-pam", "Latn", } -- dgu is not a language; see [[w:Dhekaru]] m["dgw"] = { "Daungwurrung", 5228050, "aus-pam", "Latn", } m["dgx"] = { "Doghoro", 12952392, "ngf-bin", "Latn", } m["dgz"] = { "Daga", 5208442, "ngf-dag", "Latn", } m["dhg"] = { "Dhangu", 5268960, "aus-yol", "Latn", } m["dhd"] = { "Dhundhari", 633359, "raj", "Deva", translit = "hi-translit", } m["dhi"] = { "Dhimal", 35229, "sit-dhi", "Deva", } m["dhl"] = { "Dhalandji", 5268787, "aus-psw", "Latn", } m["dhm"] = { "Zemba", 3502283, "bnt-swb", "Latn", ancestors = "hz", } m["dhn"] = { "Dhanki", 5268992, "inc-bhi", } m["dho"] = { "Dhodia", 5269658, "inc-bhi", "Deva", } m["dhr"] = { "Tharrgari", 10470289, "aus-psw", "Latn", } m["dhs"] = { "Dhaiso", 11001788, "bnt-kka", "Latn", } m["dhu"] = { "Dhurga", 1285318, "aus-yuk", "Latn", } m["dhv"] = { "Drehu", 3039319, "poz-cln", "Latn", } m["dhw"] = { "Danuwar", 3522797, "inc-bhi", "Deva", } m["dhx"] = { "Dhungaloo", 16960599, "aus-pam", "Latn", } m["dia"] = { "Dia", 3446591, "paa-wap", "Latn", } m["dib"] = { "South Central Dinka", 35154, "sdv-dnu", "Latn", ancestors = "din", } m["dic"] = { "Lakota Dida", 11001730, "kro-did", "Latn", } m["did"] = { "Didinga", 56365, "sdv", "Latn", } m["dif"] = { "Dieri", 25559563, "aus-kar", "Latn", } m["dig"] = { "Digo", 3362072, "bnt-mij", "Latn", } -- "dih" is split into nai-ipa, nai-kum, nai-tip, see [[WT:LT]] m["dii"] = { "Dimbong", 35196, "bnt-baf", "Latn", } m["dij"] = { "Dai", 5209056, "poz-tim", "Latn", } m["dik"] = { "Southwestern Dinka", 36540, "sdv-dnu", "Latn", ancestors = "din", } m["dil"] = { "Dilling", 35152, "nub-hil", "Latn", } m["dim"] = { "Dime", 35311, "omv-aro", } m["din"] = { "Dinka", 56466, "sdv-dnu", "Latn", } m["dio"] = { "Dibo", 3914891, "alv-ngb", "Latn", } m["dip"] = { "Northeastern Dinka", 36246, "sdv-dnu", "Latn", ancestors = "din", } m["dir"] = { "Dirim", 11130804, "nic-dak", "Latn", } m["dis"] = { "Dimasa", 56664, "tbq-bdg", "Latn, Beng", } m["diu"] = { "Gciriku", 3780954, "bnt-kav", "Latn", } m["diw"] = { "Northwestern Dinka", 36249, "sdv-dnu", "Latn", ancestors = "din", } m["dix"] = { "Dixon Reef", 5284967, "poz-vnc", "Latn", } m["diy"] = { "Diuwe", 5283765, "ngf-asm", "Latn", } m["diz"] = { "Ding", 35202, "bnt-bdz", "Latn", } m["dja"] = { "Djadjawurrung", 5285190, "aus-pam", "Latn", } m["djb"] = { "Djinba", 5285351, "aus-yol", "Latn", } m["djc"] = { "Dar Daju Daju", 5209890, "sdv-daj", "Latn", } m["djd"] = { "Jaminjung", 6147825, "aus-mir", "Latn", } m["dje"] = { "Zarma", 36990, "son", "Latn, Arab, Brai", } m["djf"] = { "Djangun", 10474818, "aus-pmn", "Latn", } m["dji"] = { "Djinang", 5285350, "aus-yol", "Latn", } m["djj"] = { "Ndjébbana", 5285274, "aus-arn", "Latn", } m["djk"] = { "Aukan", 2659044, "crp", "Latn, Afak", ancestors = "en", } m["djl"] = { "Djiwarli", 2669569, "aus-psw", "Latn", } m["djm"] = { "Jamsay", 3913290, "nic-pld", "Latn", } m["djn"] = { "Djauan", 13553748, "aus-gun", "Latn", } m["djo"] = { "Jangkang", 12952388, "day", } m["djr"] = { "Djambarrpuyngu", 3915679, "aus-yol", "Latn", } m["dju"] = { "Kapriman", 6367199, "paa-sep", "Latn", } m["djw"] = { "Djawi", 3913844, "aus-nyu", "Latn", ancestors = "bcj", } m["dka"] = { "Dakpa", 3695189, "sit-ebo", "Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["dkk"] = { "Dakka", 5209962, "poz-ssw", } m["dkr"] = { "Kuijau", 13580777, "poz-bnn", } m["dks"] = { "Southeastern Dinka", 36538, "sdv-dnu", "Latn", ancestors = "din", } m["dkx"] = { "Mazagway", 6798209, "cdc-cbm", "Latn", } m["dlg"] = { "Dolgano", --TLCHANGE 32878, "trk-nsb", "Cyrl", sort_key = { from = {"ё", "һ", "ӈ", "ө", "ү"}, to = {"е" .. p[1], "к" .. p[1], "н" .. p[1], "о" .. p[1], "у" .. p[1]} }, english_name = "Dolgan", --TLCHANGE spanish_name = "Dolgano", --TLCHANGE } m["dlk"] = { "Dahalik", 32260, "sem-eth", "Ethi", translit = "Ethi-translit", } m["dlm"] = { "Dalmatiko", --TLCHANGE 35527, "roa-dal", "Latn", english_name = "Dalmatian", --TLCHANGE spanish_name = "Dalmático", --TLCHANGE } m["dln"] = { "Darlong", 5224029, "tbq-kuk", "Latn", } m["dma"] = { "Duma", 35319, "bnt-nze", "Latn", } m["dmb"] = { "Mombo Dogon", 6897074, "nic-dgw", "Latn", } m["dmc"] = { "Gavak", 5277406, "ngf-nad", "Latn", } m["dmd"] = { "Madhi Madhi", 6727353, "aus-pam", "Latn", } m["dme"] = { "Dugwor", 56313, "cdc-cbm", "Latn", } m["dmf"] = { "Medefaidrin", 1519764, "art", "Medf", type = "appendix-constructed", } m["dmg"] = { "Upper Kinabatangan", 16109975, "poz-san", "Latn", } m["dmk"] = { "Domaaki", 32900, "inc-wes", "Arab", } m["dml"] = { "Dameli", 32288, "inc-kun", } m["dmm"] = { "Dama (Nigeria)", 5211865, "alv-mbm", "Latn", } m["dmo"] = { "Kemezung", 35562, "nic-bbe", "Latn", } m["dmr"] = { "East Damar", 5328200, "poz-cet", "Latn", } m["dms"] = { "Dampelas", 5212928, "poz-tot", "Latn", } m["dmu"] = { "Dubu", 7692059, "paa-wpw", "Latn", } m["dmv"] = { "Dumpas", 12953512, "poz-san", "Latn", } m["dmw"] = { "Mudburra", 6931573, "aus-pam", "Latn", } m["dmx"] = { "Dema", 3553423, "bnt-sho", "Latn", } m["dmy"] = { "Demta", 14466283, "paa-sen", "Latn", } m["dna"] = { "Upper Grand Valley Dani", 12952361, "ngf-gvd", "Latn", } m["dnd"] = { "Daonda", 5221528, "paa-war", "Latn", } m["dne"] = { "Ndendeule", 6983725, "bnt-mbi", "Latn", } m["dng"] = { "Dunggano", --TLCHANGE 33050, "zhx-man", "Cyrl, Hants, Arab", generate_forms = "zh-generateforms", translit = {Cyrl = "dng-translit"}, sort_key = { Cyrl = { from = {"ё", "ә", "җ", "ң", "ў", "ү"}, to = {"е" .. p[1], "е" .. p[2], "ж" .. p[1], "н" .. p[1], "у" .. p[1], "у" .. p[2]} }, Hani = "Hani-sortkey", }, english_name = "Dungan", --TLCHANGE spanish_name = "Dungano", --TLCHANGE } m["dni"] = { "Lower Grand Valley Dani", 12635807, "ngf-gvd", "Latn", } m["dnj"] = { "Dan", 1158971, "dmn-mda", "Latn", } m["dnk"] = { "Dengka", 5256954, "poz-tim", "Latn", } m["dnn"] = { "Dzuun", 10973260, "dmn-smg", "Latn", } m["dno"] = { "Ndrulo", 60785094, "csu-lnd", } m["dnr"] = { "Danaru", 5214932, "ngf-pek", "Latn", } m["dnt"] = { "Mid Grand Valley Dani", 12952359, "ngf-gvd", "Latn", } m["dnu"] = { "Danau", 5013745, "mkh-pal", "Mymr", } m["dnv"] = { "Danu", 5221251, "tbq-brm", "Mymr", ancestors = "obr", } m["dnw"] = { "Western Dani", 7987774, "ngf-cda", "Latn", } m["dny"] = { "Dení", 56562, "auf", "Latn", } m["doa"] = { "Dom", 5289770, "ngf-sim", "Latn", } m["dob"] = { "Dobu", 952133, "poz-ocw", "Latn", } m["doc"] = { "Northern Kam", 17195499, "qfa-tak", "Latn", } m["doe"] = { "Doe", 5288055, "bnt-ruv", "Latn", } m["dof"] = { "Domu", 5291375, "paa-mal", "Latn", } m["doh"] = { "Dong", 3438405, "nic-dak", "Latn", } m["doi"] = { "Dogri", 32730, "him", "Deva, Takr, fa-Arab, Dogr", translit = { Deva = "hi-translit", Dogr = "Dogr-translit", }, } m["dok"] = { "Dondo", 5295571, "poz-tot", "Latn", } m["dol"] = { "Doso", 4167202, "paa-dtu", "Latn", } m["don"] = { "Doura", 7829037, "poz-ocw", "Latn", } m["doo"] = { "Dongo", 35303, "nic-mbc", "Latn", } m["dop"] = { "Lukpa", 3258739, "nic-gne", "Latn", } m["doq"] = { "Dominican Sign Language", 5290820, "sgn", "Latn", -- when documented } m["dor"] = { "Dori'o", 3037084, "poz-sls", "Latn", } m["dos"] = { "Dogosé", 3913314, "nic-gur", "Latn", } m["dot"] = { "Dass", 3441293, "cdc-wst", "Latn", } m["dov"] = { "Toka-Leya", 11001779, "bnt-bot", "Latn", ancestors = "toi", } m["dow"] = { "Doyayo", 35299, "alv-dur", "Latn", } m["dox"] = { "Bussa", 35123, "cus-eas", "Latn", } m["doy"] = { "Dompo", 35270, "alv-gng", "Latn", } m["doz"] = { "Dorze", 56336, "omv-nom", "Latn", } m["dpp"] = { "Papar", 7132487, "poz-san", "Latn", } m["drb"] = { "Dair", 12952360, "nub-hil", "Latn", } m["drc"] = { "Minderico", 6863806, "roa-gap", "Latn", ancestors = "pt", } m["drd"] = { "Darmiya", 5224058, "sit-alm", } m["drg"] = { "Rungus", 6897407, "poz-san", "Latn", } m["dri"] = { "Lela", 3914004, "nic-knn", "Latn", } m["drl"] = { "Baagandji", 5223941, "aus-pam", "Latn", } m["drn"] = { "West Damar", 3450459, "poz-tim", "Latn", } m["dro"] = { "Daro-Matu Melanau", 5224156, "poz-bnn", "Latn", } m["drq"] = { "Dura", 3449842, "sit-gma", "Deva", } m["drs"] = { "Gedeo", 56622, "cus-hec", "Ethi", } m["dru"] = { "Rukai", 49232, "map", "Latn", ancestors = "dru-pro", } m["dry"] = { "Darai", 46995026, "inc-bhi", "Deva", } m["dsb"] = { "Lower Sorbian", 13286, "wen", "Latn", sort_key = s["wen-sortkey"], standard_chars = "AaBbCcČčĆćDdEeĚěFfGgHhIiJjKkŁłLlMmNnŃńOoÓóPpRrŔŕSsŠšŚśTtUuWwYyZzŽžŹź" .. c.punc, } m["dse"] = { "Dutch Sign Language", 2201099, "sgn", "Latn", -- when documented } m["dsh"] = { "Daasanach", 56637, "cus-eas", "Latn", } m["dsi"] = { "Disa", 3914455, "csu-bgr", "Latn", } m["dsl"] = { "Danish Sign Language", 2605298, "sgn", "Latn", -- when documented } m["dsn"] = { "Dusner", 5316948, "poz-hce", "Latn", } m["dso"] = { "Desiya", 12629755, "inc-eas", "Orya", ancestors = "or", } m["dsq"] = { "Tadaksahak", 36568, "son", "Arab, Latn", } m["dta"] = { "Daur", 32430, "xgn", "Latn, Hani, Cyrl, Mong", ancestors = "xng", -- Mong translit, display_text and strip_diacritics in [[Module:scripts/data]] sort_key = {Hani = "Hani-sortkey"}, } m["dtb"] = { "Labuk-Kinabatangan Kadazan", 5330240, "poz-san", "Latn", } m["dtd"] = { "Ditidaht", 13728042, "wak", "Latn", } m["dth"] = { -- contrast 'rrt' "Adithinngithigh", 4683034, "aus-pmn", "Latn", } m["dti"] = { "Ana Tinga Dogon", 4750346, "qfa-dgn", "Latn", } m["dtk"] = { "Tene Kan Dogon", 11018863, "nic-pld", "Latn", } m["dtm"] = { "Tomo Kan Dogon", 11137719, "nic-pld", "Latn", } m["dto"] = { "Tommo So", 47012992, "nic-dge", "Latn", } m["dtp"] = { "Central Dusun", 5317225, "poz-san", "Latn", } m["dtr"] = { "Lotud", 6685078, "poz-san", "Latn", } m["dts"] = { "Toro So Dogon", 11003311, "nic-dge", "Latn", } m["dtt"] = { "Toro Tegu Dogon", 3913924, "nic-pld", "Latn", } m["dtu"] = { "Tebul Ure Dogon", 7692089, "qfa-dgn", "Latn", } m["dty"] = { "Doteli", 18415595, "inc-pah", "Deva", translit = "ne-translit", } m["dua"] = { "Duala", 33013, "bnt-saw", "Latn", } m["dub"] = { "Dubli", 5310792, "inc-bhi", } m["duc"] = { "Duna", 5314039, "qfa-dis", -- Papuan; isolate in Glottolog; tentatively grouped with Bogaya into a Duna-Pogaya [sic] family, -- ultimately in TNG "Latn", } m["due"] = { "Agta Dumagat Umiray", --"Umiray Dumaget Agta", 7881585, "phi", "Latn", english_name = "Umiray Dumaget Agta", --TLCHANGE } m["duf"] = { "Dumbea", 6983819, "poz-cln", "Latn", } m["dug"] = { "Chiduruma", 35614, "bnt-mij", "Latn", } m["duh"] = { "Dungra Bhil", 12953513, "inc-bhi", "Deva, Gujr", } m["dui"] = { "Dumun", 5314004, "ngf-yag", "Latn", } m["duk"] = { "Uyajitaya", 7904085, "ngf-nur", "Latn", } m["dul"] = { "Ayta Kadi", --"Alabat Island Agta", 3399709, "phi", "Latn", is_official_kwf_name = "https://kwfwikaatkultura.ph/ayta-kadi/", --TLCHANGE english_name = "Alabat Island Agta", --TLCHANGE } m["dum"] = { "Gitnang Nerlandes", --TLCHANGE 178806, "gmw-frk", "Latn", ancestors = "odt", strip_diacritics = {remove_diacritics = c.circ .. c.macron .. c.diaer}, english_name = "Middle Dutch", --TLCHANGE spanish_name = "Neerlandés medio", --TLCHANGE } m["dun"] = { "Dusun Deyah", 2784033, "poz-bre", "Latn", } m["duo"] = { "Tenap", --"Dupaningan Agta", 5315912, "phi", "Latn", english_name = "Dupaningan Agta", --TLCHANGE } m["dup"] = { "Duano", 3040468, "poz-mly", "Latn", } m["duq"] = { "Dusun Malang", 3041711, "poz-bre", "Latn", } m["dur"] = { "Dii", 35208, "alv-dur", "Latn", } m["dus"] = { "Dumi", 56315, "sit-kiw", "Deva", } m["duu"] = { "Drung", 56406, "sit-nng", "Latn", } m["duv"] = { "Duvle", 56364, "paa-lpl", "Latn", } m["duw"] = { "Dusun Witu", 2381310, "poz-bre", "Latn", } m["dux"] = { "Duun", 3914880, "dmn-smg", "Latn", } m["duy"] = { "Dicamay Agta", 5272321, "phi", "Latn", } m["duz"] = { "Duli", 5313405, "alv-ada", "Latn", } m["dva"] = { "Duau", 5310448, "poz-ocw", "Latn", } m["dwa"] = { "Diri", 56286, "cdc-wst", "Latn", } m["dwr"] = { "Dawro", 12629647, "omv-nom", "Ethi, Latn", } m["dwu"] = { "Dhuwal", 3120791, "aus-yol", "Latn", } m["dww"] = { "Dawawa", 5242286, "poz-ocw", "Latn", } m["dwy"] = { "Dhuwaya", 63348560, "aus-yol", "Latn", } m["dwz"] = { "Dewas Rai", 62663667, "inc-bhi", } m["dya"] = { "Dyan", 35340, "nic-gur", "Latn", } m["dyb"] = { "Dyaberdyaber", 5285185, "aus-nyu", "Latn", } m["dyd"] = { "Dyugun", 3913785, "aus-nyu", "Latn", } -- dyg (Villa Viciosa Agta) deleted as extinct and unattested; per Wikipedia: "Villa Viciosa Atta, supposed once spoken -- in Villaviciosa, Abra, is presumed to be related, but is unattested." m["dyi"] = { "Djimini", 35336, "alv-tdj", "Latn", } m["dym"] = { "Yanda Dogon", 8048316, "qfa-dgn", "Latn", } m["dyn"] = { "Dyangadi", 3913820, "aus-cww", "Latn", } m["dyo"] = { "Jola-Fonyi", 3507832, "alv-jol", "Latn", } m["dyu"] = { "Dyula", 32706, "dmn-man", "Latn", } m["dyy"] = { "Dyaabugay", 2591320, "aus-yid", "Latn", } m["dza"] = { "Tunzu", 3915845, "nic-jer", "Latn", } m["dzg"] = { "Dazaga", 35244, "ssa-sah", "Latn", } m["dzl"] = { "Dzala", 56607, "sit-ebo", "Tibt", override_translit = true, -- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]] } m["dzn"] = { "Dzando", 5319622, "bnt-bun", "Latn", } return require("Module:languages").finalizeData(m, "language") ie49w5f4hgsvtsmmsu79yl7u36q83f7 Module:la-headword 828 33168 178469 178402 2026-10-27T02:40:16Z GinawaSaHapon 3989 178469 Scribunto text/plain -- TODO: handle "-old" subtypes generally, appending "in Old Latin", where terms have additional OL inflections. local export = {} local pos_functions = {} local string_utilities = "Module:string utilities" local table_module = "Module:table" local utilities_module = "Module:utilities" local concat = table.concat local form_is_empty = require("Module:la-utilities").form_is_empty local insert = table.insert local remove = table.remove local umatch = mw.ustring.match local lang = require("Module:languages").getByCode("la") local NAMESPACE = mw.title.getCurrentTitle().nsText local PAGENAME = mw.loadData("Module:headword/data").pagename local legal_gender = { ["m"] = true, ["f"] = true, ["n"] = true, ["?"] = true, ["?!"] = true, } local declension_to_english = { ["1"] = "unang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", } local gender_names = { ["m"] = "panlalaki", ["f"] = "pambabae", ["n"] = "di-tiyak", ["?"] = "di-alam na kasarian", ["?!"] = "di-kumpirmadong kasarian", } local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function get_plaintext(...) get_plaintext = require(utilities_module).get_plaintext return get_plaintext(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function invert(...) invert = require(table_module).invert return invert(...) end local function keys_to_list(...) keys_to_list = require(table_module).keysToList return keys_to_list(...) end local function pattern_escape(...) pattern_escape = require(string_utilities).pattern_escape return pattern_escape(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) end local function split(...) split = require(string_utilities).split return split(...) end local function ulower(...) ulower = require(string_utilities).lower return ulower(...) end local function format(array, concatenater) if #array == 0 then return "" end local concatenated = concat(array, concatenater) if concatenated == "" then return "" elseif concatenated:sub(-1) == "'" then concatenated = concatenated .. " " end return "; ''" .. concatenated .. "''" end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function make_link(page, display, face, accel) return require("Module:links").full_link({term = page, alt = display, lang = lang, accel = accel}, face) end -- The main entry point. -- This is the only function that can be invoked from a template. function export.show(frame) local iargs = require("Module:parameters").process(frame.args, { [1] = {required = true}, ["def"] = true, ["suff_type"] = true, }) local args = frame:getParent().args local poscat = iargs[1] local def = iargs.def local suff_type = iargs.suff_type local postype = nil if suff_type then postype = poscat .. '-' .. suff_type else postype = poscat end local data = {lang = lang, categories = {}, heads = {}, genders = {}, inflections = {}} local infl_classes = {} local title = {} local postscript = {} if poscat == "suffixes" then insert_if_not(data.categories, "Latin na hulaping gumagawa ng " .. suff_type) end if pos_functions[postype] then local new_poscat = pos_functions[postype](def, args, data, infl_classes, title, postscript) if new_poscat then poscat = new_poscat end end data.pos_category = poscat postscript = concat(postscript, ", ") return require("Module:headword").full_headword(data) .. format(infl_classes, "/") .. format(title, ", ") .. (postscript ~= "" and " (" .. postscript .. ")" or "") end local function process_num_type(numtype, categories) if numtype == "card" then insert_if_not(categories, "Latin na paulat na pambilang") elseif numtype == "ord" then insert_if_not(categories, "Latin na panunuran na pambilang") elseif numtype == "frac" then insert_if_not(categories, "Latin na bahaging pambilang") elseif numtype == "dist" then insert_if_not(categories, "Latin na pamahaging pambilang") elseif numtype == "mul" then insert_if_not(categories, "Latin na pamparaming pambilang") elseif numtype == "coll" then insert_if_not(categories, "Latin na kolektibong pambilang") elseif numtype then error("Unrecognized numeral type '" .. numtype .. "'") end end local function normalize_derivation(deriv, anchor, text) if not deriv then return nil end local deriv1 = deriv[1] if not deriv1 or deriv1 == "-" then return deriv1 end deriv.label = glossary_link(anchor, text) return deriv end local function derivation(data, decldata, arg, anchor, text) local der = normalize_derivation(decldata[arg], anchor, text) if der and der ~= "-" then insert(data.inflections, der) end end local function nouns(pos, def, args, data, infl_classes, title) local is_num = pos == "numerals" local is_pn = false if pos == "pantangi" then is_pn = true pos = "pangngalan" end local decldata = require("Module:la-nominal").do_generate_noun_forms(args, pos, "headword", def, is_num) local lemma = decldata.overriding_lemma -- TODO: modify the headword line if the slot isn't the expected one. if #lemma == 0 then for slot in require("Module:la-nominal").iter_potential_noun_lemma_slots() do local potential_lemma = decldata.forms["linked_" .. slot] if not form_is_empty(potential_lemma) then if decldata.unattested[slot] then potential_lemma = "*" .. potential_lemma end lemma = potential_lemma break end end end data.heads = lemma -- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-noun}}, there aren't -- really any redundant heads. data.no_redundant_head_cat = true data.id = decldata.id local genders = decldata.overriding_genders if #genders == 0 then if decldata.gender then genders = {ulower(decldata.gender)} elseif not is_num then error("No gender explicitly specified in headword template using g=, and can't infer gender from lemma spec") end end local categories = data.categories if is_num then process_num_type(decldata.num_type, categories) end if decldata.indecl then insert(data.inflections, {label = glossary_link("di-nababago")}) insert_if_not(categories, "Latin na di-nababagong " .. decldata.pos) for _, g in ipairs(genders) do local gender = g:match("^(.[\128-\191]*)%-[sp]$") if not gender then gender = g end if not legal_gender[gender] then error("Gender “" .. gender .. "” is not a valid Latin gender.") end insert(data.genders, g) insert_if_not(categories, "Latin na " .. gender_names[gender] .. " na di-nababagong " .. decldata.pos) end else local is_irreg = false local is_indecl = false local is_decl = false local has_multiple_decls = false local has_multiple_variants = false -- flatten declension specs local decls = {} for _, g in ipairs(genders) do if not legal_gender[g] then error("Gender “" .. g .. "” is not a valid Latin gender.") elseif decldata.num == "pl" then g = g .. "-p" elseif decldata.num == "sg" then g = g .. "-s" end insert(data.genders, g) end local function process_decl(decl_list, props) local headword_decl = props.headword_decl -- skip adjectival declensions if headword_decl:match("+$") then return elseif props.decl == "irreg" then is_irreg = true headword_decl = headword_decl:match("^irreg/(.*)$") or headword_decl local irreg_decls = split(headword_decl, ",") if #irreg_decls > 1 then has_multiple_decls = true end for _, d in ipairs(irreg_decls) do if d == "indecl" or d == "0" then is_indecl = true else is_decl = true end insert_if_not(decl_list, d) end else if headword_decl == "indecl" or headword_decl == "0" then is_indecl = true else is_decl = true end insert_if_not(decl_list, headword_decl) end end for _, props in ipairs(decldata.propses) do if props.headword_decl then process_decl(decls, props) else local alternant_decls = {} for _, alternant in ipairs(props) do for _, single_props in ipairs(alternant) do process_decl(alternant_decls, single_props) end end if #alternant_decls > 1 then has_multiple_decls = true elseif #decls > 1 then has_multiple_variants = true end for _, d in ipairs(alternant_decls) do insert_if_not(decls, d) end end end if is_indecl and is_decl then has_multiple_decls = true end if has_multiple_decls then insert_if_not(categories, "Latin na " .. decldata.pos .. " na may maraming kaukulan") end if has_multiple_variants then insert_if_not(categories, "Latin na " .. decldata.pos .. " na may maraming baryant ng isang kaukulan") end if is_irreg then insert(title, glossary_link("di-regular")) insert_if_not(categories, "Latin na di-regular na " .. decldata.pos) for _, g in ipairs(genders) do insert_if_not(categories, "Latin na " .. gender_names[g] .. " na di-regular na " .. decldata.pos) end end if is_indecl then if is_decl then insert(title, glossary_link("di-mauukol")) else insert(data.inflections, {label = glossary_link("di-mauukol")}) end insert_if_not(categories, "Latin na di-mauukol na " .. decldata.pos) for _, g in ipairs(genders) do insert_if_not(categories, "Latin na " .. gender_names[g] .. " na di-mauukol na " .. decldata.pos) end end if #decls > 1 then insert(title, "iba-iba ang kaukulan") end for _, decl in ipairs(decls) do if not (decl == "0" or decl == "indecl" or decl == "sgpl" or decl == "irreg") then local decl_class = declension_to_english[decl] if not decl_class then error("Internal error: declension '" .. decl .. "' not recognized") end insert(title, "[[Apendise:" .. decl_class .. " kaukulan sa Latin|" .. decl_class .. " kaukulan]]") insert_if_not(categories, "Latin na " .. decl_class .. " kaukulan na " .. decldata.pos) for _, g in ipairs(genders) do insert_if_not(categories, "Latin na " .. gender_names[g] .. " na " .. decldata.pos .. " sa " .. decl_class .. " kaukulan") end end end local lemma_num = decldata.num == "pl" and "pl" or "sg" if NAMESPACE == "Reconstruction" then -- For reconstructed nouns: if data.genders[1] == 'n' and lemma_num == 'sg' then -- singular neuter nouns give a plural local pl = decldata.forms["nom_pl"] if pl and pl ~= "" and #pl > 0 then pl.label = "plural" insert(data.inflections, pl) end else -- all others give an oblique local obl = decldata.forms["acc_" .. lemma_num] if obl and obl ~= "" and #obl > 0 then obl.label = "oblique" insert(data.inflections, obl) end end else local gen = decldata.forms["gen_" .. lemma_num] if (decldata.unattested["gen_" .. lemma_num]) then gen[1] = '*' .. gen[1] data.nolink = true end if gen and gen ~= "" and gen ~= "—" and #gen > 0 then if is_decl then -- Skip displaying the genitive for nouns that are only -- indeclinable. But we do display it for nouns like Abrahām -- and Ādām that can be either indeclinable or declined. gen.label = "paari" insert(data.inflections, gen) end else insert(data.inflections, {label = "walang paari"}) insert_if_not(categories, "Latin na " .. decldata.pos .. " na walang paaring pang-isahan") end end end derivation(data, decldata, "m", "panlalaki") derivation(data, decldata, "f", "pambabae") derivation(data, decldata, "n", "di-tiyak") derivation(data, decldata, "adj", "kaugnayan", "pangkaugnayan na pang-uri") derivation(data, decldata, "dim", "pampaliit") derivation(data, decldata, "aug", "pampalaki") for _, cat in ipairs(decldata.categories) do insert_if_not(categories, cat) end for _, cat in ipairs(decldata.cat) do insert_if_not(categories, "Latin na " .. cat) end return is_pn and decldata.pos == "nouns" and "proper nouns" or decldata.pos end pos_functions["nouns"] = function(def, args, data, infl_classes, title) return nouns("pangngalan", def, args, data, infl_classes, title) end pos_functions["proper nouns"] = function(def, args, data, infl_classes, title) return nouns("pantangi", def, args, data, infl_classes, title) end pos_functions["suffixes-noun"] = function(def, args, data, infl_classes, title) return nouns("hulapi", def, args, data, infl_classes, title) end pos_functions["numerals-noun"] = function(def, args, data, infl_classes, title) return nouns("pambilang", def, args, data, infl_classes, title) end function export.verb_title(title, typeinfo, lemma_forms) local conj = typeinfo.conj local irreg_processing = typeinfo.irreg local subtypes = typeinfo.subtypes local first_lemma = "" if #lemma_forms > 0 then first_lemma = require("Module:links").remove_links(lemma_forms[1]) end if conj == "1st" then insert(title, "[[Apendise:Unang pagbabanghay sa Latin|unang pagbabanghay]]") elseif conj == "2nd" then insert(title, "[[Apendise:Ikalawang pagbabanghay sa Latin|ikalawang pagbabanghay]]") elseif conj == "3rd" then insert(title, "[[Apendise:Ikatlong pagbabanghay sa Latin|ikatlong pagbabanghay]]") elseif conj == "3rd-io" then insert(title, ("[[Apendise:Ikatlong pagbabanghay sa Latin|ikatlong pagbabanghay (barayti %s)]]"):format(make_link(nil, "-iō", "term"))) elseif conj == "3rd/4th" then insert(title, ("[[Apendise:Ikatlong pagbabanghay sa Latin|ikatlo (%s variant)]] / [[Apendise:Ikaapat na pagbabanghay sa Latin|ikaapat na pagbabanghay]]"):format(make_link(nil, "-iō", "term"))) elseif conj == "4th" then insert(title, "[[Apendise:Ikaapat na pagbabanghay sa Latin|ikaapat na pagbabanghay]]") elseif conj == "irreg" then -- sum insert(title, "[[Apendise:Di-regular na pandiwa sa Latin|di-regular na pagbabanghay]]") end if subtypes.highlydef then -- āiō, inquam insert(title, "[[Apendise:Glosaryo#depektibong pandiwa|napakadepektibong]] pandiwa") end if subtypes.suppl then -- sum, volō insert(title, "[[Apendise:Glosaryo#supletibo]]") end if subtypes["3only"] then -- decet insert(title, "[[Apendise:Glosaryo#ikatlong_panauhan|ikatlong panauhan]] lamang") elseif subtypes.impers then -- decet, advesperāscit (also nopass) insert(title, "[[Apendise:Glosaryo#di-personal_na_pandiwa|di-personal]]") end if subtypes.depon then -- dēmōlior, calvor (also noperf) insert(title, "[[Apendise:Glosaryo#deponente|deponente]]") end if subtypes.perfaspres then -- meminī, ōdī insert(title, "walang tangkay na [[Apendise:Glosaryo#pangkasalukuyan|pangkasalukuyan]]") -- If semidepon is set, only the active forms are affected. local voice = subtypes.semidepon and "[[Apendise:Glosaryo#aktibong_tinig|aktibong tinig]] " or "" insert(title, ("May [[Apendise:Glosaryo#pangkasalukuyan|pangkasalukuyang]] %s na kahulugan ang mga anyong [[Apendise:Glosaryo#perpekto|perpektong]] %s na anyo"):format(voice, voice)) -- Clarify that deponency can only apply to the perfect. if subtypes.semidepon then -- ōdī insert(title, "[[Apendise:Glosaryo#deponente|deponente]] sa [[Apendise:Glosaryo#perpekto|perpekto]]") end if subtypes.optsemidepon then insert(title, "puwedeng [[Apendise:Glosaryo#deponente|deponente]] sa [[Apendise:Glosaryo#perpekto|perpekto]]") end else if subtypes.semidepon then -- fīdō, gaudeō insert(title, "[[Apendise:Glosaryo#bahagyang_deponente|bahagyang deponente]]") end if subtypes.optsemidepon then -- audeō, placeō, soleō, pudeō insert(title, "puwedeng [[Apendise:Glosaryo#bahagyang_deponente|bahagyang deponente]]") end end if subtypes.imponly then -- cedo, apage insert(title, "[[Apendise:Glosaryo#pautos|pautos]] lamang") end if subtypes.nopass then -- coacēscō insert(title, "walang [Apendise:Glosaryo#pasibong_tinig|pasibo]]") end local stems = {} if subtypes.nopres then -- coepī; perfaspres already handles this above insert(stems, "[[Apendise:Glosaryo#pangkasalukuyan|pangkasalukuyan]]") end if subtypes.noperf then insert(stems, "[[Apendise:Glosaryo#perpekto|perpekto]]") end if subtypes.nosup or subtypes.supfutractvonly then insert(stems, "[[Apendise:Glosaryo#supino|supino]]") end if #stems > 0 then local extra = subtypes.supfutractvonly and " maliban sa [[Apendise:Glosaryo#panghinaharap|panghinaharap]] na [[Apendise:Glosaryo#aktibong_tinig|aktibong]] [[Apendise:Glosaryo#pandiwari|pandiwari]]" insert(title, ("walang %s na tangkay%s"):format(serial_comma_join(stems, {conj = "o"}), extra or "")) end if subtypes.nofutr then -- soleō insert(title, "walang [[Apendise:Glosaryo#panghinaharap|panghinaharap]]") end if subtypes.pass3only then -- praefundō insert(title, "[[Apendise:Glosaryo#ikatlong_panauhan|ikatlong panauhan]] lamang sa [[Apendise:Glosaryo#pasibong_tinig|pasibong tinig]]") elseif subtypes.passimpers then -- abambulō local msg = "[[Apendise:Glosaryo#di-personal_na_pandiwa|di-personal]] sa [[Apendise:Glosaryo#pasibong_tinig|pasibong tinig]]" if subtypes.passimpersold then -- possum msg = msg .. " sa Lumang Latin" end insert(title, msg) end if subtypes.noimp then -- volō insert(title, "walang [[Apendise:Glosaryo#pautos|pautos]]") end if irreg_processing and umatch(first_lemma, "d[īū]cō$") then -- dīcō insert(title, "[[Apendise:Di-regular na pandiwa sa Latin|di-regular]] na pinaikling [[Apendise:Glosaryo#pautos|pautos]]") end if subtypes.nofutractvptc and not subtypes.nosup then -- fīō insert(title, "walang [[Apendise:Glosaryo#panghinaharap|panghinaharap]] na [[Apendise:Glosaryo#aktibong_tinig|aktibong]] [[Apendise:Glosaryo#pandiwari|pandiwari]]") end if not (subtypes.nopres or subtypes.perfaspres or subtypes.imponly) then if subtypes.noinf then -- inquam insert(title, "walang [[Apendise:Glosaryo#pawatas|pawatas]]") end if subtypes.noger then -- libet insert(title, "walang [[Apendise:Glosaryo#herundiyo|herundiyo]]") end end if subtypes.shorta then -- dō insert(title, ("[[Apendise:Di-regular na pandiwa sa Latin|di-regular]] na pinaikling %s sa karamihan sa mga anyo"):format(make_link(nil, "ă", "kataga"))) end if irreg_processing then if first_lemma:match("edō$") then -- edō insert(title, "[[Apendise:Di-regular na pandiwa sa Latin|di-regular]] na alternatibong pagbaybay") elseif first_lemma:match("fīō$") then -- fīō insert(title, "[[Apendise:Di-regular na pandiwa sa Latin|di-regular]] na pinahabang " .. make_link(nil, "ī", "kataga")) end end end pos_functions["verbs"] = function(def, args, data, infl_classes, title) local m_la_verb = require("Module:la-verb") local def1, def2 if def then def1, def2 = def:match("^(.-):(.*)$") end local conjdata, typeinfo = m_la_verb.make_data(args, true, def1, def2) local lemma_forms = conjdata.overriding_lemma if not lemma_forms or #lemma_forms == 0 then lemma_forms = m_la_verb.get_lemma_forms(conjdata, true) end data.heads = lemma_forms -- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-verb}}, there aren't -- really any redundant heads. data.no_redundant_head_cat = true data.id = conjdata.id local perf_only = false local function insert_inflection(infl, label) infl.label = label insert(data.inflections, infl) end local inf = m_la_verb.get_valid_forms(conjdata.forms["pres_actv_inf"]) if #inf > 0 then insert_inflection(inf, "pangkasalukuyang pawatas") else inf = m_la_verb.get_valid_forms(conjdata.forms["perf_actv_inf"]) if #inf > 0 then perf_only = true insert_inflection(inf, "perpektong pawatas") end end if not perf_only then local perf = m_la_verb.get_valid_forms(conjdata.forms["1s_perf_actv_indc"]) if #perf == 0 then perf = m_la_verb.get_valid_forms(conjdata.forms["3s_perf_actv_indc"]) end if #perf > 0 then insert_inflection(perf, "perpektong aktibo") end end local subtypes = typeinfo.subtypes if not (subtypes.depon or subtypes.semidepon) then local sup = m_la_verb.get_valid_forms(conjdata.forms["acc_sup"]) if #sup > 0 then insert_inflection(sup, "supino") else local fap = m_la_verb.get_valid_forms(conjdata.forms["futr_actv_ptc"]) if #fap > 0 then insert_inflection(fap, "panghinaharap na aktibong pandiwari") end end end export.verb_title(title, typeinfo, lemma_forms) end pos_functions["suffixes-verb"] = pos_functions["verbs"] local function attested_form(decldata, index) local form if (decldata.unattested[index]) then form = { { term = '*' .. decldata.forms[index][1], nolink = true } } else form = decldata.forms[index] end return form end local function degree_derivations(comp, sup, data) local inflections = data.inflections if not (comp or sup) then return elseif (not comp or comp == "-") and (not sup or sup == "-") then insert(inflections, {label = "hindi [[Apendise:Glosaryo#pahambing|pahambing]]"}) insert_if_not(data.categories, "Latin na pang-abay na di-mahahambing") return elseif comp == "-" then insert(inflections, {label = "walang [[Apendise:Glosaryo#pahambing|pahambing]]"}) elseif comp then insert(inflections, comp) end if sup == "-" then insert(inflections, {label = "walang [[Apendise:Glosaryo#pasukdol|pasukdol]]"}) elseif sup then insert(inflections, sup) end end local function adjectives(pos, def, args, data, infl_classes) local is_num = pos == "numerals" local decldata = require("Module:la-nominal").do_generate_adj_forms(args, pos, "headword", nil, def) local lemma = decldata.overriding_lemma -- TODO: modify the headword line if the slot isn't the expected one. if #lemma == 0 then for slot in require("Module:la-nominal").iter_potential_adj_lemma_slots() do local potential_lemma = decldata.forms["linked_" .. slot] if not form_is_empty(potential_lemma) then if decldata.unattested[slot] then potential_lemma = "*" .. potential_lemma end lemma = potential_lemma break end end end data.heads = lemma -- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-noun}}, there aren't -- really any redundant heads. data.no_redundant_head_cat = true data.id = decldata.id local categories = data.categories if is_num then process_num_type(decldata.num_type, categories) end if decldata.num == "pl" then insert_if_not(categories, "Latin na pangmaramihan lamang na " .. decldata.pos) end if decldata.indecl then insert(data.inflections, {label = glossary_link("di-nababago")}) if decldata.pos == "pandiwari" then local lemma1 = lemma[1] if lemma1:sub(-4) == "ndum" then insert_if_not(categories, "Latin na panghinaharap na pasibong pandiwari") elseif lemma1:match("um$") then insert_if_not(categories, "Latin perpektong pandiwari") end end else local lemma_num = decldata.num == "pl" and "pl" or "sg" local masc = decldata.forms["nom_" .. lemma_num .. "_m"] local fem = attested_form(decldata, "nom_" .. lemma_num .. "_f") local neut = attested_form(decldata, "nom_" .. lemma_num .. "_n") local gen = attested_form(decldata, "gen_" .. lemma_num .. "_m") local acc = attested_form(decldata, "acc_" .. lemma_num .. "_m") if decldata.pos == "pandiwari" then local masc1 = masc[1] if masc1:sub(-5) == "ūrus" then insert_if_not(categories, "Latin na panghinaharap na aktibong pandiwari") elseif masc1:sub(-4) == "ndus" then -- FIXME, should rename to "Latin gerundives") insert_if_not(categories, "Latin na panghinaharap na pasibong pandiwari") else local masc1_final2 = masc1:sub(-2) if masc1_final2 == "us" then insert_if_not(categories, "Latin na perpektong pandiwari") elseif masc1_final2 == "ns" then insert_if_not(categories, "Latin na pangkasalukuyang pandiwari") else error("Unrecognized participle ending: " .. masc1) end end end -- We display the inflections in three different ways to mimic the -- old way of doing things: -- -- 1. If masc and fem are different, show masc, fem and neut. -- 2. Otherwise, if masc and neut are different, show masc and neut. -- 3. Otherwise, show masc nominative and masc genitive. if not form_is_empty(fem) and not deep_equals(masc, fem) then fem.label = "pambabae" insert(data.inflections, fem) if not form_is_empty(neut) then neut.label = "di-tiyak" insert(data.inflections, neut) end elseif not form_is_empty(neut) and not deep_equals(masc, neut) then neut.label = "di-tiyak" insert(data.inflections, neut) elseif not form_is_empty(gen) then gen.label = "paari" insert(data.inflections, gen) elseif not form_is_empty(acc) then acc.label = "paakusa" insert(data.inflections, acc) end insert(infl_classes, decldata.title) end local comp = normalize_derivation(decldata.comp, "pahambing") local sup = normalize_derivation(decldata.sup, "pasukdol") degree_derivations(comp, sup, data) derivation(data, decldata, "adv", "pang-abay") for _, cat in ipairs(decldata.categories) do insert_if_not(categories, cat) end for _, cat in ipairs(decldata.cat) do insert_if_not(categories, "Latin na " .. cat) end return decldata.pos end pos_functions["adjectives"] = function(def, args, data, infl_classes, title) return adjectives("pang-uri", def, args, data, infl_classes, title) end pos_functions["participles"] = function(def, args, data, infl_classes, title) return adjectives("pandiwari", def, args, data, infl_classes, title) end pos_functions["determiners"] = function(def, args, data, infl_classes, title) return adjectives("pantukoy", def, args, data, infl_classes, title) end pos_functions["pronouns"] = function(def, args, data, infl_classes, title) return adjectives("panghalip", def, args, data, infl_classes, title) end pos_functions["suffixes-adjective"] = function(def, args, data, infl_classes, title) return adjectives("hulapi", def, args, data, infl_classes, title) end pos_functions["numerals-adjective"] = function(def, args, data, infl_classes, title) return adjectives("pambilang", def, args, data, infl_classes, title) end pos_functions["adverbs"] = function(def, args, data) local sublist = {sublist = "/"} args = require("Module:parameters").process(args, { [1] = {alias_of = "head", list = false}, [2] = {alias_of = "comp"}, [3] = {alias_of = "sup"}, ["head"] = {list = true, required = true}, ["comp"] = sublist, ["sup"] = sublist, ["adj"] = sublist, ["id"] = true, }) data.heads = args.head data.no_redundant_head_cat = true -- since head= is required data.id = args.id local comp, sup = args.comp, args.sup local irreg = false if comp then if comp[1] == "-" then comp = "-" elseif comp[1] == nil then comp = nil else comp.label = glossary_link("pahambing") comp = args.comp irreg = true end end if sup then if sup[1] == "-" then sup = "-" elseif sup[1] == nil then sup = nil else sup.label = glossary_link("pasukdol") sup = args.sup irreg = true end end local categories = data.categories if irreg then insert_if_not(categories, "Latin na di-regular na pang-abay") end if not (comp or sup) then local default_comp = {label = glossary_link("pahambing")} local default_sup = {label = glossary_link("pasukdol")} for _, head in ipairs(args.head) do local stem = nil for _, suff in ipairs{"iter", "nter", "ter", "er", "iē", "ē", "rā", "im", "ō"} do stem = head:match("(.*)" .. pattern_escape(suff) .. "$") comp_suff, sup_suff = "ius", "issimē" if stem ~= nil then if suff == "nter" then stem = stem .. "nt" elseif suff == "rā" then comp_suff = "er" .. comp_suff sup_suff = "imē" end insert(default_comp, stem .. comp_suff) insert(default_sup, stem .. sup_suff) break end end if not stem then error("Unrecognized adverb type, recognized types are “-ē”, “-er”, “-ter”, “-iter”, “-im”, or “-ō”, “-ra” or specify irregular forms or “-” if incomparable.") end end comp = comp or default_comp sup = sup or default_sup end degree_derivations(comp, sup, data) derivation(data, args, "adj", "adjective") end pos_functions["suffixes-adverb"] = pos_functions["adverbs"] local function get_forms(forms) if #forms == 0 then return nil end local i, attested = 1, false while true do local form = forms[i] if form == nil then return forms, attested elseif form == "-" then remove(forms, i) else if not (attested or get_plaintext(form):sub(1, 1) == "*") then attested = true end i = i + 1 end end end local function degree(pos, deg, pos_func, other_pos, other_pos_label, other_deg, other_deg_label, args, data, infl_classes) local list = {list = true} args = require("Module:parameters").process(args, { [1] = {alias_of = "head", list = false}, ["head"] = list, ["positive"] = list, [other_pos] = {sublist = "/"}, [other_deg] = list, ["id"] = true, }) data.no_redundant_head_cat = #args.head == 0 -- Set default manually so we can tell whether the user specified head=. if #args.head == 0 then args.head = {PAGENAME} end data.heads = args.head data.id = args.id insert(data.inflections, {label = deg}) if pos_func then pos_func(args, data, infl_classes) end local positive, positive_attested = get_forms(args.positive) if positive then if not positive_attested then insert(data.categories, "Latin na " .. deg .. " lamang na " .. pos) end if #positive > 0 then args.positive.label = "positive" insert(data.inflections, args.positive) else insert(data.inflections, {label = "walang anyong lantay"}) end end local other = get_forms(args[other_deg]) if other then if #other > 0 then args[other_deg].label = other_deg_label insert(data.inflections, args[other_deg]) else insert(data.inflections, {label = "walang anyong " .. other_deg_label}) end end derivation(data, args, other_pos, other_pos_label) -- If a lemma, return the primary part of speech ("adjectives" or -- "adverbs"), so that the term is categorized in "Latin adjectives" or -- "Latin adverbs". Otherwise, return nothing, so that the term goes in the -- relevant non-lemma category (e.g. "Latin comparative adjectives"), and -- into "Latin non-lemma forms". if positive and not positive_attested then return pos end end local function comp_adj(args, data, infl_classes) insert(infl_classes, "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") local n = {label = "neuter"} for _, head in ipairs(args.head) do local neuter = head:gsub("or$", "us") insert(n, neuter) end insert(data.inflections, n) end pos_functions["comparative adjectives"] = function(def, args, data, infl_classes, title) return degree("adjectives", "comparative", comp_adj, "adv", "adverb", "sup", "superlative", args, data, infl_classes) end pos_functions["comparative adverbs"] = function(def, args, data, infl_classes, title) return degree("adverbs", "comparative", nil, "adj", "adjective", "sup", "superlative", args, data, infl_classes) end local function sup_adj(args, data, infl_classes) insert(infl_classes, "[[Apendise:Unang kaukulan sa Latin|una]]") insert(infl_classes, "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") local f, n = {label = "pambabae"}, {label = "di-tiyak"} for _, head in ipairs(args.head) do local stem = head:gsub("us$", "") insert(f, stem .. "a") insert(n, stem .. "um") end insert(data.inflections, f) insert(data.inflections, n) end pos_functions["superlative adjectives"] = function(def, args, data, infl_classes, title) return degree("adjectives", "superlative", sup_adj, "adv", "adverb", "comp", "comparative", args, data, infl_classes) end pos_functions["superlative adverbs"] = function(def, args, data, infl_classes, title) return degree("adverbs", "superlative", nil, "adj", "adjective", "comp", "comparative", args, data, infl_classes) end local function adpositions(pos, def, args, data, infl_classes, title, postscript) local cases = invert(require("Module:la-utilities").cases) args = require("Module:parameters").process(args, { [1] = {alias_of = "head", list = false}, [2] = {list = true, set = keys_to_list(cases)}, ["head"] = {list = true, required = true}, ["id"] = true, }) -- Case names are supplied in numbered arguments, optionally preceded by -- headwords. cases = args[2] for i = 1, #cases do for j = i + 1, #cases do if cases[i] == cases[j] then error("Duplicate case") end end local case = cases[i] local Apendise_link = glossary_link(case) if i == 1 then Apendise_link = "+ " .. Apendise_link end insert(postscript, Apendise_link) insert_if_not(data.categories, "Latin na " .. case .. " na " .. pos) end data.heads = args.head data.no_redundant_head_cat = true -- since head= is required data.id = args.id end pos_functions["prepositions"] = function(...) return adpositions("prepositions", ...) end pos_functions["postpositions"] = function(...) return adpositions("postpositions", ...) end pos_functions["gerunds"] = function(def, args, data) args = require("Module:parameters").process(args, { [1] = {required = true, default = "labōrandum"}, -- headword [2] = true, -- gerundive }) data.heads = {args[1]} data.no_redundant_head_cat = true -- since 1= is required and goes into data.heads insert(data.inflections, {label = "[[Apendise:Glosaryo#palayon|palayon]]"}) local stem = args[1]:match("^(.*)um$") if not stem then error("Unrecognized gerund ending: " .. stem) end if args[2] == "-" then insert(data.inflections, {label = "no [[Apendise:Glosaryo#herundiyo|herundiyo]]"}) else insert(data.inflections, {[1] = args[2] or stem .. "us", label = "[[Apendise:Glosaryo#herundiyo|herundiyo]]"}) end end local function non_lemma_forms(def, args, data) args = require("Module:parameters").process(args, { [1] = {required = true, default = def}, -- headword or cases ["head"] = {list = true, require_index = true}, ["g"] = {list = true}, ["id"] = true, }) local heads = {args[1]} for _, head in ipairs(args.head) do insert(heads, head) end data.heads = heads data.no_redundant_head_cat = true -- since 1= is required and goes into data.heads data.genders = args.g data.id = args.id end pos_functions["noun forms"] = non_lemma_forms pos_functions["proper noun forms"] = non_lemma_forms pos_functions["pronoun forms"] = non_lemma_forms pos_functions["verb forms"] = non_lemma_forms pos_functions["gerund forms"] = non_lemma_forms pos_functions["adjective forms"] = non_lemma_forms pos_functions["participle forms"] = non_lemma_forms pos_functions["determiner forms"] = non_lemma_forms pos_functions["numeral forms"] = non_lemma_forms pos_functions["suffix forms"] = non_lemma_forms return export g8n2g1t1nflm8i5qcfy02dlqh8nccha Module:form of/data/1 828 33945 178532 176790 2026-10-27T08:24:12Z GinawaSaHapon 3989 178532 Scribunto text/plain --[=[ This module lists the more common recognized inflection tags, along with their shortcut aliases, the corresponding glossary entry or page describing the tag, and the corresponding wikidata entry. The less common tags are in [[Module:form of/data/2]]. We divide the tags this way to save memory space. Be careful adding more tags to this module; add them to the other module unless you're sure they are common. TAGS is a table where keys are the canonical form of an inflection tag and the corresponding values are tables describing the tags, consisting of the following keys: - 1: Type of the tag ("person", "number", "gender", "case", "animacy", "tense-aspect", "mood", "voice-valence", etc.). - 2: Anchor or page describing the inflection tag, with the following values: * nil: No link. * APPENDIX: Anchor in [[Appendix:Glossary]] whose name is the same as the tag * WIKT: Page in the English Wiktionary whose name is the same as the tag. * WP: Page in the English Wikipedia whose name is the same as the tag. * A string: If prefixed by 'w:' the specified page in the English Wikipedia. If prefixed by 'wikt:', the specified page in the English Wiktionary. Otherwise, an anchor in [[Appendix:Glossary]]. NOTE: GLOSSARY ANCHORS ARE PREFERRED. Other types of entries should be migrated to the glossary, with links to Wikipedia and/or Wiktionary entries as appropriate. - 3: List of shortcuts (i.e. aliases for the inflection tag) or a single shortcut string, or nil. - 4: Numeric value of Wikidata identifier (see wikidata.org) for the concept most closely describing this tag. (The actual Wikidata identifier is a string formed by prefixing the number with Q.) - display: If specified, consists of text to display in the definition line, in lieu of the canonical form of the inflection tag. If there is a glossary entry, the displayed text forms the right side of the two-part glossary link. - no_space_on_left: If specified, don't display a space to the left of the tag. Used for punctuation. - no_space_on_right: If specified, don't display a space to the right of the tag. Used for punctuation. SHORTCUTS is a table mapping shortcut aliases to canonical inflection tag names. Shortcuts are of one of three types: (1) A simple alias of a tag. These do not need to be entered explicitly into the table; code at the end of the module automatically fills in these entries based on the information in TAGS. (2) An alias to a multipart tag. For example, the alias "mf" maps to the multipart tag "m//f", which will in turn be expanded into the canonical multipart tag {"masculine", "feminine"}, which will display as (approximately) "[[Appendix:Glossary#gender|masculine]] and [[Appendix:Glossary#gender|feminine]]". The number of such aliases should be liminted, and should cover only the most common combinations. Normally, multipart tags are displayed using serialCommaJoin() in [[Module:table]] to appropriately join the display form of the individual tags using commas and/or "and". However, some multipart tags are displayed specially; see DISPLAY_HANDLERS below. Note that aliases to multipart tags can themselves contain simple aliases in them. (3) An alias to a list of multiple tags (which may themselves be simple or multipart aliases). Specifying the alias is exactly equivalent to specifying the tags in the list in order, one after another. An example is "1s", which maps to the list {"1", "s"}. The number of such aliases should be limited, and should cover only the most common combinations. NOTE: In some cases below, multiple tags point to the same wikidata, because Wikipedia considers them synonyms. Examples are indirect case vs. objective case vs. oblique case, and inferential mood vs. renarrative mood. We do this because (a) we want to allow users to choose their own terminology; (b) we want to be able to use the terminology most common for the language in question; (c) terms considered synonyms may or may not actually be synonyms, as different languages may use the terms differently. For example, although the Wikipedia page on [[w:inferential mood]] claims that inferential and renarrative moods are the same, the page on [[w:Bulgarian_verbs#Evidentials]] claims that Bulgarian has both, and that they are not the same. ]=] local m_form_of_data = require("Module:form of/data") local APPENDIX = m_form_of_data.APPENDIX local WP = m_form_of_data.WP local WIKT = m_form_of_data.WIKT local tags = {} local shortcuts = {} ----------------------- Person ----------------------- tags["unang panauhan"] = { --TLCHANGE "person", APPENDIX, --TLCHANGE "first person" {"1", "first-person"}, --TLCHANGE 21714344, } tags["ikalawang panauhan"] = { --TLCHANGE "person", APPENDIX, --TLCHANGE "second person" {"2", "second-person"}, --TLCHANGE 51929049, } tags["ikatlong panauhan"] = { --TLCHANGE "person", APPENDIX, --TLCHANGE "third person" {"3", "third-person"}, --TLCHANGE 51929074, } tags["di-panao"] = { --TLCHANGE "person", APPENDIX, {"impers", "impersonal"}, --TLCHANGE } shortcuts["12"] = "1//2" shortcuts["13"] = "1//3" shortcuts["23"] = "2//3" shortcuts["123"] = "1//2//3" ----------------------- Number ----------------------- tags["isahan"] = { --TLCHANGE "number", "isahang bilang", --TLCHANGE "singular number", {"s", "sg", "singular"}, 110786, } tags["dalawahan"] = { --TLCHANGE "number", "dalawahang bilang", --TLCHANGE "dual number", {"d", "du", "dual"}, --TLCHANGE 110022, } tags["maramihan"] = { --TLCHANGE "number", "maramihang bilang", --TLCHANGE "plural number", {"p", "pl", "plural"}, --TLCHANGE 146786, } tags["single-possession"] = { "number", "singular number", "spos", 110786, -- Singular } tags["multiple-possession"] = { "number", "plural number", "mpos", 146786, -- Plural } shortcuts["1s"] = {"1", "s"} shortcuts["2s"] = {"2", "s"} shortcuts["3s"] = {"3", "s"} shortcuts["1d"] = {"1", "d"} shortcuts["2d"] = {"2", "d"} shortcuts["3d"] = {"3", "d"} shortcuts["1p"] = {"1", "p"} shortcuts["2p"] = {"2", "p"} shortcuts["3p"] = {"3", "p"} ----------------------- Gender ----------------------- tags["panlalaki"] = { --TLCHANGE "gender", "gender", {"m", "masculine"}, --TLCHANGE 499327, } -- This is useful e.g. in Swedish. tags["natural masculine"] = { "gender", "gender", "natm", } tags["pambabae"] = { --TLCHANGE "gender", "gender", {"f", "feminine"}, --TLCHANGE 1775415, } tags["di-tiyak"] = { --TLCHANGE "gender", "gender", {"n", "neuter"}, --TLCHANGE 1775461, } tags["karaniwan"] = { "gender", "gender", "c", 1305037, } tags["di-panlalaki"] = { "gender", APPENDIX, "nv", } shortcuts["mf"] = "m//f" shortcuts["mn"] = "m//n" shortcuts["fn"] = "f//n" shortcuts["mfn"] = "m//f//n" ----------------------- Animacy ----------------------- -- (may be useful sometimes for [[Module:object usage]].) tags["buhay"] = { "animacy", APPENDIX, "an", 51927507, } tags["di-buhay"] = { "animacy", APPENDIX, {"in", "inan"}, 51927539, } tags["panao"] = { "animacy", APPENDIX, {"pr", "pers"}, 63302102, } ----------------------- Tense/aspect ----------------------- tags["pangkasalukuyan"] = { --TLCHANGE "tense-aspect", "panahong pangkasalukuyan", --TLCHANGE "present tense", {"pres", "present"}, --TLCHANGE 192613, } tags["pangnakaraan"] = { --TLCHANGE "tense-aspect", "panahong pangnakaraan", --TLCHANGE "past tense", "past", --TLCHANGE 1994301, } tags["panghinaharap"] = { --TLCHANGE "tense-aspect", "panahong panghinaharap", --TLCHANGE "future tense", {"fut", "futr", "future"}, --TLCHANGE 501405, } tags["perpektong panghinaharap"] = { --TLCHANGE "tense-aspect", APPENDIX, {"futp", "fperf", "future perfect"}, --TLCHANGE 1234617, } tags["di-pangnakaraan"] = { --TLCHANGE "tense-aspect", "panahong di-pangnakaraan", --TLCHANGE "non-past tense", {"npast", "non-past"}, --TLCHANGE 16916993, } tags["nagaganap"] = { --TLCHANGE "tense-aspect", APPENDIX, {"prog", "progressive"}, --TLCHANGE 56653945, } tags["di-pangnakaraan"] = { --TLCHANGE preterite ay hindi nakaraan (ie, ngayon at bukas) "tense-aspect", APPENDIX, {"pret", "preterite"}, --TLCHANGE 442485, } -- paalala, iba ang perpekto/imperpekto sa perpektibo/imperpektibo, mahalaga yung pagkakaiba lalo na sa Tagalog tags["perpekto"] = { --TLCHANGE no Tagalog equivalent, "tense-aspect", APPENDIX, {"perf", "perfect"}, --TLCHANGE 625420, } tags["imperpekto"] = { --TLCHANGE no Tagalog equivalent "tense-aspect", APPENDIX, {"impf", "imperf", "imperfect"}, --TLCHANGE } tags["pluperpekto"] = { --TLCHANGE sinalin sa pinakamadaling maiintindihan "tense-aspect", APPENDIX, {"plup", "pluperf", "pluperfect"}, --TLCHANGE 623742, } tags["aoristo"] = { --TLCHANGE no Tagalog equivalent "tense-aspect", "aorist tense", {"aor", "aori", "aorist"}, --TLCHANGE 216497, } tags["historikong pangnakaraan"] = { --TLCHANGE "tense-aspect", nil, {"phis", "past historic"}, --TLCHANGE 442485, -- Preterite } tags["imperpektibo"] = { --TLCHANGE technically, nagaganap pero gamitin na lang sa progressive "tense-aspect", APPENDIX, {"impfv", "imperfv", "imperfective"}, --TLCHANGE 371427, } tags["perpektibo"] = { --TLCHANGE technically, naganap pero gamitin na lang sa contemplative "tense-aspect", APPENDIX, {"pfv", "perfv", "perfective"}, --TLCHANGE 1424306, } shortcuts["spast"] = {"simpleng", "past"} --TLCHANGE {"simple", "past"} shortcuts["simple past"] = {"simpleng", "past"} --TLCHANGE {"simple", "past"} shortcuts["spres"] = {"simpleng", "present"} --TLCHANGE {"simple", "present"} shortcuts["simple present"] = {"simpleng", "present"} --TLCHANGE {"simple", "present"} ----------------------- Mood ----------------------- tags["pautos"] = { --TLCHANGE "mood", "panaganong pautos", --TLCHANGE "imperative mood", {"imp", "impr", "impv", "imperative"}, --TLCHANGE 22716, } tags["paturol"] = { --TLCHANGE "mood", "panaganong paturol", --TLCHANGE "indicative mood", {"ind", "indc", "indic", "indicative"}, --TLCHANGE 682111, } tags["pasakali"] = { --TLCHANGE "mood", "panaganong pasakali", --TLCHANGE "subjunctive mood", {"sub", "subj", "subjunctive"}, --TLCHANGE 473746, } tags["panubali"] = { --TLCHANGE "mood", "panaganong panubali", --TLCHANGE "conditional mood", {"cond", "conditional"}, --TLCHANGE 625581, } tags["pamaraan"] = { --TLCHANGE "mood", "w:modality (linguistics)", {"mod", "modal"}, --TLCHANGE 1243600, } tags["pasana"] = { -- tlchange mula sana optative "mood", "panaganong pasana", {"opta", "opt"}, 527205, } tags["pahiling"] = { -- tlchange mula hiling jussive "mood", "panaganong pahiling", "juss", 462367, } tags["pahikayat"] = { -- tlchange mula hikayat hortative "mood", "panaganong pahikayat", "hort", 5906629, } ----------------------- Voice/valence ----------------------- -- This tag type combines what is normally called "voice" (active, passive, middle, mediopassive) with other tags that -- aren't normally called voice but are similar in that they control the valence/valency (number and structure of the -- arguments of a verb). tags["aktibong tinig"] = { --TLCHANGE "voice-valence", "aktibong tinig", --TLCHANGE "active voice", {"act", "actv", "active", "tahasan"}, --TLCHANGE 1317831, } tags["middle"] = { "voice-valence", "middle voice", {"mid", "midl"}, } tags["pasibong tinig"] = { --TLCHANGE "voice-valence", APPENDIX, --TLCHANGE "passive voice", {"pass", "pasv", "passive", "kabalikan"}, --TLCHANGE 1194697, } tags["medyo pasibong tinig"] = { "voice-valence", APPENDIX, {"mp", "mpass", "mpasv", "mpsv"}, 1601545, } tags["paiba"] = { --TLCHANGE "voice-valence", APPENDIX, {"refl", "reflexive"}, --TLCHANGE 13475484, -- for "reflexive verb" } tags["transitibo"] = { --TLCHANGE "voice-valence", "pandiwang transitibo", --TLCHANGE "transitive verb", {"tr", "vt", "transitive"}, --TLCHANGE 1774805, -- for "transitive verb" } tags["intransitibo"] = { --TLCHANGE "voice-valence", "pandiwang intransitibo", --TLCHANGE "intransitive verb", {"intr", "vi", "intransitive"}, --TLCHANGE 1166153, -- for "intransitive verb" } tags["ditransitibo"] = { "voice-valence", "pandiwang ditransitibo", "ditr", 2328313, -- for "ditransitive verb" } tags["kosatibo"] = { "voice-valence", "pandiwang kosatibo", "caus", 56677011, -- for "causative verb" } ----------------------- Non-finite ----------------------- tags["pawatas"] = { --TLCHANGE "non-finite", APPENDIX, {"inf", "infinitive"}, --TLCHANGE 179230, } -- A form found in Portuguese and Galician, as well as in Hungarian. This is probably unnecessary and can be replaced -- with the regular "infinitive" tag. A personal infinitive is not a separate infinitive from the plain infinitive, just -- an inflection of the infinitive. tags["personal infinitive"] = { "non-finite", "w:Portuguese verb conjugation", "pinf", } tags["pandiwari"] = { --TLCHANGE "non-finite", APPENDIX, {"part", "ptcp", "participle"}, --TLCHANGE 814722, } tags["pangngalang pandiwa"] = { --TLCHANGE "non-finite", APPENDIX, {"vnoun", "verbal noun"}, --TLCHANGE 1350145, } tags["herundiyo"] = { "non-finite", APPENDIX, {"ger", "gerund"}, 1923028, } tags["supino"] = { "non-finite", APPENDIX, {"sup", "supine"}, 548470, } tags["transgressive"] = { "non-finite", APPENDIX, nil, 904896, } ----------------------- Case ----------------------- tags["palayo"] = { "case", "kaukulang palayo", {"abl", "ablative"}, 156986, } tags["palayon"] = { --TLCHANGE "case", "kaukulang palayon", {"acc", "accusative"}, --TLCHANGE 146078, } tags["patanggap"] = { "case", "kaukulang patanggap", {"dat", "dative"}, 145599, } tags["paari"] = { --TLCHANGE "case", "kaukulang paari", {"gen", "genitive"}, --TLCHANGE 146233, } tags["pagamit"] = { "case", "kaukulang pagamit", {"ins", "instrumental"}, 192997, } tags["panlunan"] = { "case", "kaukulang panlunan", {"loc", "locative"}, 202142, } tags["palagyo"] = { --TLCHANGE "case", "kaukulang palagyo", {"nom", "nominative"}, --TLCHANGE 131105, } tags["paukol"] = { "case", "kaukulang paukol", {"pre", "prep", "prepositional"}, 2114906, } tags["pabanggit"] = { --TLCHANGE "case", "kaukulang pabanggit", {"voc", "vocative"}, --TLCHANGE 185077, } ----------------------- State ----------------------- tags["construct"] = { "state", "construct state", {"cons", "construct state"}, 1641446, display = "construct state", } tags["definite"] = { "state", APPENDIX, {"def", "defn", "definite state"}, 53997851, } tags["panaklaw"] = { --TLCHANGE "state", APPENDIX, {"indef", "indf", "indefinite state", "indefinite"}, --TLCHANGE 53997857, } tags["paari"] = { --TLCHANGE "state", WP, {"poss", "possessive"}, --TLCHANGE 2105891, } tags["malakas"] = { "state", "indefinite", {"str", "strong"}, 53997857, -- Indefinite } tags["mahina"] = { "state", "definite", {"wk","weak"}, 53997851, -- Definite } tags["mixed"] = { "state", APPENDIX, "mix", 63302161, } tags["attributive"] = { "state", APPENDIX, "attr", } tags["predicative"] = { "state", APPENDIX, "pred", } ----------------------- Degrees of comparison ----------------------- tags["lantay"] = { --TLCHANGE "comparison", "lantay", {"posd", "positive", "positive degree"}, --TLCHANGE 3482678, -- Doesn't exist in English; only in Czech, Estonian, Finnish and various Nordic languages. } tags["pahambing"] = { --TLCHANGE "comparison", "pahambing", {"comd", "comparative", "comparative degree"}, --TLCHANGE 14169499, } tags["pasukdol"] = { --TLCHANGE "comparison", "pasukdol", {"supd", "superlative", "superlative degree"}, --TLCHANGE 1817208, } ----------------------- Register ----------------------- ----------------------- Deixis ----------------------- ----------------------- Clusivity ----------------------- ----------------------- Inflectional class ----------------------- tags["makahalip"] = { --TLCHANGE "class", WIKT, {"pron", "pronominal"}, --TLCHANGE 12721180, -- for "pronominal attribute", existing only in the Romanian Wikipedia } ----------------------- Attitude ----------------------- -- This is a vague tag type grouping augmentative, diminutive and pejorative, which generally indicate the speaker's -- attitude towards the object in question (as well as often indicating size). tags["pampalaki"] = { --TLCHANGE "attitude", APPENDIX, {"aug", "augmentative"}, --TLCHANGE 1358239, } tags["pampaliit"] = { --TLCHANGE "attitude", APPENDIX, {"dim", "diminutive"}, 108709, } tags["pampanira"] = { "attitude", APPENDIX, {"pej","pejorative"}, 545779, } ----------------------- Sound changes ----------------------- tags["contracted"] = { "sound change", nil, "contr", 126473, } tags["uncontracted"] = { "sound change", nil, "uncontr", } ----------------------- Misc grammar ----------------------- shortcuts["past-cl"] = {"past", "-", "tense", "clause"} shortcuts["pres-cl"] = {"pres", "-", "tense", "clause"} shortcuts["fut-cl"] = {"fut", "-", "tense", "clause"} shortcuts["ind-cl"] = {"ind", "clause"} shortcuts["sub-cl"] = {"sub", "clause"} shortcuts["past-sub-cl"] = {"past", "sub", "clause"} shortcuts["pres-sub-cl"] = {"pres", "sub", "clause"} shortcuts["fut-sub-cl"] = {"fut", "sub", "clause"} shortcuts["cond-cl"] = {"cond", "clause"} shortcuts["cond-past-cl"] = {"cond", "past", "clause"} tags["simple"] = { "grammar", nil, "sim", } tags["short"] = { "grammar", } tags["long"] = { "grammar", } tags["anyo"] = { --TLCHANGE "grammar", nil, "form", --TLCHANGE } tags["malapang-uri"] = { --TLCHANGE "grammar", WIKT, {"adj", "adjectival"}, --TLCHANGE } tags["malapang-abay"] = { --TLCHANGE "grammar", APPENDIX, {"adv", "adverbial"}, --TLCHANGE } tags["negative"] = { "grammar", "w:affirmation and negation", "neg", 63302088, } tags["nominalized"] = { "grammar", nil, "nomz", 4683152, -- entry for "nominalized adjective" } tags["nominalization"] = { "grammar", nil, "nomzn", 1500667, } tags["ugat"] = { --TLCHANGE "grammar", nil, "root", --TLCHANGE 111029, } tags["tangkay"] = { "grammar", nil, "stem", 210523, } tags["dependent"] = { "grammar", nil, "dep", 1122094, -- entry for "dependent clause" } tags["independent"] = { "grammar", nil, "indep", 1419215, -- entry for "independent clause" } tags["simuno"] = { --TLCHANGE "grammar", APPENDIX, {"sbj", "subject"}, -- sub and subj used for subjunctive --TLCHANGE 164573, } tags["layon"] = { --TLCHANGE "grammar", APPENDIX, {"obj", "object"}, --TLCHANGE 175026, } tags["tuwirang layon"] = { --TLCHANGE "grammar", APPENDIX, {"dirobj", "direct object"}, --TLCHANGE 2990574, } tags["di-tuwirang layon"] = { --TLCHANGE "grammar", APPENDIX, {"indirobj", "indirect object"}, --TLCHANGE 1094061, } tags["panahon"] = { --TLCHANGE "grammar", APPENDIX, "tense", --TLCHANGE 177691, } tags["sugnay"] = { --TLCHANGE "grammar", APPENDIX, "clause", --TLCHANGE 117364, } tags["parirala"] = { --TLCHANGE "grammar", APPENDIX, "phrase", --TLCHANGE 187931, } tags["indirect question"] = { "grammar", WP, {"indq", "indirq"}, 1661444, } ----------------------- Other tags ----------------------- -- This consists of non-content words like "and" as well as punctuation characters. If the punctuation characters appear -- by themselves as tags, we special-case the handling of surrounding spaces so the output looks correct. tags["at"] = { --TLCHANGE "other", nil, "and", --TLCHANGE } -- HACK! "in" is a shortcut for "inanimate" so create "!in" to display "in". We should generalize this like for labels. tags["!in"] = { "other", display = "in", } tags[","] = { "other", no_space_on_left = true, } tags[":"] = { "other", no_space_on_left = true, } tags["/"] = { "other", no_space_on_left = true, no_space_on_right = true, } tags["("] = { "other", no_space_on_right = true, } tags[")"] = { "other", no_space_on_left = true, } tags["["] = { "other", no_space_on_right = true, } tags["]"] = { "other", no_space_on_left = true, } tags["-"] = { -- regular hyphen-minus "other", no_space_on_left = true, no_space_on_right = true, } ----------------------- Create the shortcuts list ----------------------- m_form_of_data.finalize(tags, shortcuts) return {tags = tags, shortcuts = shortcuts} 3y9h1z38e9hopk4ivr6045ef27fqyvl Wiksiyonaryo:Usaping Wikimedia 4 34256 178446 177958 2026-10-26T14:00:48Z MediaWiki message delivery 1908 /* Pagpapalit ng serbidor - May parating na panahon na maaari mo lamang basahin ang iyong wiki na hindi tatagal nang masyado */ bagong seksyon 178446 wikitext text/x-wiki __NOEDITSECTION__ Maligayang pagdating sa talakayang '''Usaping Wikimedia''' ng Wiktionary sa Tagalog. Dito matatagpuan ang mga paksang nakatuon sa mga balita at usaping teknikal ng <span class="plainlinks">[https://wikimediafoundation.org/ Wikimedia]</span>. Maaaring ang linalaman nito ay nasa Tagalog, Ingles, o iba pang mga wika. {{Wiktionary:Puntahan ng Pamayanan}} ---- == Final proposed modifications to the Universal Code of Conduct Enforcement Guidelines and U4C Charter now posted == <div lang="en" dir="ltr" class="mw-content-ltr"> The proposed modifications to the [[foundation:Special:MyLanguage/Policy:Universal_Code_of_Conduct/Enforcement_guidelines|Universal Code of Conduct Enforcement Guidelines]] and the U4C Charter [[m:Universal_Code_of_Conduct/Annual_review/2025/Proposed_Changes|are now on Meta-wiki for community notice]] in advance of the voting period. This final draft was developed from the previous two rounds of community review. Community members will be able to vote on these modifications starting on 17 April 2025. The vote will close on 1 May 2025, and results will be announced no later than 12 May 2025. The U4C election period, starting with a call for candidates, will open immediately following the announcement of the review results. More information will be posted on [[m:Special:MyLanguage//Universal_Code_of_Conduct/Coordinating_Committee/Election|the wiki page for the election]] soon. Please be advised that this process will require more messages to be sent here over the next two months. The [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee (U4C)]] is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, you may [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Charter|review the U4C Charter]]. Please share this message with members of your community so they can participate as well. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User_talk:Keegan (WMF)|talk]]) 02:05, 4 Abril 2025 (UTC) </div> <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28469465 --> == Vote now on the revised UCoC Enforcement Guidelines and U4C Charter == <div lang="en" dir="ltr" class="mw-content-ltr"> The voting period for the revisions to the Universal Code of Conduct Enforcement Guidelines ("UCoC EG") and the UCoC's Coordinating Committee Charter is open now through the end of 1 May (UTC) ([https://zonestamp.toolforge.org/1746162000 find in your time zone]). [[m:Special:MyLanguage/Universal_Code_of_Conduct/Annual_review/2025/Voter_information|Read the information on how to participate and read over the proposal before voting]] on the UCoC page on Meta-wiki. The [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee (U4C)]] is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review of the EG and Charter was planned and implemented by the U4C. Further information will be provided in the coming months about the review of the UCoC itself. For more information and the responsibilities of the U4C, you may [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Charter|review the U4C Charter]]. Please share this message with members of your community so they can participate as well. In cooperation with the U4C -- [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User_talk:Keegan (WMF)|talk]]) 00:35, 17 Abril 2025 (UTC) </div> <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28469465 --> == <span lang="en" dir="ltr">Vote on proposed modifications to the UCoC Enforcement Guidelines and U4C Charter</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> The voting period for the revisions to the Universal Code of Conduct Enforcement Guidelines and U4C Charter closes on 1 May 2025 at 23:59 UTC ([https://zonestamp.toolforge.org/1746162000 find in your time zone]). [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2025/Voter information|Read the information on how to participate and read over the proposal before voting]] on the UCoC page on Meta-wiki. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee (U4C)]] is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, you may [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|review the U4C Charter]]. Please share this message with members of your community in your language, as appropriate, so they can participate as well. In cooperation with the U4C -- <section end="announcement-content" /> </div> <div lang="en" dir="ltr" class="mw-content-ltr"> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 03:42, 29 Abril 2025 (UTC)</div> <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28618011 --> == We will be enabling the new Charts extension on your wiki soon! == ''(Apologies for posting in English)'' Hi all! We have good news to share regarding the ongoing problem with graphs and charts affecting all wikis that use them. As you probably know, the [[:mw:Special:MyLanguage/Extension:Graph|old Graph extension]] was disabled in 2023 [[listarchive:list/wikitech-l@lists.wikimedia.org/thread/EWL4AGBEZEDMNNFTM4FRD4MHOU3CVESO/|due to security reasons]]. We’ve worked in these two years to find a solution that could replace the old extension, and provide a safer and better solution to users who wanted to showcase graphs and charts in their articles. We therefore developed the [[:mw:Special:MyLanguage/Extension:Chart|Charts extension]], which will be replacing the old Graph extension and potentially also the [[:mw:Extension:EasyTimeline|EasyTimeline extension]]. After successfully deploying the extension on Italian, Swedish, and Hebrew Wikipedia, as well as on MediaWiki.org, as part of a pilot phase, we are now happy to announce that we are moving forward with the next phase of deployment, which will also include your wiki. The deployment will happen in batches, and will start from '''May 6'''. Please, consult [[:mw:Special:MyLanguage/Extension:Chart/Project#Deployment Timeline|our page on MediaWiki.org]] to discover when the new Charts extension will be deployed on your wiki. You can also [[:mw:Special:MyLanguage/Extension:Chart|consult the documentation]] about the extension on MediaWiki.org. If you have questions, need clarifications, or just want to express your opinion about it, please refer to the [[:mw:Special:MyLanguage/Extension_talk:Chart/Project|project’s talk page on Mediawiki.org]], or ping me directly under this thread. If you encounter issues using Charts once it gets enabled on your wiki, please report it on the [[:mw:Extension_talk:Chart/Project|talk page]] or at [[phab:tag/charts|Phabricator]]. Thank you in advance! -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 15:07, 6 Mayo 2025 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=28663781 --> == <span lang="en" dir="ltr">Call for Candidates for the Universal Code of Conduct Coordinating Committee (U4C)</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> The results of voting on the Universal Code of Conduct Enforcement Guidelines and Universal Code of Conduct Coordinating Committee (U4C) Charter is [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2025#Results|available on Meta-wiki]]. You may now [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Election/2025/Candidates|submit your candidacy to serve on the U4C]] through 29 May 2025 at 12:00 UTC. Information about [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Election/2025|eligibility, process, and the timeline are on Meta-wiki]]. Voting on candidates will open on 1 June 2025 and run for two weeks, closing on 15 June 2025 at 12:00 UTC. If you have any questions, you can ask on [[m:Talk:Universal Code of Conduct/Coordinating Committee/Election/2025|the discussion page for the election]]. -- in cooperation with the U4C, </div><section end="announcement-content" /> </div> <bdi lang="en" dir="ltr">[[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User_talk:Keegan (WMF)|usapan]])</bdi> 22:08, 15 Mayo 2025 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28618011 --> == RfC ongoing regarding Abstract Wikipedia (and your project) == <div lang="en" dir="ltr" class="mw-content-ltr"> ''(Apologies for posting in English, if this is not your first language)'' Hello all! We opened a discussion on Meta about a very delicate issue for the development of [[:m:Special:MyLanguage/Abstract Wikipedia|Abstract Wikipedia]]: where to store the abstract content that will be developed through functions from Wikifunctions and data from Wikidata. Since some of the hypothesis involve your project, we wanted to hear your thoughts too. We want to make the decision process clear: we do not yet know which option we want to use, which is why we are consulting here. We will take the arguments from the Wikimedia communities into account, and we want to consult with the different communities and hear arguments that will help us with the decision. The decision will be made and communicated after the consultation period by the Foundation. You can read the various hypothesis and have your say at [[:m:Abstract Wikipedia/Location of Abstract Content|Abstract Wikipedia/Location of Abstract Content]]. Thank you in advance! -- [[User:Sannita (WMF)|Sannita (WMF)]] ([[User talk:Sannita (WMF)|<span class="signature-talk">{{int:Talkpagelinktext}}</span>]]) 15:27, 22 Mayo 2025 (UTC) </div> <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=28768453 --> == <span lang="en" dir="ltr">Wikimedia Foundation Board of Trustees 2025 Selection & Call for Questions</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> :''[[m:Special:MyLanguage/Wikimedia Foundation elections/2025/Announcement/Selection announcement|{{int:interlanguage-link-mul}}]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-{{urlencode:Wikimedia Foundation elections/2025/Announcement/Selection announcement}}&language=&action=page&filter= {{int:please-translate}}]'' Dear all, This year, the term of 2 (two) Community- and Affiliate-selected Trustees on the Wikimedia Foundation Board of Trustees will come to an end [1]. The Board invites the whole movement to participate in this year’s selection process and vote to fill those seats. The Elections Committee will oversee this process with support from Foundation staff [2]. The Governance Committee, composed of trustees who are not candidates in the 2025 community-and-affiliate-selected trustee selection process (Raju Narisetti, Shani Evenstein Sigalov, Lorenzo Losa, Kathy Collins, Victoria Doronina and Esra’a Al Shafei) [3], is tasked with providing Board oversight for the 2025 trustee selection process and for keeping the Board informed. More details on the roles of the Elections Committee, Board, and staff are here [4]. Here are the key planned dates: * May 22 – June 5: Announcement (this communication) and call for questions period [6] * June 17 – July 1, 2025: Call for candidates * July 2025: If needed, affiliates vote to shortlist candidates if more than 10 apply [5] * August 2025: Campaign period * August – September 2025: Two-week community voting period * October – November 2025: Background check of selected candidates * Board’s Meeting in December 2025: New trustees seated Learn more about the 2025 selection process - including the detailed timeline, the candidacy process, the campaign rules, and the voter eligibility criteria - on this Meta-wiki page [[m:Special:MyLanguage/Wikimedia_Foundation_elections/2025|[link]]]. '''Call for Questions''' In each selection process, the community has the opportunity to submit questions for the Board of Trustees candidates to answer. The Election Committee selects questions from the list developed by the community for the candidates to answer. Candidates must answer all the required questions in the application in order to be eligible; otherwise their application will be disqualified. This year, the Election Committee will select 5 questions for the candidates to answer. The selected questions may be a combination of what’s been submitted from the community, if they’re alike or related. [[m:Special:MyLanguage/Wikimedia_Foundation_elections/2025/Questions_for_candidates|[link]]] '''Election Volunteers''' Another way to be involved with the 2025 selection process is to be an Election Volunteer. Election Volunteers are a bridge between the Elections Committee and their respective community. They help ensure their community is represented and mobilize them to vote. Learn more about the program and how to join on this Meta-wiki page [[m:Wikimedia_Foundation_elections/2025/Election_volunteers|[link].]] Thank you! [1] https://meta.wikimedia.org/wiki/Wikimedia_Foundation_elections/2022/Results [2] https://foundation.wikimedia.org/wiki/Committee:Elections_Committee_Charter [3] https://foundation.wikimedia.org/wiki/Resolution:Committee_Membership,_December_2024 [4] https://meta.wikimedia.org/wiki/Wikimedia_Foundation_elections_committee/Roles [5] https://meta.wikimedia.org/wiki/Wikimedia_Foundation_elections/2025/FAQ [6] https://meta.wikimedia.org/wiki/Wikimedia_Foundation_elections/2025/Questions_for_candidates Best regards, Victoria Doronina Board Liaison to the Elections Committee Governance Committee<section end="announcement-content" /> </div> [[Tagagamit:MediaWiki message delivery|MediaWiki message delivery]] ([[Usapang tagagamit:MediaWiki message delivery|kausapin]]) 03:08, 28 Mayo 2025 (UTC) <!-- Message sent by User:RamzyM (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28618011 --> == Vote now in the 2025 U4C Election == <div lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{Int:Please-translate}} Eligible voters are asked to participate in the 2025 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2025|2025 Election information page]]. The vote closes on 17 June 2025 at [https://zonestamp.toolforge.org/1750161600 12:00 UTC]. Please vote if your account is eligible. Results will be available by 1 July 2025. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 23:01, 13 Hunyo 2025 (UTC) </div> <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28848819 --> == <span lang="en" dir="ltr">Wikimedia Foundation Board of Trustees 2025 - Call for Candidates</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> :''<div class="plainlinks">[[m:Special:MyLanguage/Wikimedia Foundation elections/2025/Announcement/Call for candidates|{{int:interlanguage-link-mul}}]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-{{urlencode:Wikimedia Foundation elections/2025/Announcement/Call for candidates}}&language=&action=page&filter= {{int:please-translate}}]</div> Hello all, The [[m:Special:MyLanguage/Wikimedia Foundation elections/2025|call for candidates for the 2025 Wikimedia Foundation Board of Trustees selection is now open]] from June 17, 2025 – July 2, 2025 at 11:59 UTC [1]. The Board of Trustees oversees the Wikimedia Foundation's work, and each Trustee serves a three-year term [2]. This is a volunteer position. This year, the Wikimedia community will vote in late August through September 2025 to fill two (2) seats on the Foundation Board. Could you – or someone you know – be a good fit to join the Wikimedia Foundation's Board of Trustees? [3] Learn more about what it takes to stand for these leadership positions and how to submit your candidacy on [[m:Special:MyLanguage/Wikimedia Foundation elections/2025/Candidate application|this Meta-wiki page]] or encourage someone else to run in this year's election. Best regards, Abhishek Suryawanshi<br /> Chair of the Elections Committee On behalf of the Elections Committee and Governance Committee [1] https://meta.wikimedia.org/wiki/Special:MyLanguage/Wikimedia_Foundation_elections/2025/Call_for_candidates [2] https://foundation.wikimedia.org/wiki/Legal:Bylaws#(B)_Term. [3] https://meta.wikimedia.org/wiki/Special:MyLanguage/Wikimedia_Foundation_elections/2025/Resources_for_candidates<section end="announcement-content" /> </div> [[Tagagamit:MediaWiki message delivery|MediaWiki message delivery]] ([[Usapang tagagamit:MediaWiki message delivery|kausapin]]) 17:45, 17 Hunyo 2025 (UTC) <!-- Message sent by User:RamzyM (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=28866958 --> == <span lang="en" dir="ltr">Sister Projects Task Force reviews Wikispore and Wikinews</span> == <div lang="en" dir="ltr"> <section begin="message"/> Dear Wikimedia Community, The [[m:Wikimedia Foundation Community Affairs Committee|Community Affairs Committee (CAC)]] of the Wikimedia Foundation Board of Trustees assigned [[m:Wikimedia Foundation Community Affairs Committee/Sister Projects Task Force|the Sister Projects Task Force (SPTF)]] to update and implement a procedure for assessing the lifecycle of Sister Projects – wiki [[m:Wikimedia projects|projects supported by Wikimedia Foundation (WMF)]]. A vision of relevant, accessible, and impactful free knowledge has always guided the Wikimedia Movement. As the ecosystem of Wikimedia projects continues to evolve, it is crucial that we periodically review existing projects to ensure they still align with our goals and community capacity. Despite their noble intent, some projects may no longer effectively serve their original purpose. '''Reviewing such projects is not about giving up – it's about responsible stewardship of shared resources'''. Volunteer time, staff support, infrastructure, and community attention are finite, and the non-technical costs tend to grow significantly as our ecosystem has entered a different age of the internet than the one we were founded in. Supporting inactive projects or projects that didn't meet our ambitions can unintentionally divert these resources from areas with more potential impact. Moreover, maintaining projects that no longer reflect the quality and reliability of the Wikimedia name stands for, involves a reputational risk. An abandoned or less reliable project affects trust in the Wikimedia movement. Lastly, '''failing to sunset or reimagine projects that are no longer working can make it much harder to start new ones'''. When the community feels bound to every past decision – no matter how outdated – we risk stagnation. A healthy ecosystem must allow for evolution, adaptation, and, when necessary, letting go. If we create the expectation that every project must exist indefinitely, we limit our ability to experiment and innovate. Because of this, SPTF reviewed two requests concerning the lifecycle of the Sister Projects to work through and demonstrate the review process. We chose Wikispore as a case study for a possible new Sister Project opening and Wikinews as a case study for a review of an existing project. Preliminary findings were discussed with the CAC, and a community consultation on both proposals was recommended. === Wikispore === The [[m:Wikispore|application to consider Wikispore]] was submitted in 2019. SPTF decided to review this request in more depth because rather than being concentrated on a specific topic, as most of the proposals for the new Sister Projects are, Wikispore has the potential to nurture multiple start-up Sister Projects. After careful consideration, the SPTF has decided '''not to recommend''' Wikispore as a Wikimedia Sister Project. Considering the current activity level, the current arrangement allows '''better flexibility''' and experimentation while WMF provides core infrastructural support. We acknowledge the initiative's potential and seek community input on what would constitute a sufficient level of activity and engagement to reconsider its status in the future. As part of the process, we shared the decision with the Wikispore community and invited one of its leaders, Pharos, to an SPTF meeting. Currently, we especially invite feedback on measurable criteria indicating the project's readiness, such as contributor numbers, content volume, and sustained community support. This would clarify the criteria sufficient for opening a new Sister Project, including possible future Wikispore re-application. However, the numbers will always be a guide because any number can be gamed. === Wikinews === We chose to review Wikinews among existing Sister Projects because it is the one for which we have observed the highest level of concern in multiple ways. Since the SPTF was convened in 2023, its members have asked for the community's opinions during conferences and community calls about Sister Projects that did not fulfil their promise in the Wikimedia movement.[https://commons.wikimedia.org/wiki/File:WCNA_2024._Sister_Projects_-_opening%3F_closing%3F_merging%3F_splitting%3F.pdf <nowiki>[1]</nowiki>][https://meta.wikimedia.org/wiki/Wikimedia_Foundation_Community_Affairs_Committee/Sister_Projects_Task_Force#Wikimania_2023_session_%22Sister_Projects:_past,_present_and_the_glorious_future%22 <nowiki>[2]</nowiki>][https://meta.wikimedia.org/wiki/WikiConvention_francophone/2024/Programme/Quelle_proc%C3%A9dure_pour_ouvrir_ou_fermer_un_projet_%3F <nowiki>[3]</nowiki>] Wikinews was the leading candidate for an evaluation because people from multiple language communities proposed it. Additionally, by most measures, it is the least active Sister Project, with the greatest drop in activity over the years. While the Language Committee routinely opens and closes language versions of the Sister Projects in small languages, there has never been a valid proposal to close Wikipedia in major languages or any project in English. This is not true for Wikinews, where there was a proposal to close English Wikinews, which gained some traction but did not result in any action[https://meta.wikimedia.org/wiki/Proposals_for_closing_projects/Closure_of_English_Wikinews <nowiki>[4]</nowiki>][https://meta.wikimedia.org/wiki/WikiConvention_francophone/2024/Programme/Quelle_proc%C3%A9dure_pour_ouvrir_ou_fermer_un_projet_%3F <nowiki>[5]</nowiki>, see section 5] as well as a draft proposal to close all languages of Wikinews[https://meta.wikimedia.org/wiki/Talk:Proposals_for_closing_projects/Archive_2#Close_Wikinews_completely,_all_languages? <nowiki>[6]</nowiki>]. [[:c:File:Sister Projects Taskforce Wikinews review 2024.pdf|Initial metrics]] compiled by WMF staff also support the community's concerns about Wikinews. Based on this report, SPTF recommends a community reevaluation of Wikinews. We conclude that its current structure and activity levels are the lowest among the existing sister projects. SPTF also recommends pausing the opening of new language editions while the consultation runs. SPTF brings this analysis to a discussion and welcomes discussions of alternative outcomes, including potential restructuring efforts or integration with other Wikimedia initiatives. '''Options''' mentioned so far (which might be applied to just low-activity languages or all languages) include but are not limited to: *Restructure how Wikinews works and is linked to other current events efforts on the projects, *Merge the content of Wikinews into the relevant language Wikipedias, possibly in a new namespace, *Merge content into compatibly licensed external projects, *Archive Wikinews projects. Your insights and perspectives are invaluable in shaping the future of these projects. We encourage all interested community members to share their thoughts on the relevant discussion pages or through other designated feedback channels. === Feedback and next steps === We'd be grateful if you want to take part in a conversation on the future of these projects and the review process. We are setting up two different project pages: [[m:Public consultation about Wikispore|Public consultation about Wikispore]] and [[m:Public consultation about Wikinews|Public consultation about Wikinews]]. Please participate between 27 June 2025 and 27 July 2025, after which we will summarize the discussion to move forward. You can write in your own language. I will also host a community conversation 16th July Wednesday 11.00 UTC and 17th July Thursday 17.00 UTC (call links to follow shortly) and will be around at Wikimania for more discussions. <section end="message"/> </div> -- [[User:Victoria|Victoria]] on behalf of the Sister Project Task Force, 20:58, 27 Hunyo 2025 (UTC) <!-- Message sent by User:Johan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Johan_(WMF)/Sister_project_MassMassage_on_behalf_of_Victoria/Target_list&oldid=28911188 --> == <span lang="en" dir="ltr">Temporary accounts will be rolled out soon</span> == <div lang="en" dir="ltr"> <section begin="body"/> Hello, we are the Wikimedia Foundation [[mw:Special:MyLanguage/Product Safety and Integrity|Product Safety and Integrity]] team. We would like to announce that '''we plan to enable [[mw:Special:MyLanguage/Trust and Safety Product/Temporary Accounts|temporary accounts]] for this wiki in the week of September 1'''. Temporary accounts are successfully live on 30 wikis, including many large ones like German, Japanese, and French. The change they bring is especially relevant to logged-out editors, who this feature is designed to protect. But it is also relevant to community members like mentors, patrollers, and admins – anyone who reverts edits, blocks users, or otherwise interacts with logged-out editors as part of keeping the wikis safe and accurate. '''Why we are building temporary accounts''' Our wikis should be safer to edit by default for logged-out editors. Temporary accounts allow people to continue editing the wikis without creating an account, while avoiding publicly tying their edits to their IP address. We believe this is in the best interest of our logged-out editors, who make valuable contributions to the wikis and who may later create accounts and grow our community of editors, admins, and other roles. Even though the wikis do warn logged-out editors that their IP address will be associated with their edit, many people may not understand what an IP address is, or that it could be used to connect them to other information about them in ways they might not expect. Additionally, our moderation software and tools rely too heavily on network origin (IP addresses) to identify users and patterns of activity, especially as IP addresses themselves are becoming less stable as identifiers. Temporary accounts allow for more precise interactions with logged-out editors, including more precise blocks, and can help limit how often we unintentionally end up blocking good-faith users who use the same IP addresses as bad-faith users. '''How temporary accounts work''' [[File:Temporary account banner and empty talk page.png|thumb]] Any time a logged-out user publishes an edit on this wiki, a cookie will be set in this user's browser, and a temporary account tied with this cookie will be automatically created. This account's name will follow the pattern: <code dir=ltr>~2025-12345-67</code> (a tilde, current year, a number). On pages like Recent Changes or page history, this name will be displayed. The cookie will expire 90 days after its creation. As long as it exists, all edits made from this device will be attributed to this temporary account. It will be the same account even if the IP address changes, unless the user clears their cookies or uses a different device or web browser. A record of the IP address used at the time of each edit will be stored for 90 days after the edit. However, only some logged-in users will be able to see it. '''What does this mean for different groups of users?''' '''For logged-out editors''' * This increases privacy: currently, if you do not use a registered account to edit, then everybody can see the IP address for the edits you made, even after 90 days. That will no longer be possible on this wiki. * If you use a temporary account to edit from different locations in the last 90 days (for example at home and at a coffee shop), the edit history and the IP addresses for all those locations will now be recorded together, for the same temporary account. Users who [[foundation:Special:MyLanguage/Policy:Access_to_temporary_account_IP_addresses|meet the relevant requirements]] will be able to view this data. If this creates any personal security concerns for you, please contact talktohumanrights at wikimedia.org for advice. '''For community members interacting with logged-out editors''' * A temporary account is uniquely linked to a device. In comparison, an IP address can be shared with different devices and people (for example, different people at school or at work might have the same IP address). * Compared to the current situation, it will be safer to assume that a temporary user's talk page belongs to only one person, and messages left there will be read by them. As you can see in the screenshot, temporary account users will receive notifications. It will also be possible to thank them for their edits, ping them in discussions, and invite them to get more involved in the community. '''For users who use IP address data to moderate and maintain the wiki''' * '''For patrollers''' who track persistent abusers, investigate violations of policies, etc.: Users who [[foundation:Special:MyLanguage/Policy:Access_to_temporary_account_IP_addresses|meet the requirements]] will be able to reveal temporary users' IP addresses and all contributions made by temporary accounts from a specific IP address or range ([[Special:IPContributions]]). They will also have access to useful information about the IP addresses thanks to the [[mw:Special:MyLanguage/Trust and Safety Product/IP Info|IP Info]] feature. Many other pieces of software have been built or adjusted to work with temporary accounts, including AbuseFilter, global blocks, Global User Contributions, and more. (For information for volunteer developers on how to update the code of your tools – see the last part of the message.) * '''For admins blocking logged-out editors''': ** It will be possible to block many abusers by just blocking their temporary accounts. A blocked person won't be able to create new temporary accounts quickly if the admin selects the [[mw:Special:MyLanguage/Autoblock|autoblock]] option. ** It will still be possible to block an IP address or IP range. * Temporary accounts will not be retroactively applied to contributions made before the deployment. On Special:Contributions, you will be able to see existing IP user contributions, but not new contributions made by temporary accounts on that IP address. Instead, you should use Special:IPContributions for this. '''Our requests for you, and next steps''' * If you know of any tools, bots, gadgets etc. using data about IP addresses or being available for logged-out users, you may want to test if they work on [[testwiki:Main_Page|testwiki]] or [[test2wiki:Main_Page|test2wiki]]. If you are a volunteer developer, [[mw:Special:MyLanguage/Trust and Safety Product/Temporary Accounts/For developers|read our documentation for developers]], and in particular, the section on [[mw:Special:MyLanguage/Trust and Safety Product/Temporary Accounts/For developers#How should I update my code?|how your code might need to be updated]]. * If you want to test the temporary account experience, for example just to check what it feels like, go to testwiki or test2wiki and edit without logging in. * Tell us if you know of any difficulties that need to be addressed. We will try to help, and if we are not able, we will consider the available options. * Look at our [[m:Meta:Babel#Temporary_Accounts:_access_to_IP_addresses_and_next_steps|previous message]] about requirements for users without extended rights who may need access to IP addresses. To learn more about the project, check out [[mw:Special:MyLanguage/Trust and Safety Product/Temporary Accounts/FAQ|our FAQ]] – you will find many useful answers there. You may also [[mw:Special:MyLanguage/Trust and Safety Product/Temporary Accounts/Updates|look at the updates]] (we have just posted one) and [[mw:Newsletter:Product Safety and Integrity|subscribe to our new newsletter]]. If you'd like to talk to me (Szymon) off-wiki, you will find me on Discord and Telegram. Thank you!<section end="body" /> </div> <bdi lang="en" dir="ltr">[[m:user:NKohli (WMF)|NKohli (WMF)]], [[m:user:SGrabarczuk (WMF)|SGrabarczuk (WMF)]]</bdi> 21:37, 26 Agosto 2025 (UTC) (This message was sent to [[:Wiktionary:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:Quiddity (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Quiddity_(WMF)/sandbox6&oldid=29181713 --> == <span lang="en" dir="ltr">Wikifunctions will be deployed on your wiki on 2025-09-17</span> == <div lang="en" dir="ltr"> <section begin="Message"/> :''[[m:Special:MyLanguage/Abstract Wikipedia/Wikifunctions deployment|{{int:interlanguage-link-mul}}]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-{{urlencode:Abstract Wikipedia/Wikifunctions deployment}}&language=&action=page&filter= {{int:please-translate}}]'' Hi all, we want to let you know that [[:f:|Wikifunctions]] is coming to your project soon! When enabled, you will be able to call functions from your project, and integrate them in your articles. A function is something that takes one or more inputs and transforms them into a desired output. Think of adding up two numbers, or converting miles into metres, or calculating how much time has passed since an event, or declining a word into a case. This is usually done with templates that are complicated to create or to import. With Wikifunctions, you will be able to do this with just a couple of clicks! Please check out [[:f:Special:MyLanguage/Wikifunctions:Introduction|these tutorials]] for more details. You’re also invited to [[:f:Special:CreateObject|create functions]] that you find useful, or [[:f:Wikifunctions:Suggest a function|ask for help from the Wikifunctions community]]. We would like to invite you to contribute to Wikifunctions, by translating the existing functions labels into your language, so that more users in your community can more easily reuse them on the project. You can also translate the messages for the Wikifunctions interface on TranslateWiki ([https://translatewiki.net/w/i.php?title=Special%3ATranslate&group=ext-wikilambda-ve&filter=%21translated&action=translate here for VisualEditor messages], and [https://translatewiki.net/w/i.php?title=Special%3ATranslate&group=ext-wikilambda-user&filter=%21translated&action=translate here for the Wikifunctions interface proper]). Of course, we are happy to help in case there are questions or difficulties, and we are ready to listen to your feedback. Please ping me directly in case of necessity or reach out to me [[User talk:Sannita (WMF)|on my talk page]]. -- [[User:Sannita (WMF)|Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 19:02, 10 Setyembre 2025 (UTC) <section end="Message"/> </div> (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=29237323 --> == Pagpapalit ng serbidor - May parating na panahon na maaari mo lamang basahin ang iyong wiki na hindi tatagal nang masyado == <section begin="server-switch"/><div class="plainlinks"> [[:m:Special:MyLanguage/Tech/Server switch|Basahin ang mensaheng ito sa ibang wika]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-Tech%2FServer+switch&language=&action=page&filter= {{int:please-translate}}] Ililipat ng [[foundation:|Pundasyong Wikimedia]] ang trapikong dumadaloy sa pagitan ng mga sentro ng datos (''data centers'') nito. Sisiguraduhin nito na mananatiling ''online'' ang Wikipedia at ang mga iba pang wiki ng Wikimedia kahit kung lumipas ang isang sakuna. Ililipat ang lahat ng trapiko sa '''{{#time:j xg|2025-09-24|tl}}'''. Magsisimula ang pagpapalit sa '''[https://zonestamp.toolforge.org/{{#time:U|2025-09-24T15:00|en}} {{#time:H:i e|2025-09-24T15:00}}]'''. Sa kasamaang palad, dahil sa limitasyon sa [[mw:Special:MyLanguage/Manual:What is MediaWiki?|MediaWiki]], kailangan munang ihinto ang lahat ng pagbabago habang ginagawa ang paglilipat. Humihingi po kami ng paumanhin para sa pagkagambalang ito, at sinisikap naming mabawasan ito sa mga susunod na panahon. May ipapakitang bandera sa lahat ng mga wiki 30 minuto bago magsimula ang operasyong ito. <span lang="en" dir="ltr" class="mw-content-ltr">This banner will remain visible until the end of the operation.</span> <span lang="en" dir="ltr" class="mw-content-ltr">You can contribute to the [https://meta.wikimedia.org/w/index.php?title=Special%3ATranslate&group=Centralnotice-tgroup-read_only_banner&task=view&language=&filter=&action=translate translation or proofreading] of this banner text.</span> '''Makababasa ka, nguni hindi makakapagbago, ng lahat ng mga wiki sa loob lamang ng maikling panahon.''' *Hindi ka makakapagbago ng hanggang sa isang oras sa {{#time:l j xg Y|2025-09-24|tl}}. *Kung susubukin mong magbago o maglagak sa mga oras na ito, makakikita ka ng mensahe ng kamalian. Inaasahan namin na walang mawawala na pagbabago sa mga minutong ito, ngunit hindi namin ito maipapangako. Kung nakikita mo ang mensahe ng kamalian, mangyaring maghintay hanggang bumalik sa normal na ang lahat. Pagkatapos niyon ay maaari mo nang mai-save ang iyong edit. Pero, amin namin kayong pinapayuhan na gumawa muna ng kopya ng iyong mga pagbabago, upang makasigurado. ''Mga ibang epekto'': *Babagal ang mga ''background job'' at maaaring tanggalin ang ilan. Maaaring hindi maisasapanahon ang mga pulang kawing ng kasimbilis ng normal. Kung maglilikha ka ng artikulo na nakakawing na sa ibang lugar, mas matagal na mananatiling pula ang kawing. Kailangang pahintuin ang mga ilang pangmatagalang iskrip. * Inaasahan namin na ang mga ''code deployment'' ay mangyayari katulad ng sa anumang ibang mga linggo. Pero, may mga ''case-by-case code freezes'' na mangyayari sa tamang panahon kung kakailanganin nila ito pagkatapos. * Hindi magagamit ang [[mw:Special:MyLanguage/GitLab|GitLab]] ng mga nasa 90 minutos. Maaaring ipagpaliban ang proyektong ito kung kinakailangan. Maaari mong [[wikitech:Switch_Datacenter|basahin ang iskedyul sa wikitech.wikimedia.org]]. Ihahayag ang anumang pagbabago sa iskedyul. '''Mangyaring ibahagi ang impormasyon sa iyong pamayanan.'''</div><section end="server-switch"/> <span dir=ltr>[[m:User:Trizek (WMF)|Trizek (WMF)]] ([[m:User talk:Trizek (WMF)|{{int:talk}}]])</span> 15:41, 18 Setyembre 2025 (UTC) (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:Trizek (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=29170715 --> == <span lang="en" dir="ltr">Have your say: vote for the 2025 Board of Trustees</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Hello all, The voting period for the [[m:Special:MyLanguage/Wikimedia Foundation elections/2025|2025 Board of Trustees election]] is now open. Candidates are running for two (2) seats on the Board. To check your voter eligibility, please visit the [[m:Special:MyLanguage/Wikimedia Foundation elections/2025/Voter eligibility guidelines|voter eligibility page]]. Learn more about them by [[m:Special:MyLanguage/Wikimedia Foundation elections/2025/Candidates|reading their application statements and watch their candidacy videos]]. When you are ready, go to the [[m:Special:SecurePoll/vote/405|SecurePoll voting page to vote]]. '''The vote is open from October 8 at 00:00 UTC to October 22 at 23:59 UTC.''' Best regards, Abhishek Suryawanshi<br />Chair, Elections Committee<section end="announcement-content" /> </div> [[Tagagamit:MediaWiki message delivery|MediaWiki message delivery]] ([[Usapang tagagamit:MediaWiki message delivery|kausapin]]) 04:49, 9 Oktubre 2025 (UTC) <!-- Message sent by User:RamzyM (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29360896 --> == <span lang="en" dir="ltr">Help us decide the name of the new Abstract Wikipedia project</span> == <div lang="en" dir="ltr"> <section begin="function1"/> {{int:Hello}}. Please help pick a name for the new Abstract Wikipedia wiki project. This project will be a wiki that will enable users to combine functions from [[:f:|Wikifunctions]] and data from Wikidata in order to generate natural language sentences in any supported languages. These sentences can then be used by any Wikipedia (or elsewhere). There will be two rounds of voting, each followed by legal review of candidates, with votes beginning on 20 October and 17 November 2025. Our goal is to have a final project name selected on mid-December 2025. If you would like to participate, then '''[[m:Special:MyLanguage/Abstract Wikipedia/Abstract Wikipedia naming contest|please learn more and vote now]]''' at meta-wiki. {{Int:Feedback-thanks-title}} <section end="function1"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 11:44, 20 Oktubre 2025 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29432175 --> == <span lang="en" dir="ltr">Seeking volunteers to join several of the movement’s committees</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Each year, typically from October through December, several of the movement’s committees seek new volunteers. Read more about the committees on their Meta-wiki pages: * [[m:Special:MyLanguage/Affiliations Committee|Affiliations Committee (AffCom)]] * [[m:Special:MyLanguage/Ombuds commission|Ombuds commission (OC)]] * [[m:Special:MyLanguage/Wikimedia Foundation/Legal/Community Resilience and Sustainability/Trust and Safety/Case Review Committee|Case Review Committee (CRC)]] Applications for the committees open on October 30, 2025. Applications for the Affiliations Committee, Ombuds commission and the Case Review Committee close on December 11, 2025. Learn how to apply by [[m:Special:MyLanguage/Wikimedia Foundation/Legal/Committee appointments|visiting the appointment page on Meta-wiki]]. Post to the talk page or email cst[[File:At sign.svg|16x16px|link=|(_AT_)]]wikimedia.org with any questions you may have. For the Committee Support team, <section end="announcement-content" /> </div> -[[m:User:MKaur (WMF)| MKaur (WMF)]] 14:14, 30 Oktubre 2025 (UTC) <!-- Message sent by User:MKaur (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29517125 --> == <span lang="en" dir="ltr">Reminder: Help us decide the name of the new Abstract Wikipedia project</span> == <div lang="en" dir="ltr"> <section begin="function2"/> {{int:Hello}}. Reminder: Please help to choose name for the new Abstract Wikipedia wiki project. The finalist vote starts today. The finalists for the name are: <span lang="en" dir="ltr" class="mw-content-ltr">Abstract Wikipedia, Multilingual Wikipedia, Wikiabstracts, Wikigenerator, Proto-Wiki</span>. If you would like to participate, then '''[[m:Special:MyLanguage/Abstract Wikipedia/Abstract Wikipedia naming contest|please learn more and vote now]]''' at meta-wiki. {{Int:Feedback-thanks-title}} <section end="function2"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 14:23, 20 Nobyembre 2025 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29583860 --> == Thank You for Last Year – Join Wiki Loves Ramadan 2026 == Dear Wikimedia communities, We hope you are doing well, and we wish you a happy New Year. ''Last year, we captured light. This year, we’ll capture legacy.'' In 2025, communities around the world shared the glow of Ramadan nights and the warmth of collective iftars. In 2026, ''Wiki Loves Ramadan'' is expanding, bringing more stories, more cultures, and deeper global connections across Wikimedia projects. We invite you to explore the ''Wiki Loves Ramadan 2026'' [[m:Special:MyLanguage/Wiki Loves Ramadan 2026|Meta page]] to learn how you can participate and [[m:Special:MyLanguage/Wiki Loves Ramadan 2026/Participating communities|sign up]] your community. 📷 ''Photo campaign on '' [[c:Special:MyLanguage/Commons:Wiki Loves Ramadan 2026|Wikimedia Commons]] If you have questions about the project, please refer to the FAQs: * [[m:Special:MyLanguage/Wiki Loves Ramadan/FAQ/|Meta-Wiki]] * [[c:Special:MyLanguage/Commons:Wiki Loves Ramadan/FAQ|Wikimedia Commons]] ''Early registration for updates is now open via the '''[[m:Special:RegisterForEvent/2710|Event page]]''''' ''Stay connected and receive updates:'' * [https://t.me/WikiLovesRamadan Telegram channel] * [https://lists.wikimedia.org/postorius/lists/wikilovesramadan.lists.wikimedia.org/ Mailing list] We look forward to collaborating with you and your community. '''The Wiki Loves Ramadan 2026 Organizing Team''' 19:45, 16 Enero 2026 (UTC) (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:ZI Jony@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=29879549 --> == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 Enero 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Action Required: Update templates/modules for electoral maps (Migrating from P1846 to P14226) == Hello everyone, This is a notice regarding an ongoing data migration on Wikidata that may affect your election-related templates and Lua modules (such as <code>Module:Itemgroup/list</code>). '''The Change:'''<br /> Currently, many templates pull electoral maps from Wikidata using the property [[:d:Property:P1846|P1846]], combined with the qualifier [[:d:Property:P180|P180]]: [[:d:Q19571328|Q19571328]]. We are migrating this data (across roughly 4,000 items) to a newly created, dedicated property: '''[[:d:Property:P14226|P14226]]'''. '''What You Need To Do:'''<br /> To ensure your templates and infoboxes do not break or lose their maps, please update your local code to fetch data from [[:d:Property:P14226|P14226]] instead of the old [[:d:Property:P1846|P1846]] + [[:d:Property:P180|P180]] structure. A [[m:Wikidata/Property Migration: P1846 to P14226/List|list of pages]] was generated using Wikimedia Global Search. '''Deadline:'''<br /> We are temporarily retaining the old data on [[:d:Property:P1846|P1846]] to allow for a smooth transition. However, to complete the data cleanup on Wikidata, the old [[:d:Property:P1846|P1846]] statements will be removed after '''May 1, 2026'''. Please update your modules and templates before this date to prevent any disruption to your wiki's election articles. Let us know if you have any questions or need assistance with the query logic. Thank you for your help! [[User:ZI Jony|ZI Jony]] using [[Tagagamit:MediaWiki message delivery|MediaWiki message delivery]] ([[Usapang tagagamit:MediaWiki message delivery|kausapin]]) 17:11, 3 Abril 2026 (UTC) (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:ZI Jony@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=29941252 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Tagagamit:MediaWiki message delivery|MediaWiki message delivery]] ([[Usapang tagagamit:MediaWiki message delivery|kausapin]]) 00:58, 26 Abril 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 Mayo 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|usapan]])</bdi> 17:12, 23 Hunyo 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 Hunyo 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 Hulyo 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == Pagpapalit ng serbidor - May parating na panahon na maaari mo lamang basahin ang iyong wiki na hindi tatagal nang masyado == <section begin="server-switch"/><div class="plainlinks"> [[:m:Special:MyLanguage/Tech/Server switch|Basahin ang mensaheng ito sa ibang wika]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-Tech%2FServer+switch&language=&action=page&filter= {{int:please-translate}}] Ililipat ng [[foundation:|Pundasyong Wikimedia]] ang trapikong dumadaloy sa pagitan ng mga sentro ng datos (''data centers'') nito. Sisiguraduhin nito na mananatiling ''online'' ang Wikipedia at ang mga iba pang wiki ng Wikimedia kahit kung lumipas ang isang sakuna. Ililipat ang lahat ng trapiko sa '''{{#time:j xg|2026-09-23|tl}}'''. Magsisimula ang pagpapalit sa '''[https://zonestamp.toolforge.org/{{#time:U|2026-09-23T14:00|en}} {{#time:H:i e|2026-09-23T14:00}}]'''. Sa kasamaang palad, dahil sa limitasyon sa [[mw:Special:MyLanguage/Manual:What is MediaWiki?|MediaWiki]], kailangan munang ihinto ang lahat ng pagbabago habang ginagawa ang paglilipat. Humihingi po kami ng paumanhin para sa pagkagambalang ito, at sinisikap naming mabawasan ito sa mga susunod na panahon. May ipapakitang bandera sa lahat ng mga wiki 30 minuto bago magsimula ang operasyong ito. <span lang="en" dir="ltr" class="mw-content-ltr">This banner will remain visible until the end of the operation.</span> <span lang="en" dir="ltr" class="mw-content-ltr">You can contribute to the [https://meta.wikimedia.org/w/index.php?title=Special%3ATranslate&group=Centralnotice-tgroup-read_only_banner&task=view&language=&filter=&action=translate translation or proofreading] of this banner text.</span> '''Makababasa ka, nguni hindi makakapagbago, ng lahat ng mga wiki sa loob lamang ng maikling panahon.''' * Hindi ka makakapagbago ng hanggang sa isang oras sa {{#time:l j xg Y|2026-09-23|tl}}. * Kung susubukin mong magbago o maglagak sa mga oras na ito, makakikita ka ng mensahe ng kamalian. Inaasahan namin na walang mawawala na pagbabago sa mga minutong ito, ngunit hindi namin ito maipapangako. Kung nakikita mo ang mensahe ng kamalian, mangyaring maghintay hanggang bumalik sa normal na ang lahat. Pagkatapos niyon ay maaari mo nang mai-save ang iyong edit. Pero, amin namin kayong pinapayuhan na gumawa muna ng kopya ng iyong mga pagbabago, upang makasigurado. ''Mga ibang epekto'': * Babagal ang mga ''background job'' at maaaring tanggalin ang ilan. Maaaring hindi maisasapanahon ang mga pulang kawing ng kasimbilis ng normal. Kung maglilikha ka ng artikulo na nakakawing na sa ibang lugar, mas matagal na mananatiling pula ang kawing. Kailangang pahintuin ang mga ilang pangmatagalang iskrip. * Inaasahan namin na ang mga ''code deployment'' ay mangyayari katulad ng sa anumang ibang mga linggo. Pero, may mga ''case-by-case code freezes'' na mangyayari sa tamang panahon kung kakailanganin nila ito pagkatapos. * Hindi magagamit ang [[mw:Special:MyLanguage/GitLab|GitLab]] ng mga nasa 90 minutos. Maaaring ipagpaliban ang proyektong ito kung kinakailangan. Maaari mong [[wikitech:Switch_Datacenter|basahin ang iskedyul sa wikitech.wikimedia.org]]. Ihahayag ang anumang pagbabago sa iskedyul. '''Mangyaring ibahagi ang impormasyon sa iyong pamayanan.'''</div><section end="server-switch"/> [[m:user:Trizek (WMF)|Trizek (WMF)]] 12:58, 15 Setyembre 2026 (UTC) (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:Trizek (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=30513874 --> == Pagpapalit ng serbidor - May parating na panahon na maaari mo lamang basahin ang iyong wiki na hindi tatagal nang masyado == <section begin="server-switch"/><div class="plainlinks"> [[:m:Special:MyLanguage/Tech/Server switch|Basahin ang mensaheng ito sa ibang wika]] • [https://meta.wikimedia.org/w/index.php?title=Special:Translate&group=page-Tech%2FServer+switch&language=&action=page&filter= {{int:please-translate}}] Ililipat ng [[foundation:|Pundasyong Wikimedia]] ang trapikong dumadaloy sa pagitan ng mga sentro ng datos (''data centers'') nito. Sinisigurado nito na mananatiling ''online'' ang Wikipedia at ang iba pang mga wiki ng Wikimedia kahit dumaan ang isang sakuna. Ililipat ang lahat ng trapiko sa '''{{#time:j xg|2026-10-28|tl}}'''. Magsisimula ang pagpapalit sa '''[https://zonestamp.toolforge.org/{{#time:U|2026-10-28T15:00|en}} {{#time:H:i e|2026-10-28T15:00}}]'''. Sa kasamaang palad, dahil sa ilang mga limitasyon sa [[mw:Special:MyLanguage/Manual:What is MediaWiki?|MediaWiki]], kailangan munang ihinto ang lahat ng pamamatnugot habang ginagawa ang paglilipat. Humihingi kami ng paumanhin para sa pagkagambalang ito, at sinisikap naming mabawasan ito sa mga susunod na panahon. May ipapakitang bandera sa lahat ng mga wiki 30 minuto bago magsimula ang operasyong ito. Magpapakita ang bandera into hanggang matapos ang operasyong ito. Maaari kang makisama sa [https://meta.wikimedia.org/w/index.php?title=Special%3ATranslate&group=Centralnotice-tgroup-read_only_banner&task=view&language=&filter=&action=translate pagsasalin o pagwawasto] ng teksto ng banderang ito. '''Makababasa ka, ngunit hindi makakapagbago, ng lahat ng mga wiki sa loob lamang ng maikling panahon.''' * Hindi ka makakapagbago ng hanggang sa isang oras sa {{#time:l j xg Y|2026-10-28|tl}}. * Kung susubukin mong magbago o maglagak sa mga oras na ito, makakikita ka ng mensahe ng kamalian. Inaasahan namin na walang mawawala na pagbabago sa mga minutong ito, ngunit hindi namin ito maipapangako. Kung nakikita mo ang mensahe ng kamalian, mangyaring maghintay hanggang bumalik sa normal na ang lahat. Pagkatapos niyon ay maaari mo nang mai-save ang iyong edit. Ngunit hinihikayat namin na gumawa ka ng kopya ng iyong mga pagbabago, upang makasigurado. ''Mga ibang epekto'': * Babagal ang mga ''background job'' at maaaring hindi tumakbo ang ilan. Maaaring hindi maisasapanahon ang mga pulang kawing ng kasing bilis ng normal. Kung maglilikha ka ng artikulo na nakakawing na sa ibang lugar, mas matagal na mananatiling pula ang kawing. Kailangang pahintuin ang mga ilang pangmatagalang skrito. * Inaasahan namin na ang mga ''code deployment'' ay mangyayari katulad ng sa anumang ibang mga linggo. Ngunit maaring may mga pagtitigal sa pagbabago ng kodigo na mangyayari sa tamang panahon kung kakailanganin nila ito pagkatapos. * Hindi magagamit ang [[mw:Special:MyLanguage/GitLab|GitLab]] ng mga nasa 90 minutos. Maaaring ipagpaliban ang proyektong ito kung kinakailangan. Maaari mong [[wikitech:Switch_Datacenter|basahin ang iskedyul sa wikitech.wikimedia.org]]. Ihahayag ang anumang pagbabago sa iskedyul. '''Mangyaring ibahagi ang impormasyon sa iyong pamayanan.'''</div><section end="server-switch"/> [[user:Trizek_(WMF)|Trizek_(WMF)]] 14:00, 26 Oktubre 2026 (UTC) (This message was sent to [[:Wiksiyonaryo:Usaping WikiMedia]] and is being posted here due to a redirect.) <!-- Message sent by User:Trizek (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=30513874 --> acibub0mxlr2czp1ydsr79ihyasc589 Module:etymology/templates/descendant 828 35062 178455 168636 2026-10-27T01:40:37Z GinawaSaHapon 3989 178455 Scribunto text/plain local export = {} local concat = table.concat local insert = table.insert local listToSet = require("Module:table").listToSet local rsplit = mw.text.split local descendants_tree_module = "Module:descendants tree" local labels_module = "Module:labels" local languages_module = "Module:languages" local links_module = "Module:links" local parse_utilities_module = "Module:parse utilities" local scripts_module = "Module:scripts" local table_module = "Module:table" local error_on_no_descendants = false local function qualifier(content) if content then return '<span class="ib-brac qualifier-brac">(</span><span class="ib-content qualifier-content">' .. content .. '</span><span class="ib-brac qualifier-brac">)</span>' end end local function track(page) return require("Module:debug/track")("descendant/" .. page) end local function ine(arg) if arg == "" then return nil else return arg end end local function add_tooltip(text, tooltip) return '<span class="desc-arr" title="' .. tooltip .. '">' .. text .. '</span>' end local function split_on_comma(term) if term:find(",%s") then return require(parse_utilities_module).split_on_comma(term) else return rsplit(term, ",") end end -- Params that modify a descendant term (as also supported by {{l}}, {{m}}). Doesn't include gloss=, which we -- handle specially. local param_term_mods = {"alt", "g", "id", "lit", "pos", "t", "tr", "ts"} local param_term_mod_set = listToSet(param_term_mods) -- Boolean params indicating whether a descendant term (or all terms) are particular sorts of borrowings. local bortypes = {"inh", "bor", "lbor", "slb", "obor", "translit", "der", "clq", "pclq", "sml", "unc"} local bortype_set = listToSet(bortypes) -- Aliases of clq=. local calque_aliases = {"cal", "calq", "calque"} local calque_alias_set = listToSet(calque_aliases) -- Aliases of pclq=. local partial_calque_aliases = {"pcal", "pcalq", "pcalque"} local partial_calque_alias_set = listToSet(partial_calque_aliases) -- Miscellaneous list params. local misc_list_params = {"q", "qq", "lb"} local misc_list_param_set = listToSet(misc_list_params) -- Add a "regular" list param such as g=, gloss=, lit=, etc. "Regular" here means that `param` and `param1` are -- the same thing. `type` if given is the param type (e.g. "boolean") and `alias_of` is used for params that are -- aliases of other params. local function add_regular_list_param(params, param, type, alias_of) local spec = {type = type, list = true} if alias_of == nil then spec.allow_holes = true else spec.alias_of = alias_of end params[param] = spec end -- Add an index-separated list param such as bor=, calq=, qq=, etc. "Index-separated" means that `param` and -- `param1` are different. Non-numbered `param` is accessible as `args.param` while numbered `param1`, `param2`, -- etc. are accessible as `args.partparam[1]`, `args.partparam[2]`, etc. `type` if given is the param type (e.g. -- "boolean") and `alias_of` is used for params that are aliases of other params. local function add_index_separated_list_param(params, param, type, alias_of) params[param] = {alias_of = alias_of, type = type} local spec = {type = type, list = param, require_index = true} if alias_of == nil then spec.allow_holes = true else spec.alias_of = "part" .. alias_of end params["part" .. param] = spec end -- Convert a raw lb= param (or nil) to a list of label info objects of the format described in get_label_info() in -- [[Module:labels]]). Unrecognized labels will end up with an unchanged display form. Return nil if nil passed in. local function split_and_process_raw_labels(raw_lb, lang) if not raw_lb then return nil end return require(labels_module).split_and_process_raw_labels { labels = raw_lb, lang = lang, nocat = true } end -- Return a function of one argument `arg` (a param name), which fetches args[`arg`] if index == 0, else -- args["part" .. `arg`][index]. local function get_val(args, index) return function(arg) if index == 0 then return args[arg] else return args["part" .. arg][index] end end end -- Return the arrow text for the `index`th term, or the overall arrow text if index == 0. local function get_arrow(args, index) local val = get_val(args, index) local arrow if val("bor") then arrow = add_tooltip("→", "hiram") elseif val("lbor") then arrow = add_tooltip("→", "aral na hiram") elseif val("slb") then arrow = add_tooltip("→", "bahagyang aral na hiram") elseif val("obor") then arrow = add_tooltip("→", "ortograpikong hiram") elseif val("translit") then arrow = add_tooltip("→", "transliterasyon") elseif val("clq") then arrow = add_tooltip("→", "kalko") elseif val("pclq") then arrow = add_tooltip("→", "bahagyang kalko") elseif val("sml") then arrow = add_tooltip("→", "hiram na kahulugan") elseif val("inh") or (val("unc") and not val("der")) then arrow = add_tooltip(">", "minana") else arrow = "" end -- allow der=1 in conjunction with bor=1 to indicate e.g. English "pars recta" -- derived and borrowed from Latin "pars". if val("der") then arrow = arrow .. add_tooltip("⇒", "hinulma sa pamamagitan ng analohiya o karagdagang morpema") end if val("unc") then arrow = arrow .. add_tooltip("?", "di-alam") end if arrow ~= "" then arrow = arrow .. " " end return arrow end -- Return the pre-qualifier text for the `index`th term, or the overall pre-qualifier text if index == 0. local function get_pre_qualifiers(args, index, lang) local val = get_val(args, index) local quals if index > 0 then local labels = split_and_process_raw_labels(val("lb"), lang) if labels then labels = require(labels_module).format_processed_labels { labels = labels, lang = lang, no_ib_content = true } if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances quals = {labels} end end end if val("q") then quals = quals or {} insert(quals, val("q")) end if quals then return require("Module:qualifier").format_qualifier(quals) .. " " else return "" end end -- Return the post-qualifier text for the `index`th term, or the overall post-qualifier text if index == 0. local function get_post_qualifiers(args, index, lang) local val = get_val(args, index) local postqs = {} if val("inh") then insert(postqs, qualifier("minana")) end if val("lbor") then insert(postqs, qualifier("aral na hiram")) end if val("slb") then insert(postqs, qualifier("bahagyang aral na hiram")) end if val("translit") then insert(postqs, qualifier("transliterasyon")) end if val("clq") then insert(postqs, qualifier("kalko")) end if val("pclq") then insert(postqs, qualifier("bahagyang kalko")) end if val("sml") then insert(postqs, qualifier("hiram na kahulugan")) end if val("qq") then insert(postqs, require("Module:qualifier").format_qualifier(val("qq"))) end if index == 0 then local labels = split_and_process_raw_labels(val("lb"), lang) if labels then labels = require(labels_module).format_processed_labels { labels = labels, lang = lang } if labels ~= "" then insert(postqs, "&mdash; " .. labels) end end end if #postqs > 0 then return " " .. concat(postqs, " ") end return "" end local function desc_or_desc_tree(frame, desc_tree) local params local boolean = {type = "boolean"} if desc_tree then params = { [1] = {required = true, type = "language", family = true, default = "gem-pro"}, [2] = {required = true, list = true, allow_holes = true, default = "*fuhsaz"}, ["notext"] = boolean, ["noalts"] = boolean, ["noparent"] = boolean, } else params = { [1] = {required = true, type = "language", family = true, default = "en"}, [2] = {list = true, allow_holes = true}, ["alts"] = boolean } -- If template namespace. if mw.title.getCurrentTitle().namespace == 10 then params[2].default = "word" end end for _, term_mod in ipairs(param_term_mods) do add_regular_list_param(params, term_mod) end -- Handle gloss= specially because it's an alias. add_regular_list_param(params, "gloss", nil, "t") -- Handle sc= specially because the type is "script". add_regular_list_param(params, "sc", "script") for _, bortype in ipairs(bortypes) do add_index_separated_list_param(params, bortype, "boolean") end for _, calque_alias in ipairs(calque_aliases) do add_index_separated_list_param(params, calque_alias, "boolean", "clq") end for _, partial_calque_alias in ipairs(partial_calque_aliases) do add_index_separated_list_param(params, partial_calque_alias, "boolean", "pclq") end for _, misc_list_param in ipairs(misc_list_params) do add_index_separated_list_param(params, misc_list_param) end -- Add other single params. params.sclang = boolean params.sclb = {type = "boolean", alias_of = "sclang"} params.nolang = boolean params.nolb = {type = "boolean", alias_of = "nolang"} local namespace = mw.title.getCurrentTitle().nsText local parent_args if frame.args[1] then parent_args = frame.args else parent_args = frame:getParent().args end -- FIXME: Temporary error message. for arg, _ in pairs(parent_args) do if type(arg) == "string" and arg:find("^tag[0-9]*$") then local lbarg = arg:gsub("^tag", "lb") error(("Use %s= instead of %s="):format(lbarg, arg)) end end -- Error to catch most uses of old-style parameters. if ine(parent_args[4]) and not ine(parent_args[3]) and not ine(parent_args.tr2) and not ine(parent_args.ts2) and not ine(parent_args.t2) and not ine(parent_args.gloss2) and not ine(parent_args.g2) and not ine(parent_args.alt2) then error("You specified a term in 4= and not one in 3=. You probably meant to use t= to specify a gloss instead. " .. "If you intended to specify two terms, put the second term in 3=.") end if not ine(parent_args[3]) and not ine(parent_args.alt2) and not ine(parent_args.tr2) and not ine(parent_args.ts2) and ine(parent_args.g2) then error("You specified a gender in g2= but no term in 3=. You were probably trying to specify two genders for " .. "a single term. To do that, put both genders in g=, comma-separated.") end local args = require("Module:parameters").process(parent_args, params) local lang = args[1] local terms = args[2] local alts = args.alt if (namespace == "" or namespace == "Reconstruction") and (lang:hasType("appendix-constructed") and not lang:hasType("regular")) then error("Terms in appendix-only constructed languages may not be given as descendants.") end local fetch_alt_forms = desc_tree and not args.noalts or not desc_tree and args.alts local m_desctree if desc_tree or fetch_alt_forms then m_desctree = require(descendants_tree_module) end if lang:getCode() ~= lang:getFullCode() then -- [[Special:WhatLinksHere/Wiktionary:Tracking/descendant/etymological]] track("etymological") track("etymological/" .. lang:getCode()) end local is_family = lang:hasType("family") local proxy_lang if is_family then -- [[Special:WhatLinksHere/Wiktionary:Tracking/descendant/family]] track("family") track("family/" .. lang:getCode()) proxy_lang = require(languages_module).getByCode("und") else proxy_lang = lang end local languageName if is_family then -- The display form for families includes the word "languages", which we probably don't want to -- display. languageName = lang:getCanonicalName() else languageName = lang:getDisplayForm() end local langtag if args.sclang then local sc = args.sc[1] if sc then langtag = sc:getDisplayForm() else local term, alt = terms[1], alts[1] local best_sc if is_family then best_sc = require(scripts_module).findBestScriptWithoutLang(term or alt, "none is last resort") else best_sc = lang:findBestScript(term or alt) end langtag = best_sc:getDisplayForm() end else langtag = languageName end -- Find the maximum index among any of the list parameters. local maxmaxindex = terms.maxindex for k, v in pairs(args) do if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then maxmaxindex = v.maxindex end end local parts = {} local terms_for_descendant_trees = {} -- Keep track of descendants whose descendant tree we fetch. Don't fetch the same descendant tree twice (which -- can happen especially with Arabic-script terms with the same unvocalized spelling but differing vocalization). -- This happens e.g. with Ottoman Turkish [[پورتقال]], which has {{desctree|fa-cls|پُرْتُقَال|پُرْتِقَال|bor=1}}, with -- two terms that have the same unvocalized spelling. local terms_and_ids_fetched = {} local descendant_terms_seen = {} local use_semicolon = false local ind = 0 for i = 1, maxmaxindex do local term = terms[i] if term ~= ";" then ind = ind + 1 local alt = args.alt[ind] local id = args.id[ind] local sc = args.sc[ind] local tr = args.tr[ind] local ts = args.ts[ind] local gloss = args.t[ind] local pos = args.pos[ind] local lit = args.lit[ind] local g = args.g[ind] and rsplit(args.g[ind], "%s*,%s*") or {} local link local terms_for_alt_forms = {} local termobj = { lang = proxy_lang, } -- Initialize `termobj` with indexed modifier params such as t1, t2, etc. and alt1, alt2, etc. Inline -- modifiers specified using the <...> notation override these. local function reinit_termobj(term) termobj.term = term termobj.sc = sc termobj.track_sc = true termobj.term = term termobj.alt = alt termobj.id = id termobj.tr = tr termobj.ts = ts termobj.genders = g termobj.gloss = gloss termobj.pos = pos termobj.lit = lit end -- Construct a link out of `termobj`. Also add the term to the list of descendant trees and/or alternative -- forms to fetch, if the page+ID combination hasn't already been seen. local function get_link() local link = "" -- If an individual term has a literal comma in it, use semicolons for all joiners. Otherwise we use -- semicolon only if the user specified a literal semicolon as a term. if termobj.term and termobj.term:find(",") then use_semicolon = true end if termobj.term ~= "-" then -- including term == nil link = require("Module:links").full_link(termobj, nil, true) if termobj.term and (desc_tree or fetch_alt_forms) then local entry_name = require(links_module).get_link_page(termobj.term, lang, sc) -- NOTE: We use the term and ID as the key, but not the language. This is OK currently because -- all terms have the same language; but if we ever add support for a term-specific language, -- we need to fix this. local term_and_id = termobj.id and entry_name .. "!!!" .. termobj.id or entry_name if not terms_and_ids_fetched[term_and_id] then terms_and_ids_fetched[term_and_id] = true local term_for_fetching = { lang = lang, entry_name = entry_name, id = termobj.id } if desc_tree then if is_family then error("No support currently (and probably ever) for fetching a descendant tree when a family code instead of language code is given") end if error_on_no_descendants then require(table_module).insertIfNot(descendant_terms_seen, { term = termobj.term, id = termobj.id }) end table.insert(terms_for_descendant_trees, term_for_fetching) end if fetch_alt_forms then if is_family then error("No support currently (and probably ever) for fetching alternative forms when a family code instead of language code is given") end -- [[Special:WhatLinksHere/Wiktionary:Tracking/descendant/alts]] track("alts") table.insert(terms_for_alt_forms, term_for_fetching) end end end elseif termobj.ts or termobj.gloss or #termobj.genders > 0 then -- [[Special:WhatLinksHere/Wiktionary:Tracking/descendant/no term]] track("no term") termobj.term = nil link = require("Module:links").full_link(termobj, nil, true) link = link :gsub("<small>%[Term%?%]</small> ", "") :gsub("<small>%[Term%?%]</small>&nbsp;", "") :gsub("%[%[Category:[^%[%]]+ term requests%]%]", "") else -- display no link at all -- [[Special:WhatLinksHere/Wiktionary:Tracking/descendant/no term or annotations]] track("no term or annotations") end return link end -- Check for inline modifier, e.g. מרים<tr:Miryem>. But exclude HTML entry with <span ...>, <i ...>, -- <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{af|...}} or similar. if term and term:find("<") and not require(parse_utilities_module).term_contains_top_level_html(term) then local run = require(parse_utilities_module).parse_balanced_segment_run(term, "<", ">") -- Split the non-modifier parts of an alternating run on comma, but not on comma+whitespace. local comma_separated_runs = require(parse_utilities_module).split_alternating_runs_on_comma(run) local sub_links = {} local function parse_err(msg) local parts = {} for _, run in ipairs(comma_separated_runs) do insert(parts, concat(run)) end error(msg .. ": " .. (i + 1) .. "=" .. concat(parts, ",")) end for j, run in ipairs(comma_separated_runs) do reinit_termobj(run[1]) local seen_mods = {} for k = 2, #run - 1, 2 do if run[k + 1] ~= "" then parse_err("Extraneous text '" .. run[k + 1] .. "' after modifier") end local modtext = run[k]:match("^<(.*)>$") if not modtext then parse_err("Internal error: Modifier '" .. modtext .. "' isn't surrounded by angle brackets") end local prefix, arg = modtext:match("^(%l+):(.*)$") if prefix then if seen_mods[prefix] then parse_err("Modifier '" .. prefix .. "' occurs twice, second occurrence " .. run[k]) end seen_mods[prefix] = true if prefix == "t" or prefix == "gloss" then termobj.gloss = arg elseif prefix == "g" then termobj.genders = rsplit(arg, "%s*,%s*") elseif prefix == "sc" then termobj.sc = arg elseif param_term_mod_set[prefix] then termobj[prefix] = arg elseif misc_list_param_set[prefix] then if j < #comma_separated_runs then parse_err("Modifier " .. run[k] .. " should come after the last term") end args["part" .. prefix][ind] = arg elseif prefix == "tag" then -- FIXME: Remove support for <tag:...> in favor of <lb:...> error("Use <lb:...> instead of <tag:...>") else parse_err("Unrecognized prefix '" .. prefix .. "' in modifier " .. run[k]) end elseif j < #comma_separated_runs then parse_err("Modifier " .. run[k] .. " should come after the last term") else if seen_mods[modtext] then parse_err("Modifier '" .. modtext .. "' occurs twice") end seen_mods[modtext] = true if bortype_set[modtext] then args["part" .. modtext][ind] = true elseif calque_alias_set[modtext] then args.partclq[ind] = true elseif partial_calque_alias_set[modtext] then args.partpclq[ind] = true else parse_err("Unrecognized modifier '" .. modtext .. "'") end end end local sub_link = get_link() if sub_link ~= "" then insert(sub_links, sub_link) end end link = concat(sub_links, "/") elseif term and term:find(",") then local sub_terms = split_on_comma(term) local sub_links = {} for _, sub_term in ipairs(sub_terms) do reinit_termobj(sub_term) local sub_link = get_link() if sub_link ~= "" then insert(sub_links, sub_link) end end link = concat(sub_links, "/") else reinit_termobj(term) link = get_link() end local arrow = get_arrow(args, ind) local preqs = get_pre_qualifiers(args, ind, proxy_lang) local postqs = get_post_qualifiers(args, ind, proxy_lang) insert(parts, { arrow = arrow, preqs = preqs, link = link, terms_for_alt_forms = terms_for_alt_forms, postqs = postqs, use_semicolon = terms[i - 1] == ";" }) end end local descendant_trees = {} for _, descterm in ipairs(terms_for_descendant_trees) do -- When I ([[User:Benwing2]]) first implemented this in Nov 2020, I had `maxmaxindex > 1` as the last argument. -- Since then, [[User:Fytcha]] changed the last param to `true`. local descendant_tree = m_desctree.get_descendants(descterm.lang, descterm.entry_name, descterm.id, true) if descendant_tree and descendant_tree ~= "" then insert(descendant_trees, descendant_tree) end end if error_on_no_descendants and desc_tree and not descendant_trees[1] then local function format_term_seen(term_seen) if term_seen.id then return ("[[%s]] with ID '%s'"):format(term_seen.term, term_seen.id) else return ("[[%s]]"):format(term_seen.term) end end if #descendant_terms_seen == 0 then error("[[Template:desctree]] invoked but no terms to retrieve descendants from") elseif #descendant_terms_seen == 1 then error(("No Descendants section was found in the entry %s under the header for %s"):format( format_term_seen(descendant_terms_seen[1]), lang:getFullName())) else for i, term_seen in ipairs(descendant_terms_seen) do descendant_terms_seen[i] = format_term_seen(term_seen) end error(("No Descendants section was found in any of the entries %s under the header for %s"):format( concat(descendant_terms_seen, ", "), lang:getFullName())) end end local descendants = concat(descendant_trees) if args.noparent then return descendants end local initial_arrow = get_arrow(args, 0) local initial_preqs = get_pre_qualifiers(args, 0, proxy_lang) local final_postqs = get_post_qualifiers(args, 0, proxy_lang) -- Now format each part. We wait to do this because we may not know the separator (semicolon or comma) till now. for i, part in ipairs(parts) do local partparts = {} local function ins(text) insert(partparts, text) end if not args.notext then ins(part.arrow) end ins(part.preqs) ins(part.link) for _, altterm in ipairs(part.terms_for_alt_forms) do local altform = m_desctree.get_alternative_forms(altterm.lang, altterm.entry_name, altterm.id, use_semicolon and "; " or ", ") if altform ~= "" then ins(use_semicolon and "; " or ", ") ins(altform) end end ins(part.postqs) local parttext = concat(partparts) if i > 1 and parttext ~= "" then parttext = ((use_semicolon or part.use_semicolon) and "; " or ", ") .. parttext end parts[i] = parttext end local all_linktext = initial_preqs .. concat(parts) .. final_postqs .. descendants if args.notext then return all_linktext elseif args.nolang then return initial_arrow .. all_linktext else return concat { initial_arrow, langtag, ":", all_linktext ~= "" and " " or "", all_linktext } end end function export.descendant(frame) return desc_or_desc_tree(frame, false) .. require("Module:TemplateStyles")("Module:etymology/style.css") end function export.descendants_tree(frame) return desc_or_desc_tree(frame, true) end return export gin10bc9fcxj5abshwqf9537wjex8l6 Module:R:Perseus 828 35549 178485 169528 2026-10-27T03:22:06Z GinawaSaHapon 3989 178485 Scribunto text/plain local export = {} -- Collisions contained in submodules of [[Module:R:Perseus/collision-data]]. local m_params = require("Module:parameters") local m_utils = require("Module:grc-utilities") local m_scripts = require("Module:scripts") local m_script_utils = require("Module:script utilities") local m_languages = require("Module:languages") local tag_greek = m_utils.tag local function tag_latin(text) local lang = m_languages.getByCode("la") local sc = m_scripts.getByCode("Latn") return m_script_utils.tag_text(text, lang, sc, nil) end local function track(code) require("Module:debug").track("R:Perseus/" .. code) return "" -- for format_perseus_wikilink end local function lower_dashed(w) return string.gsub(string.lower(w), " ", "-") end local function remove_diacritics(x) return mw.ustring.gsub(mw.ustring.toNFD(x), "%W+", "") end -- maybe there is a better way to do this local function beta(w) return require("Module:R:Perseus/polytonic-to-perseus-betacode").polytonic_to_perseus_betacode(w) end --[[ Resources: template name, with "R:" removed = { [1] = Perseus resource id, [2] = collisions index name, [3] = f-query-entry-postprocess or table of {get_entry = f-get-visible-entry, get_url_param = f-format-entry-into-url-param}, [4] = query-entry-suffix, [5] = language name } ]] -- This allows the optional selection of a different bio number for Smith's Persons. if mw.getCurrentFrame():getParent().args[2] then if mw.ustring.match(mw.getCurrentFrame():getParent().args[2],"-bio-",1) then a = "" else a = "-bio-1" end end local resources = { ["la:L&S"] = { "1999.04.0059", "LS", nil, nil, "latin", }, ["la:Elementary Lewis"] = { "1999.04.0060", "EL", nil, nil, "latin" }, ["la:Peck"] = { "1999.04.0062", nil, lower_dashed, "-harpers", "latin" }, ["la:PersEnc"] = { "1999.04.0004", nil, lower_dashed, "", "latin" }, ["la:Stillwell"] = { "1999.04.0006", "PECS", lower_dashed, "", "latin" }, ["la:Platner"] = { "1999.04.0054", "TDAR", lower_dashed, "", "latin" }, ["Smith's Antiquities"] = { "1999.04.0063", nil, lower_dashed, "-cn", "latin" }, ["Smith's Persons"] = { "1999.04.0104", nil, lower_dashed, a, "latin" }, ["Smith's Geography"] = { "1999.04.0064", nil, lower_dashed, "-geo", "latin" }, ["grc:LSJ"] = { "1999.04.0057", "LSJ", nil, nil, "greek" }, ["grc:Middle Liddell"] = { "1999.04.0058", "ML", nil, nil, "greek" }, ["grc:Harpocration"] = { "2013.01.0002", nil, function(w) return lower_dashed(remove_diacritics(w)) end, "", "greek" }, ["grc:Autenrieth"] = { "1999.04.0073", "Autenrieth", nil, nil, "greek" }, ["grc:Slater"] = { "1999.04.0072", "Slater", nil, nil, "greek" }, ["Zoega"] = { "2003.02.0002", "Zoega", {get_entry = function(w) return (w:gsub(" .*", ""):gsub("ǫ", "ö"):gsub("ǿ", "œ")) end, get_url_param = function(w) return lower_dashed(remove_diacritics(w)) end, }, nil, "non" }, } local function get_language(template) return resources[template][5] end local function is_collision(x, template) local collisions_data = resources[template][2] local lhs_postprocess = resources[template][3] or x if collisions_data then return mw.loadData("Module:R:Perseus/collision-data/" .. resources[template][2])[lhs_postprocess] == true end end local function format_perseus_url(beta_or_latin, template, redirect) local harpo = template == "grc:Harpocration" and ":letter=" .. string.upper(string.sub(remove_diacritics(beta_or_latin), 1, 1)) or "" local data = resources[template] local id = data[1] or "" local url_redirect_lhs = "https://www.perseus.tufts.edu/hopper/resolveform?type=exact&lookup=" local url_entry_lhs = "https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:" .. id .. harpo .. ":entry=" local url_rhs = redirect and "&lang=" .. get_language(template) or "" local get_entry local get_url_param local function identity(w) return w end if data[3] ~= nil then if type(data[3]) == "table" then get_entry = data[3].get_entry or identity get_url_param = data[3].get_url_param or identity else get_entry = identity get_url_param = data[3] end postprocess = function(w) return get_url_param(get_entry(w)) .. (data[4] or "") end else postprocess = identity end return (redirect and url_redirect_lhs or url_entry_lhs) .. postprocess(beta_or_latin) .. url_rhs end local function is_polytonic(text) local sccode = m_languages.getByCode("grc"):findBestScript(text):getCode() return sccode == "Polyt" end local function format_perseus_wikilink(title, beta_or_latin, template, redirect) local title_span = title if get_language(template) == "greek" then if not is_polytonic(title_span) then -- [[Special:WhatLinksHere/Wiktionary:Tracking/R:Perseus/wrong-script]] track("wrong-script") end title_span = tag_greek(title_span) elseif get_language(template) == "latin" then title_span = tag_latin(title_span) end return (beta_or_latin == "" and track("no Perseus link") or "“[" .. format_perseus_url(beta_or_latin, template, redirect) .. " " .. title_span .. "]”, in ") end function export.create(frame) local iparams = { ["rawurl"] = {type = "boolean"}, ["getentry"] = {type = "boolean"}, ["template"] = {}, } local iargs = m_params.process(frame.args, iparams) local params = { [1] = {}, -- Perseus code or word [2] = {}, -- word; only for Greek templates? ["page"] = {}, ["pages"] = {}, ["pageref"] = {}, ["column"] = {}, ["columns"] = {}, ["passage"] = {}, ["footer"] = {}, ["author"] = {}, } local args = m_params.process(frame:getParent().args, params) local template = iargs.template or string.gsub(frame:getParent():getTitle(), "^Template:R:", "") template = string.gsub(template, "^sandbox/", "") template = string.gsub(template, "/sandbox$", "") local latin = not (get_language(template) == "greek") if not latin and args[2] and not args[1] then error("Parameter 2 should be placed in parameter 1.") end local title = mw.loadData("Module:headword/data").pagename local word, perseus_code if latin then word = args[1] or title perseus_code = args[2] or title else word = args[2] if word and not is_polytonic(word) then error("Second parameter of {{[[Template:R:" .. template .. "|R:" .. template .. "]]}} should be a Greek word.") end if args[1] then if is_polytonic(args[1]) then if not word then word = args[1] else error("Second parameter of {{[[Template:R:" .. template .. "|R:" .. template .. "]]}} is a Greek word, so first parameter must be Perseus entry code.") end else perseus_code = args[1] end end if not word then local pagename = title if is_polytonic(pagename) then word = pagename elseif mw.title.getCurrentTitle().nsText == "Template" then word = "λέξις" else error("{{[[Template:R:" .. template .. "|R:" .. template .. "]]}} needs manual input: pagename is not Greek.") end end if not perseus_code then perseus_code = beta(word) end end local redirect = not (args[1] or args[2]) and is_collision(word, template) if word == template then return "" elseif iargs.getentry then local data = resources[template] if type(data[3]) == "table" then return data[3].get_entry(word) else return word end elseif iargs.rawurl then return format_perseus_url(perseus_code, template, redirect) else return format_perseus_wikilink(word, perseus_code, template, redirect) end end return export insaq5b348v14olw256k1pphzhi1hp1 178486 178485 2026-10-27T03:26:24Z GinawaSaHapon 3989 178486 Scribunto text/plain local export = {} -- Collisions contained in submodules of [[Module:R:Perseus/collision-data]]. local m_params = require("Module:parameters") local m_utils = require("Module:grc-utilities") local m_scripts = require("Module:scripts") local m_script_utils = require("Module:script utilities") local m_languages = require("Module:languages") local tag_greek = m_utils.tag local function tag_latin(text) local lang = m_languages.getByCode("la") local sc = m_scripts.getByCode("Latn") return m_script_utils.tag_text(text, lang, sc, nil) end local function track(code) require("Module:debug").track("R:Perseus/" .. code) return "" -- for format_perseus_wikilink end local function lower_dashed(w) return string.gsub(string.lower(w), " ", "-") end local function remove_diacritics(x) return mw.ustring.gsub(mw.ustring.toNFD(x), "%W+", "") end -- maybe there is a better way to do this local function beta(w) return require("Module:R:Perseus/polytonic-to-perseus-betacode").polytonic_to_perseus_betacode(w) end --[[ Resources: template name, with "R:" removed = { [1] = Perseus resource id, [2] = collisions index name, [3] = f-query-entry-postprocess or table of {get_entry = f-get-visible-entry, get_url_param = f-format-entry-into-url-param}, [4] = query-entry-suffix, [5] = language name } ]] -- This allows the optional selection of a different bio number for Smith's Persons. if mw.getCurrentFrame():getParent().args[2] then if mw.ustring.match(mw.getCurrentFrame():getParent().args[2],"-bio-",1) then a = "" else a = "-bio-1" end end local resources = { ["la:L&S"] = { "1999.04.0059", "LS", nil, nil, "latin", }, ["la:Elementary Lewis"] = { "1999.04.0060", "EL", nil, nil, "latin" }, ["la:Peck"] = { "1999.04.0062", nil, lower_dashed, "-harpers", "latin" }, ["la:PersEnc"] = { "1999.04.0004", nil, lower_dashed, "", "latin" }, ["la:Stillwell"] = { "1999.04.0006", "PECS", lower_dashed, "", "latin" }, ["la:Platner"] = { "1999.04.0054", "TDAR", lower_dashed, "", "latin" }, ["Smith's Antiquities"] = { "1999.04.0063", nil, lower_dashed, "-cn", "latin" }, ["Smith's Persons"] = { "1999.04.0104", nil, lower_dashed, a, "latin" }, ["Smith's Geography"] = { "1999.04.0064", nil, lower_dashed, "-geo", "latin" }, ["grc:LSJ"] = { "1999.04.0057", "LSJ", nil, nil, "greek" }, ["grc:Middle Liddell"] = { "1999.04.0058", "ML", nil, nil, "greek" }, ["grc:Harpocration"] = { "2013.01.0002", nil, function(w) return lower_dashed(remove_diacritics(w)) end, "", "greek" }, ["grc:Autenrieth"] = { "1999.04.0073", "Autenrieth", nil, nil, "greek" }, ["grc:Slater"] = { "1999.04.0072", "Slater", nil, nil, "greek" }, ["Zoega"] = { "2003.02.0002", "Zoega", {get_entry = function(w) return (w:gsub(" .*", ""):gsub("ǫ", "ö"):gsub("ǿ", "œ")) end, get_url_param = function(w) return lower_dashed(remove_diacritics(w)) end, }, nil, "non" }, } local function get_language(template) return resources[template][5] end local function is_collision(x, template) local collisions_data = resources[template][2] local lhs_postprocess = resources[template][3] or x if collisions_data then return mw.loadData("Module:R:Perseus/collision-data/" .. resources[template][2])[lhs_postprocess] == true end end local function format_perseus_url(beta_or_latin, template, redirect) local harpo = template == "grc:Harpocration" and ":letter=" .. string.upper(string.sub(remove_diacritics(beta_or_latin), 1, 1)) or "" local data = resources[template] local id = data[1] or "" local url_redirect_lhs = "https://www.perseus.tufts.edu/hopper/resolveform?type=exact&lookup=" local url_entry_lhs = "https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:" .. id .. harpo .. ":entry=" local url_rhs = redirect and "&lang=" .. get_language(template) or "" local get_entry local get_url_param local function identity(w) return w end if data[3] ~= nil then if type(data[3]) == "table" then get_entry = data[3].get_entry or identity get_url_param = data[3].get_url_param or identity else get_entry = identity get_url_param = data[3] end postprocess = function(w) return get_url_param(get_entry(w)) .. (data[4] or "") end else postprocess = identity end return (redirect and url_redirect_lhs or url_entry_lhs) .. postprocess(beta_or_latin) .. url_rhs end local function is_polytonic(text) local sccode = m_languages.getByCode("grc"):findBestScript(text):getCode() return sccode == "Polyt" end local function format_perseus_wikilink(title, beta_or_latin, template, redirect) local title_span = title if get_language(template) == "greek" then if not is_polytonic(title_span) then -- [[Special:WhatLinksHere/Wiktionary:Tracking/R:Perseus/wrong-script]] track("wrong-script") end title_span = tag_greek(title_span) elseif get_language(template) == "latin" then title_span = tag_latin(title_span) end return (beta_or_latin == "" and track("no Perseus link") or "“[" .. format_perseus_url(beta_or_latin, template, redirect) .. " " .. title_span .. "]”, in ") end function export.create(frame) local iparams = { ["rawurl"] = {type = "boolean"}, ["getentry"] = {type = "boolean"}, ["template"] = {}, } local iargs = m_params.process(frame.args, iparams) local params = { [1] = {}, -- Perseus code or word [2] = {}, -- word; only for Greek templates? ["page"] = {}, ["pages"] = {}, ["pageref"] = {}, ["column"] = {}, ["columns"] = {}, ["passage"] = {}, ["footer"] = {}, ["author"] = {}, } local args = m_params.process(frame:getParent().args, params) local template = iargs.template or string.gsub(frame:getParent():getTitle(), "^Padron:R:", "") template = string.gsub(template, "^sandbox/", "") template = string.gsub(template, "/sandbox$", "") local latin = not (get_language(template) == "greek") if not latin and args[2] and not args[1] then error("Parameter 2 should be placed in parameter 1.") end local title = mw.loadData("Module:headword/data").pagename local word, perseus_code if latin then word = args[1] or title perseus_code = args[2] or title else word = args[2] if word and not is_polytonic(word) then error("Second parameter of {{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} should be a Greek word.") end if args[1] then if is_polytonic(args[1]) then if not word then word = args[1] else error("Second parameter of {{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} is a Greek word, so first parameter must be Perseus entry code.") end else perseus_code = args[1] end end if not word then local pagename = title if is_polytonic(pagename) then word = pagename elseif mw.title.getCurrentTitle().nsText == "Template" then word = "λέξις" else error("{{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} needs manual input: pagename is not Greek.") end end if not perseus_code then perseus_code = beta(word) end end local redirect = not (args[1] or args[2]) and is_collision(word, template) if word == template then return "" elseif iargs.getentry then local data = resources[template] if type(data[3]) == "table" then return data[3].get_entry(word) else return word end elseif iargs.rawurl then return format_perseus_url(perseus_code, template, redirect) else return format_perseus_wikilink(word, perseus_code, template, redirect) end end return export hdqz20nfk4eclrjyr1y93e8r7t00aub 178488 178486 2026-10-27T03:34:20Z GinawaSaHapon 3989 178488 Scribunto text/plain local export = {} -- Collisions contained in submodules of [[Module:R:Perseus/collision-data]]. local m_params = require("Module:parameters") local m_utils = require("Module:grc-utilities") local m_scripts = require("Module:scripts") local m_script_utils = require("Module:script utilities") local m_languages = require("Module:languages") local tag_greek = m_utils.tag local function tag_latin(text) local lang = m_languages.getByCode("la") local sc = m_scripts.getByCode("Latn") return m_script_utils.tag_text(text, lang, sc, nil) end local function track(code) require("Module:debug").track("R:Perseus/" .. code) return "" -- for format_perseus_wikilink end local function lower_dashed(w) return string.gsub(string.lower(w), " ", "-") end local function remove_diacritics(x) return mw.ustring.gsub(mw.ustring.toNFD(x), "%W+", "") end -- maybe there is a better way to do this local function beta(w) return require("Module:R:Perseus/polytonic-to-perseus-betacode").polytonic_to_perseus_betacode(w) end --[[ Resources: template name, with "R:" removed = { [1] = Perseus resource id, [2] = collisions index name, [3] = f-query-entry-postprocess or table of {get_entry = f-get-visible-entry, get_url_param = f-format-entry-into-url-param}, [4] = query-entry-suffix, [5] = language name } ]] -- This allows the optional selection of a different bio number for Smith's Persons. if mw.getCurrentFrame():getParent().args[2] then if mw.ustring.match(mw.getCurrentFrame():getParent().args[2],"-bio-",1) then a = "" else a = "-bio-1" end end local resources = { ["la:L&S"] = { "1999.04.0059", "LS", nil, nil, "latin", }, ["la:Elementary Lewis"] = { "1999.04.0060", "EL", nil, nil, "latin" }, ["la:Peck"] = { "1999.04.0062", nil, lower_dashed, "-harpers", "latin" }, ["la:PersEnc"] = { "1999.04.0004", nil, lower_dashed, "", "latin" }, ["la:Stillwell"] = { "1999.04.0006", "PECS", lower_dashed, "", "latin" }, ["la:Platner"] = { "1999.04.0054", "TDAR", lower_dashed, "", "latin" }, ["Smith's Antiquities"] = { "1999.04.0063", nil, lower_dashed, "-cn", "latin" }, ["Smith's Persons"] = { "1999.04.0104", nil, lower_dashed, a, "latin" }, ["Smith's Geography"] = { "1999.04.0064", nil, lower_dashed, "-geo", "latin" }, ["grc:LSJ"] = { "1999.04.0057", "LSJ", nil, nil, "greek" }, ["grc:Middle Liddell"] = { "1999.04.0058", "ML", nil, nil, "greek" }, ["grc:Harpocration"] = { "2013.01.0002", nil, function(w) return lower_dashed(remove_diacritics(w)) end, "", "greek" }, ["grc:Autenrieth"] = { "1999.04.0073", "Autenrieth", nil, nil, "greek" }, ["grc:Slater"] = { "1999.04.0072", "Slater", nil, nil, "greek" }, ["Zoega"] = { "2003.02.0002", "Zoega", {get_entry = function(w) return (w:gsub(" .*", ""):gsub("ǫ", "ö"):gsub("ǿ", "œ")) end, get_url_param = function(w) return lower_dashed(remove_diacritics(w)) end, }, nil, "non" }, } local function get_language(template) return resources[template][5] end local function is_collision(x, template) local collisions_data = resources[template][2] local lhs_postprocess = resources[template][3] or x if collisions_data then return mw.loadData("Module:R:Perseus/collision-data/" .. resources[template][2])[lhs_postprocess] == true end end local function format_perseus_url(beta_or_latin, template, redirect) local harpo = template == "grc:Harpocration" and ":letter=" .. string.upper(string.sub(remove_diacritics(beta_or_latin), 1, 1)) or "" local data = resources[template] local id = data[1] or "" local url_redirect_lhs = "https://www.perseus.tufts.edu/hopper/resolveform?type=exact&lookup=" local url_entry_lhs = "https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:" .. id .. harpo .. ":entry=" local url_rhs = redirect and "&lang=" .. get_language(template) or "" local get_entry local get_url_param local function identity(w) return w end if data[3] ~= nil then if type(data[3]) == "table" then get_entry = data[3].get_entry or identity get_url_param = data[3].get_url_param or identity else get_entry = identity get_url_param = data[3] end postprocess = function(w) return get_url_param(get_entry(w)) .. (data[4] or "") end else postprocess = identity end return (redirect and url_redirect_lhs or url_entry_lhs) .. postprocess(beta_or_latin) .. url_rhs end local function is_polytonic(text) local sccode = m_languages.getByCode("grc"):findBestScript(text):getCode() return sccode == "Polyt" end local function format_perseus_wikilink(title, beta_or_latin, template, redirect) local title_span = title if get_language(template) == "greek" then if not is_polytonic(title_span) then -- [[Special:WhatLinksHere/Wiktionary:Tracking/R:Perseus/wrong-script]] track("wrong-script") end title_span = tag_greek(title_span) elseif get_language(template) == "latin" then title_span = tag_latin(title_span) end return (beta_or_latin == "" and track("no Perseus link") or "“[" .. format_perseus_url(beta_or_latin, template, redirect) .. " " .. title_span .. "]”, mula sa ") end function export.create(frame) local iparams = { ["rawurl"] = {type = "boolean"}, ["getentry"] = {type = "boolean"}, ["template"] = {}, } local iargs = m_params.process(frame.args, iparams) local params = { [1] = {}, -- Perseus code or word [2] = {}, -- word; only for Greek templates? ["page"] = {}, ["pages"] = {}, ["pageref"] = {}, ["column"] = {}, ["columns"] = {}, ["passage"] = {}, ["footer"] = {}, ["author"] = {}, } local args = m_params.process(frame:getParent().args, params) local template = iargs.template or string.gsub(frame:getParent():getTitle(), "^Padron:R:", "") template = string.gsub(template, "^sandbox/", "") template = string.gsub(template, "/sandbox$", "") local latin = not (get_language(template) == "greek") if not latin and args[2] and not args[1] then error("Parameter 2 should be placed in parameter 1.") end local title = mw.loadData("Module:headword/data").pagename local word, perseus_code if latin then word = args[1] or title perseus_code = args[2] or title else word = args[2] if word and not is_polytonic(word) then error("Second parameter of {{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} should be a Greek word.") end if args[1] then if is_polytonic(args[1]) then if not word then word = args[1] else error("Second parameter of {{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} is a Greek word, so first parameter must be Perseus entry code.") end else perseus_code = args[1] end end if not word then local pagename = title if is_polytonic(pagename) then word = pagename elseif mw.title.getCurrentTitle().nsText == "Template" then word = "λέξις" else error("{{[[Padron:R:" .. template .. "|R:" .. template .. "]]}} needs manual input: pagename is not Greek.") end end if not perseus_code then perseus_code = beta(word) end end local redirect = not (args[1] or args[2]) and is_collision(word, template) if word == template then return "" elseif iargs.getentry then local data = resources[template] if type(data[3]) == "table" then return data[3].get_entry(word) else return word end elseif iargs.rawurl then return format_perseus_url(perseus_code, template, redirect) else return format_perseus_wikilink(word, perseus_code, template, redirect) end end return export 0iyhbllry9ajkq9kv12w15iwec5z090 Apendise:Glosaryo 0 35981 178448 178444 2026-10-27T01:02:26Z GinawaSaHapon 3989 178448 wikitext text/x-wiki Ito ang glosaryo ng mga katagang pambalarila na ginagamit sa diksiyonaryong ito. <!-- Paunawa: wag pong tanggalin ang mga kataga sa Ingles para po masuportahan yung mga module at template na hindi pa nasasalin nang maayos. Ang pangunahing kahulugan ay para sa salin nito sa Tagalog. Para sa kataga sa Ingles, ire-redirect natin sa kataga sa Tagalog. Ngayon, posibleng magkaroon ng samu't saring kataga para sa isang konsepto (hal. unang panauhan vs panauhan una), sa ganitong kaso, pakigamit po ang {{anchor}} kung ito ay variation lang ng kataga. Irereserba lang sa mga kataga dito ang mga katagang natatangi. --> <!-- Wag munang i-link hanggat walang entry dito sa tlwikt. --> ==0-9== ; 1st person : ''tingnan ang '''{{lg|unang panauhan}}''''' ; 2nd person : ''tingnan ang '''{{lg|ikalawang panauhan}}''''' ; 3rd person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ==Simbolo== ; {{anchor|*|asterisk|asterisko}} * : kapag nakalagay bago ang isang kataga, ipinapahiwatig nito na ang naturang kataga ay isa lamang pagtataya at hindi kumpirmado sa pamamagitan ng aktuwal na pagsulat, halimbawa, ang katagang {{m|phi-pro|*dilaw}} ay ang salitang Proto-Pilipino para sa ''[[dilaw]]''. ; {{anchor|**|double asterisk|dobleng asterisko|dalawang asterisko}} ** : kapag nakalagay bago ang isang kataga, ipinapahiwatig nito ang naturang anyo ng kataga ay inaasahan kung susundin ang mga tuntunin, ngunit mali sa katunayan at may ibang anyo na aktuwal na ginagamit, halimbawa ang salitang Ingles na ''[[knife]]'', na kung susundin ang regular na paghuhulaping pangmaramihan ay magiging ''**knifes'', ngunit mali ito dahil ang tama ay ''[[knives]]''. ; {{anchor|[ ]|bracket|brackets|square bracket|square brackets}} [&nbsp;] : kung ginagamit sa isang pagbanggit, ipinapahiwatig nito na ang kataga ay nabanggit lamang nang pahapyaw at hindi aktuwal na ginamit: ikumpara ang salitang Ingles na {{m|en|manoeuvre}} sa mga pangungusap na ''Many will find ''manoeuvre'' hard to spell'' ("Marami ang nahihirapan baybayin ang salitang ''manoeuvre''") at ''He ''manoeuvres'' his car to avoid a collision'' ("Minaneobra niya ang kanyang sasakyan para makaiwas sa banggaan"). Bukod dito, ginagamit din ang mga ito upang magbigay impormasyon o konteksto, halimbawa ay "mahilig siyang kumain ng {{l|tl|libro|id=anatomiya}} [ng baka]". ==A== ; {{anchor|a|a.}} a. : [[#daglat|daglat]] para sa Latin ''[[ante]]'' ("[[bago]] [hindi ngayon o mamaya]"). Ibig sabihin, ang isang pagbanggit na may taon na ''a.'' 1924 ay nangangahulugan na ang naturang pagbanggit na yon ay bago ang taong 1924. ; abbreviation : ''tingnan ang '''{{lg|daglat}}''''' ; ablatibo, ablative, kaukulang ablatibo : ''tingnan ang '''{{lg|palayo}}''''' ; {{anchor|ablaut|grade|grado}} ablaut : sa Proto-Indo-Europeo at mga anak nito (pamilyang Indo-Europeo), tumutukoy ito sa sistema ng pagpapalitan ng mga patinig kung saan maaaring magbago ang mga patinig ng isang salita depende sa kahulugan. Halimbawa sa Ingles (isa sa mga anak na wika nito) ang {{m|en|goose}} at {{m|en|geese}}, kung saan ang nauna ay ang anyong pang-isahan at ang huli ay ang anyong pangmaramihan. Ginagamit ang sistemang ito sa [[#banghay|pagbabanghay]] at paggawa ng salita. May partikular na klase ng ablaut na tinatawag na '''grade''' o ''grado'' (kagaya ng [[#zero-grade|zero-grade]]). Ikumpara sa [[#umlaut|umlaut]]. ; absolutibo, absolutive : ''tingnan ang '''{{lg|patanggap}}''''' ; abstraktong pangngalan, abstract noun : ''tingnan ang '''{{lg|pangngalang basal}}''''' ; {{anchor|AD}} AD : daglat para sa ''Anno Domini'', katumbas ng [[#KP|KP]] sa mundong Kristiyano. ; adjective, adj. ''tingnan ang '''{{lg|pang-uri}}''''' ; adverb, adv. : ''tingnan ang '''{{lg|pang-abay}}''''' ; {{anchor|aral na hiram|arál na hiram|learned borrowing|learned loan}} aral na hiram : [[#hiram|salitang hiram]] na sadyang hiniram mula sa ibang wika imbes na dumaan sa likas na panghihiram ng mga wika sa isa't isa. Kadalasang resulta ito ng pagpunan ng mga mananalita sa mga konseptong wala sa kanilang wika. Halimbawa nito sa Tagalog ang {{m|tl|bansa}}, na isang aral na hiram mula sa Malay {{m|ms|bangsa}} upang punan ang konsepto ng Espanyol {{m|es|nacion}} dahil hindi maituturing na direktang katumbas nito ang {{m|tl|bayan}}. ; arkaiko, archaic : ''tingnan ang '''{{lg|makaluma}}''''' ; {{anchor|aspect|aspekto|aspeto|grammatical aspect}} aspekto, aspeto, aspect : katangian ng pandiwa na magbago ayon sa kakumpletuhan ng kilos. Wag ikalito sa [[#panahon|panahon]], na tumutukoy sa oras o panahon kung kailan isinagawa ang kilos. Sa Tagalog, ito ang [[#naganap|naganap]], [[#nagaganap|nagaganap]], [[#magaganap|magaganap]], at [[#kagaganap|kagaganap]]. ==B== ; {{anchor|banghay|pagbabanghay|conjugation|inflection}} banghay, pagbabanghay : pagbabago sa anyo ng mga salita ayon sa kategorya kagaya ng [[#aspekto|aspekto]], [[#panahon|panahon]], o [[#kailanan|kailanan]]. Karaniwang tumutukoy ito sa Tagalog sa proseso sa mga pandiwa, [[#deklinasyon|deklinasyon]] ang katumbas sa ibang bahagi ng pananalita kagaya ng sa pangngalan, panghalip, at pang-uri. ; {{anchor|bahagi ng pananalita|part of speech|PoS|POS|BNP|BnP}} bahagi ng pananalita, BNP, BnP : kategorya ng salita ayon sa tungkulin nito sa isang pangungusap. Ilan sa mga halimbawa ang [[#pangngalan|pangngalan]], [[#panghalip|panghalip]], [[#pandiwa|pandiwa]], at [[#pang-uri|pang-uri]]. Maaaring kabilang ang mga salita sa higit sa isang kategorya, gaya ng sa Tagalog {{m|tl|pula}}, na maaaring gamitin bilang pangngalan (''ang kotse ay pula'') o pang-uri (''ang pulang kotse''). ; {{anchor|BC|BK}} BC, BK : daglat para sa Bago si Kristo, katumbas ng [[#BKP|BKP]] sa mundong Kristiyano. ; {{anchor|bihira|madalang|rare}} bihira, madalang : ipinapahiwatig na ang naturang salita o kahulugan ay kumpirmadong ginagamit sa iilang piling konteksto at hindi karaniwang makikita o ginagamit labas sa mga kontekstong ito. Ikumpara sa [[#di-karaniwan|di-karaniwan]], na kahit papaano ay ginagamit ng malaki-laking grupo ngunit hindi ng mayorya. ; {{anchor|BCE|BKP}} BKP, BCE : daglat para sa Bago ang Karaniwang Panahon, katumbas ng [[#BK|BK]] sa mundong sekular. ; borrowing, borrowed : ''tingnan ang '''{{lg|hiram}}''''' ; by extension : ''tingnan ang '''{{lg|pinalawak}}''''' ==C== ; {{anchor|c.|circa|sirka}} circa, sirka, c. : ginagamit upang ipahiwatig na ang taon ay isa lamang pagtataya at hindi tumutukoy sa mismong taon. ; colloquial : ''tingnan ang '''{{lg|kolokyal}}''''' ; comparative : ''tingnan ang '''{{lg|pahambing}}''''' ; concrete noun : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; conjugation : [[#banghay|pagbabanghay]] sa pandiwa ; contemplative : ''tingnan ang '''{{lg|magaganap}}''''' ==D== ; {{anchor|abbr|abbreviation|daglat}} daglat : pinaikling anyo ng isang salita, halimbawa ay ''[[Dr.]]'' para sa [[doktor]]. ; dated : ''tingnan ang '''{{lg|luma}}''''' ; {{anchor|declination|declension|deklinasyon}} deklinasyon, declination, declension : [[#banghay|pagbabanghay]] sa pangngalan at katulad ; diaresis, diaeresis : ''tingnan ang '''{{lg|patuldok}}''''' ; di-literal : ''tingnan ang '''{{lg|matalinghaga}}''''' ==E== ; extended, extended sense : ''tingnan ang '''{{lg|pinalawak}}''''' ==F== ; figurative : ''tingnan ang '''{{lg|matalinghaga}}''''' ; first person, first-person : ''tingnan ang '''{{lg|unang panauhan}}''''' ; future tense : ''tingnan ang '''{{lg|panghinaharap}}''''' ==G== ; genitive : ''tingnan ang '''{{lg|paari}}''''' ==H== ; henitibo, kaukulang henitibo : ''tingnan ang '''{{lg|paari}}''''' ; hinaharap : ''tingnan ang '''{{lg|panghinaharap}}''''' ; {{anchor|hiram na salita|salitang hiram|salitang-hiram|hiniram|hiniram na salita|salitang hiniram|hiram|loanword|loan word|loaned|borrowing|borrowed|borrowed term}} hiram, hiram na salita, panghihiram : salitang nagmula sa ibang wika. Iba ito sa pagbuo ng salita na nagmula sa mas matandang anyo ng parehong wika. Humihiram madalas ang Tagalog sa Espanyol at Ingles, bagamat marami rin itong wika na pinanghihiraman. Ilan sa mga halimbawa ang {{m|tl|trak}} at {{m|tl|magasin}} mula Ingles at {{m|tl|oras}} at {{m|tl|maleta}} mula naman sa Espanyol. Maaari itong binago nang lubusan upang umakma sa pagbaybay ng wikang humiram gaya ng {{m|tl|kumpisal}} mula Espanyol {{m|es|confesar}}, o hindi, lalo na kung umaakma ang orihinal na baybay sa pagbaybay ng wikang humihiram gaya ng {{m|tl|bola}}, na nagmula sa Espanyol {{m|es|bola}}. Ikumpara sa ''[[#kalko|kalko]]'', kung saan tanging kahulugan lamang ang hiniram. ==I== ; {{anchor|second person|second-person|2nd person|pangalawang panauhan|ikalawang panauhan}} ikalawang panauhan, pangalawang panauhan : [[#panauhan|panauhan]] na tumutukoy sa kausap ng nagsasalita, halimbawa sa Tagalog ang mga panghalip na ''[[ikaw]]'', ''[[ka]]'', at ''[[kayo]]''. ; {{anchor|third person|third-person|3rd person|pangatlong panauhan|ikatlong panauhan}} ikatlong panauhan, pangatlong panauhan : [[#panauhan|panauhan]] na tumutukoy sa pinag-uusapan ng nagsasalita kung saan hindi siya kabilang, halimbawa sa Tagalog ang mga panghalip na ''[[siya]]'', ''[[niya]]'', at ''[[sila]]''. ; imperpektibo, imperfective : ''tingnan ang '''{{lg|nagaganap}}''''' ; inflection : ''tingnan ang '''{{lg|banghay}}''''' ; inherited : ''tingnan ang '''{{lg|mana}}''''' ; {{anchor|isahan|isa|singular|pang-isahan|sing.}} isahan : [[#kailanan|kailanan]] na nagpapahiwatig na iisa lamang ang bagay. ==K== ; {{anchor|kagaganap|kakaganap}} kagaganap, kakaganap : [[#aspekto|aspekto]] na nagpapahiwatig na kamakailan lang natapos ang isang kilos, halimbawa, ''kakakain''. ; {{anchor|number|grammatical number|kailanan|bilang}} kailanan : kategorya ng balarila na naglalarawan sa dami o bilang ng isang bagay. Ilan sa mga halimbawa ang [[#maramihan|maramihan]] at [[#isahan|isahan]] ; kasalukuyan : ''tingnan ang '''{{lg|pangkasalukuyan}}''''' ; kaso : ''tingnan ang '''{{lg|kaukulan}}''''' ; {{anchor|case|grammatical case|kaukulan|kaso}} kaukulan : isa sa mga anyo ng pangngalan depende sa tungkulin nito sa isang pangungusap, ilan sa mga halimbawa nito ang [[#palagyo|palagyo]] at [[#paari|paari]]. ; {{anchor|colloquial|kolokyal}} kolokyal : ipinapahiwatig na ang naturang salita o kahulugan ay ginagamit sa isang partikular na barayti ng wika. Ginagamit lamang ang mga salitang ito sa kalapit o kaswal na konteksto. Maaaring katumbas ng ''[[#di-pormal|di-pormal]]'' sa ibang mga wika, at kung itinatangi ang dalawa kagaya ng sa Tagalog, mas malakas ang kolokyal kesa di-pormal. ; komparatibo, kumparatibo : ''tingnan ang '''{{lg|pahambing}}''''' ; kongkretong pangngalan, pangngalang kongkreto : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; kontemplatibo : ''tingnan ang '''{{lg|magaganap}}''''' ; {{anchor|KP|CE}} KP, CE : daglat para sa Karaniwang Panahon, katumbas ng [[#AD|AD]] sa mundong sekular ==L== ; learned borrowing, learned loan : ''tingnan ang '''{{lg|aral na hiram}}''''' ; {{anchor|obsolete|lipas na|obs.}} lipas na : hindi na ginagamit, at hindi na maiintindihan ng karaniwang tao. Mas malakas kesa ''[[#makaluma|makaluma]]'', at di hamak na mas malakas kesa ''[[#luma|luma]]''. Iba ito sa ''[[#historikal|historikal]]'', na ginagamit pa sa kasalukuyan ngunit tumutukoy sa isang bagay na wala na. ; loanword, loan word : ''tingnan ang '''{{lg|hiram}}''''' ; {{anchor|dated|luma|laos}} luma, laos : ginagamit noon, ngunit hindi na ngayon, bagamat ginagamit pa rin ng nakakatandang henerasyon. Kumbaga, laos na, gaya ng {{m|tl|walastik}}. Mas mahina sa ''[[#makaluma|makaluma]]'', na hindi na ginagamit maliban kung gustong magtunog-luma, o ''[[#lipas na|lipas na]]'', na wala na'ng gumagamit at nakakaintindi sa kahit anong konteksto. ==M== ; {{anchor|contemplative|magaganap|kontemplatibo}} magaganap : [[#aspekto|aspekto]] na nagpapahiwatig na hindi pa nagsisimula ang isang kilos, halimbawa, ''kakain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#panghinaharap|panghinaharap]] dahil sa pagsasagawa sa kilos sa hinaharap (ikumpara ang ''kakain ako'' sa ''kakain ako mamaya''). ; {{anchor|makaluma|archaic|arkaiko}} makaluma : hindi na madalas gamitin, at kung gamitin man sa kasalukuyan ay upang magbigay ng tono ng kalumaan gaya ng mga nobelang historikal. Halimbawa ang paggamit sa salitang ''[[kalatas]]'' imbes na ''[[papel]]''. Mas mahina kesa ''[[#lipas na|lipas na]]'', na hindi na talaga ginagamit at maiintindihan, ngunit mas malakas pa rin kesa ''[[#luma|luma]]'', na naiintindihan pa rin at ginagamit ng marami-rami na bahagi ng mas matandang henerasyon. ; {{anchor|inherited|inherited term|inheritance|mana|manang salita|minanang salita|minana}} mana, manang salita, pagmamana : tumutukoy sa mga salitang nagmula sa isang lumang salita mula sa magulang wika nito sa pamamagitan ng likas na pagbabago ng tunog at walang karagdagang paglalapi, hindi tulad ng sa mga [[#hiram|hiram]]. Halimbawa, nagmula ang salitang {{m|tl|dahon}} sa magulang wika nitong Proto-Pilipino {{m|phi-pro|*dahun}}. ; {{anchor|maramihan|marami|pangmaramihan|plural|pl.}} maramihan : [[#kailanan|kailanan]] na nagpapahiwatig na higit sa isa ang dami ng mga bagay. Sa Tagalog, minamarkahan ito ng partikulong ''[[mga]]'', habang sa ibang wika, binabanghay ito gaya ng sa Ingles {{m|en|books}}, na anyong maramihan ng {{m|en|book}}. ; {{anchor|figurative|non-literal|di-literal|matalinghaga}} matalinghaga : hindi [[#literal|literal]], pawang tumutukoy sa mga [[metapora]], [[idyoma]], at katulad na paraan ng pananalita na hindi dapat unawain sa literal nitong kahulugan gaya ng ''[[balat-sibuyas]] ''("madaling umiyak; iyakin"). ==N== ; {{anchor|perpektibo|naganap|perfective}} naganap : [[#aspekto|aspekto]] na nagpapahiwatig na tapos na ang isang kilos, halimbawa, ''kumain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#pangnakaraan|pangnakaraan]] dahil sa pagkakumpleto ng kilos (ikumpara ang ''kumain ako'' sa ''kumain na ako''). Wag ikalito sa ''[[#perpekto|perpekto]]'', na wala sa Tagalog ngunit mabubuo sa mga wikang may panahon kagaya ng sa Ingles. ; {{anchor|imperpektibo|nagaganap|imperfective}} nagaganap : [[#aspekto|aspekto]] na nagpapahiwatig na hindi pa tapos ang isang kilos, halimbawa, ''kumakain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#pangkasalukuyan|pangkasalukuyan]] dahil sa pagsasagawa sa kilos sa kasalukuyan (ikumpara ang ''kumakain ako'' sa ''kumakain ako ngayon''). Wag ikalito sa ''[[#imperpekto|imperpekto]]'', na wala sa Tagalog ngunit mabubuo sa mga wikang may panahon kagaya ng sa Ingles. ; nakaraan, nagdaan : ''tingnan ang '''{{lg|pangnakaraan}}''''' ; {{anchor|nilipat|transferred|transferred sense}} nilipat : ipinapahiwatig na ang orihinal na kahulugan ng isang salita ay ginamit upang tumukoy sa isang partikular na konseptong may kaugnayan dito. Halimbawa, sa Latin, pumapatungkol ang salitang {{m|la|liber}} sa paglaya, ngunit nagkaroon ito ng nilipat na kahulugan para tumukoy sa mga malalayang tao (hindi alipin). Ikumpara sa ''[[#pinalawak|pinalawak]]'', na pumapatungkol naman sa kahulugan na pinalawak upang tumukoy sa ibang konseptong katulad nito. ; nominatibo, nominative, kaukulang nominatibo : ''tingnan ang '''{{lg|palagyo}}''''' ; non-literal : ''tingnan ang '''{{lg|matalinghaga}}''''' ; noun, n. : ''tingnan ang '''{{lg|pangngalan}}''''' ==O== ; obsolete, obs. : ''tingnan ang '''{{lg|lipas na}}''''' ==P== ; {{anchor|genitive|genitive case|kaukulang paari|paari}} paari, kaukulang paari : [[#kaukulan|kaukulan]] na nagpapahiwatig sa pag-aari o kaugnayan, sa Tagalog, minamarkahan ito ng ''[[ng]]'' para sa mga di-tao at ''[[ni]]'' (''[[nina]]'' kapag maramihan) para sa mga tao. ; {{anchor|pahambing|kumparatibo|komparatibo|comparative}} pahambing : [[#banghay|pagbabanghay]] sa isang pang-uri upang ipakita ang antas ng paghahambing na higit sa karaniwan ngunit hindi nasa tugatog. Sa Tagalog, ginagamit ang partikulong ''[[mas]]'' gaya ng ''mas masarap'' upang ipakita ang antas na ito. ; {{anchor|nominative|nominative case|kaukulang palagyo|palagyo}} palagyo, kaukulang palagyo : [[#kaukulan|kaukulan]] na nagpapahiwatig sa gumagawa ng kilos, sa Tagalog, minamarkahan ito ng ''[[ang]]'' para sa mga di-tao o ''[[si]]'' (''[[sina]]'' kapag maramihan) para sa mga tao. ; {{anchor|ablative|ablative case|kaukulang palayo|palayo}} palayo, kaukulang palayo : [[#kaukulan|kaukulan]] na nagpapahiwatig ng paglayo mula sa isang bagay. Para sa mga wikang meron nito, ginagamit ito nang mag-isa o may kasamang pang-ukol. Pinakamalapit na halimbawa sa Tagalog ay ang paggamit sa pang-ukol na ''[[mula]]'', kagaya ng sa ''mula Buendia''. May mga wikang tulad ng Latin na meron nito ngunit nakakuha ng maraming gamit bukod sa pagpapahiwatig ng paglayo. ; {{anchor|panahon|tense|grammatical tense}} panahon : katangian ng pandiwa na magbago depende sa oras o panahon kung kailan isinagawa ang kilos. Wag ikalito sa [[#aspekto|aspekto]], na tumutukoy sa kakumpletuhan ng kilos. Walang ganito sa Tagalog; pinakamalapit na katumbas ang paggamit sa mga salitang nagpapahiwatig ng oras gaya ng ''[[ngayon]]'', ''[[na]]'', ''[[kanina]]'', ''[[kasalukuyan]]'', at ''[[mamaya]]''. Ilan sa mga halimbawa ang [[#pangnakaraan|pangnakaraan]], [[#panghinaharap|panghinaharap]], at [[#pangkasalukuyan|pangkasalukuyan]]. ; {{anchor|person|grammatical person|panauhan}} panauhan : kategorya sa balarila na naglalarawan sa kaugnayan ng nagsasalita sa pinag-uusapan, ilan sa mga halimbawa ang [[#unang panauhan|unang panauhan]], [[#ikalawang panauhan|ikalawang panauhan]], at [[#ikatlong panauhan|ikatlong panauhan]]. ; {{anchor|pandiwa|pnd|v.|vb.|verb}} pandiwa : [[#bahagi ng pananalita|bahagi ng pananalita]] na tumutukoy sa kilos, kaganapan, o katayuan. Tinatawag na [[#pagbabanghay|pagbabanghay]] ang proseso ng pagbabago ng anyo nito ayon sa tungkulin nito sa pangungusap. ; {{anchor|pang-abay|pnb|adverb|adv.}} pang-abay : [[#bahagi ng pananalita|bahagi ng pananalita]] na naglalarawan sa pang-uri, pandiwa, o kapwa pang-abay. Sa Tagalog, umaakto ito na parang pang-uri at [[#banghay|binabanghay]] din sa kaparehong paraan, ang pagkakaiba lamang ay kung anong bahagi ng pananalita ang inilalarawan nito. Halimbawa ay ''mabilis maglakad'', kung saan ''mabilis'' ang pang-abay sa pandiwang ''maglakad''. Pansinin na magagamit din ang mga ito bilang pang-uri, gaya ng sa ''mabilis na lakad''. ; {{anchor|panghalip|pnh|pron.|pro.|pronoun}} panghalip : [[#bahagi ng pananalita|bahagi ng pananalita]] na humahalili sa isang pangngalan at tumutukoy sa paksa ng pinag-uusapan. Maaari itong humalili sa pangalan ng tao na nasa usapan gaya ng mga panghalip panao {{m|tl|ikaw}} at {{m|tl|ako}}, o tumukoy sa ibang tao ({{m|tl|siya}}) o bagay ({{m|tl|iyon}}). ; {{anchor|pang-uri|pnu|adjective|adj.}} pang-uri : [[bahagi ng pananalita]] na naglalarawan sa pangngalan o panghalip. Marami, ngunit hindi lahat, ng mga pang-uri sa Tagalog ang kinakabitan ng unlaping {{m|tl|ma-}} gaya ng ''maganda''. Halimbawa ay ''pulang mansanas'' o ''mansanas na pula'', sa parehong kaso, ''pula'' ang pang-uri. ; {{anchor|panghinaharap|hinaharap|future tense}} panghinaharap : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isasagawa sa hinaharap. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa hinaharap gaya ng ''[[mamaya]]'' o ''[[bukas]]''. Sa Ingles, minamarkahan ito ng mga salitang {{m|en|will}} o {{m|en|shall}}. ; pang-isahan : ''tingnan ang '''{{lg|isahan}}''''' ; {{anchor|pangkasalukuyan|kasalukuyan|present tense}} pangkasalukuyan : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isinasagawa sa ngayon. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa kasalukuyan gaya ng ''[[ngayon]]'' o ''[[na]]''. Sa Ingles, karaniwang binabanghay ang mga pandiwa gamit ang hulaping {{m|en|-ing}} para maipahiwatig ang panahong ito. ; pangmaramihan : ''tingnan ang '''{{lg|maramihan}}''''' ; {{anchor|pangnakaraan|nakaraan|nagdaan|pangnagdaan|past tense}} pangnakaraan, pangnagdaan : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isinagawa sa nakaraan. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa nakaraan gaya ng ''[[kanina]]'' o ''[[kahapon]]''. Halimbawa ay ang salitang Ingles na {{m|en|saw}}, ang anyong pangnakaraan ng {{m|en|see}}. ; {{anchor|noun|pangngalan|n.|png}} pangngalan : [[#bahagi ng pananalita|bahagi ng pananalita]] na tumutukoy sa [[tao]], [[bagay]], [[lugar]], o [[konsepto]]. ; {{anchor|basal na pangngalan|pangngalang basal|abstract noun|abstraktong pangngalan|pangngalang abstrakto}} pangngalang basal, basal na pangangalan : [[#pangngalan|pangngalan]] na tumutukoy sa mga konsepto, kumpara sa mga [[#pangngalang tahas|pangngalang tahas]], na tumutukoy naman sa mga pisikal na bagay. ; {{anchor|tahas na pangngalan|pangngalang tahas|concrete noun|kongkretong pangngalan|pangngalang kongkreto}} pangngalang tahas, tahas na pangangalan : [[#pangngalan|pangngalan]] na tumutukoy sa mga pisikal na bagay, kumpara sa mga [[#pangngalang basal|pangngalang basal]], na tumutukoy naman sa mga konsepto. ; part of speech, POS, PoS : ''tingnan ang '''{{lg|bahagi ng pananalita}}''''' ; past tense : ''tingnan ang '''{{lg|pangnakaraan}}''''' ; {{anchor|pasukdol|superlative|superlatibo}} pasukdol : [[#banghay|pagbabanghay]] sa pang-uri upang ipakita ang antas ng paghahambing na higit sa lahat. Sa Tagalog, ikinakabit ang mga unlaping {{m|tl|pinaka-}} o {{m|tl|napaka-}} gaya ng ''pinakamasarap'' o ''napakasarap'' upang ipakita ang antas na ito. ; {{anchor|absolutive|absolutibo|kaukulang absolutibo|kaukulang patanggap|patanggap}} patanggap, kaukulang patanggap : [[#kaukulan|kaukulan]] na nagpapahiwatig sa tumatanggap o nakakaranas ng resulta ng kilos. ; {{anchor|diaresis|diaeresis|patuldok}} patuldok : [[#tuldik|tuldik]] ( ¨ ) na karaniwang inilalagay sa taas ng isang patinig. Sa mga wikang Pilipino, ginagamit lamang ito para sa titik ''e'' (''ë'') upang kumatawan sa tunog na schwa sa ilang mga wika gaya ng Maranaw (''Mëranaw''). Sa ibang mga wika, inilalagay ito sa mga patinig upang sabihin na dapat itong bigkasin nang hiwalay at hindi bilang [[diptonggo]], gaya ng {{m+|fr|naïf|t=walang muwang}}, o para sabihin na iba ang pagbigkas sa naturang patinig kumpara sa karaniwan, gaya ng sa Aleman {{m|de|über|t=ibabaw}} at {{m|de|König|t=hari}}, sa prosesong tinatawag na [[#umlaut|umlaut]]. ; perpektibo, perfective : ''tingnan ang '''{{lg|naganap}}''''' ; person : ''tingnan ang '''{{lg|panauhan}}''''' ; {{anchor|pinalawak|extended sense|by extension}} pinalawak : ipinapahiwatig na ang orihinal na kahulugan nito ay pinalawak upang tumukoy sa mas maraming konsepto na hindi kasama sa orihinal na kahulugan nito. Halimbawa, tumutukoy ang salitang {{m|tl|mabigat}} sa literal na pisikal na bigat, ngunit nagkaroon ito kalaunan ng pinalawak na kahulugan na "nakakapagod, mahirap, seryoso" gaya ng sa ''mabigat na parusa''. Ikumpara ito sa ''[[#nilipat|nilipat]]'', na tumutukoy naman sa paglipat ng kahulugan upang tumukoy sa isang partikular na konseptong may kaugnayan dito. ; plural, pl : ''tingnan ang '''{{lg|maramihan}}''''' ; pnb<!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pang-abay}}''''' ; pnd <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pandiwa}}''''' ; png <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pangngalan}}''''' ; pnh <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|panghalip}}''''' ; pnu <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pang-uri}}''''' ; present tense : ''tingnan ang '''{{lg|pangkasalukuyan}}''''' ; pronoun, pron., pro. : ''tingnan ang '''{{lg|panghalip}}''''' ==R== ; rare : ''tingnan ang '''{{lg|bihira}}''''' ==S== ; salitang-hiram, salitang hiram : ''tingnan ang '''{{lg|hiram}}''''' ; second person, second-person : ''tingnan ang '''{{lg|ikalawang panauhan}}''''' ; singular, sing. : ''tingnan ang '''{{lg|isahan}}''''' ; superlatibo, superlative : ''tingnan ang '''{{lg|pasukdol}}''''' ==T== ; tense : ''tingnan ang '''{{lg|panahon}}''''' ; third person, third-person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ; tiyempo : ''tingnan ang '''{{lg|panahon}}''''' ; transferred, transferred sense : ''tingnan ang '''{{lg|nilipat}}''''' ; {{anchor|tuldik|diacritic|diacritical mark|diakritiko|diyakritiko|dayakritiko|accent|accent mark|aksent}} tuldik : simbolong ikinakabit o inilalagay sa isang titik upang baguhin ang tunog nito. Sa Tagalog at mga wikang Pilipino, may tatlong tuldik na ginagamit, [[#pahilis|pahilis]] ( ´ ), [[#paiwa|paiwa]] ( ` ), at [[#pakupya|pakupya]] ( ^ ), na ginagamit upang ipakita ang pagbigkas sa mga salita para maitangi ito sa mga may kaparehong baybay. Bukod dito, ginagamit din sa ilang mga wikang Pilipino ang tuldik na [[#patuldok|patuldok]], gaya ng sa Maranaw, upang isulat ang tunog na schwa. ==U== ; {{anchor|umlaut}} umlaut : pagbabago sa tunog kung saan binabago ang isang patinig upang umayon sa patinig ng kasunod nitong pantig. Ikumpara sa ''[[#ablaut|ablaut]]''. Ginagamit rin ang kataga para sa tuldik na [[#patuldok|patuldok]], upang ilarawan ang isang patinig na sumailalim sa prosesong ito. ; {{anchor|first person|first-person|1st person|unang panauhan}} unang panauhan : [[#panauhan|panauhan]] na tumutukoy sa nagsasalita o grupo ng mga nagsasalita, halimbawa sa Tagalog ang mga panghalip na ''[[ako]]'', ''[[ko]]'', at ''[[kami]]''. ==V== ; verb, v., vb. : ''tingnan ang '''{{lg|pandiwa}}''''' ==Z== ; {{anchor|zero-grade|zero grade}} zero-grade : sa Proto-Indo-Europeo, tumutukoy sa anyo ng [[#ablaut|ablaut]] ng isang ugat na hindi nagtataglay ng mga pangunahing ponemang patinig {{ic|*/e/}} at {{ic|*/o/}}. Halimbawa, {{m|ine-pro||*bʰr̥-}} ang ''zero-grade'' ng Indo-Europeong ugat {{m|ine-pro|*bʰer-|t=magbuhat, magpasan}}. q471fh3tx2m03df7kd6981iyu3ns0x1 178533 178448 2026-10-27T08:27:02Z GinawaSaHapon 3989 178533 wikitext text/x-wiki Ito ang glosaryo ng mga katagang pambalarila na ginagamit sa diksiyonaryong ito. <!-- Paunawa: wag pong tanggalin ang mga kataga sa Ingles para po masuportahan yung mga module at template na hindi pa nasasalin nang maayos. Ang pangunahing kahulugan ay para sa salin nito sa Tagalog. Para sa kataga sa Ingles, ire-redirect natin sa kataga sa Tagalog. Ngayon, posibleng magkaroon ng samu't saring kataga para sa isang konsepto (hal. unang panauhan vs panauhan una), sa ganitong kaso, pakigamit po ang {{anchor}} kung ito ay variation lang ng kataga. Irereserba lang sa mga kataga dito ang mga katagang natatangi. --> <!-- Wag munang i-link hanggat walang entry dito sa tlwikt. --> ==0-9== ; 1st person : ''tingnan ang '''{{lg|unang panauhan}}''''' ; 2nd person : ''tingnan ang '''{{lg|ikalawang panauhan}}''''' ; 3rd person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ==Simbolo== ; {{anchor|*|asterisk|asterisko}} * : kapag nakalagay bago ang isang kataga, ipinapahiwatig nito na ang naturang kataga ay isa lamang pagtataya at hindi kumpirmado sa pamamagitan ng aktuwal na pagsulat, halimbawa, ang katagang {{m|phi-pro|*dilaw}} ay ang salitang Proto-Pilipino para sa ''[[dilaw]]''. ; {{anchor|**|double asterisk|dobleng asterisko|dalawang asterisko}} ** : kapag nakalagay bago ang isang kataga, ipinapahiwatig nito ang naturang anyo ng kataga ay inaasahan kung susundin ang mga tuntunin, ngunit mali sa katunayan at may ibang anyo na aktuwal na ginagamit, halimbawa ang salitang Ingles na ''[[knife]]'', na kung susundin ang regular na paghuhulaping pangmaramihan ay magiging ''**knifes'', ngunit mali ito dahil ang tama ay ''[[knives]]''. ; {{anchor|[ ]|bracket|brackets|square bracket|square brackets}} [&nbsp;] : kung ginagamit sa isang pagbanggit, ipinapahiwatig nito na ang kataga ay nabanggit lamang nang pahapyaw at hindi aktuwal na ginamit: ikumpara ang salitang Ingles na {{m|en|manoeuvre}} sa mga pangungusap na ''Many will find ''manoeuvre'' hard to spell'' ("Marami ang nahihirapan baybayin ang salitang ''manoeuvre''") at ''He ''manoeuvres'' his car to avoid a collision'' ("Minaneobra niya ang kanyang sasakyan para makaiwas sa banggaan"). Bukod dito, ginagamit din ang mga ito upang magbigay impormasyon o konteksto, halimbawa ay "mahilig siyang kumain ng {{l|tl|libro|id=anatomiya}} [ng baka]". ==A== ; {{anchor|a|a.}} a. : [[#daglat|daglat]] para sa Latin ''[[ante]]'' ("[[bago]] [hindi ngayon o mamaya]"). Ibig sabihin, ang isang pagbanggit na may taon na ''a.'' 1924 ay nangangahulugan na ang naturang pagbanggit na yon ay bago ang taong 1924. ; abbreviation : ''tingnan ang '''{{lg|daglat}}''''' ; ablatibo, ablative, kaukulang ablatibo : ''tingnan ang '''{{lg|palayo}}''''' ; {{anchor|ablaut|grade|grado}} ablaut : sa Proto-Indo-Europeo at mga anak nito (pamilyang Indo-Europeo), tumutukoy ito sa sistema ng pagpapalitan ng mga patinig kung saan maaaring magbago ang mga patinig ng isang salita depende sa kahulugan. Halimbawa sa Ingles (isa sa mga anak na wika nito) ang {{m|en|goose}} at {{m|en|geese}}, kung saan ang nauna ay ang anyong pang-isahan at ang huli ay ang anyong pangmaramihan. Ginagamit ang sistemang ito sa [[#banghay|pagbabanghay]] at paggawa ng salita. May partikular na klase ng ablaut na tinatawag na '''grade''' o ''grado'' (kagaya ng [[#zero-grade|zero-grade]]). Ikumpara sa [[#umlaut|umlaut]]. ; absolutibo, absolutive : ''tingnan ang '''{{lg|patanggap}}''''' ; abstraktong pangngalan, abstract noun : ''tingnan ang '''{{lg|pangngalang basal}}''''' ; {{anchor|AD}} AD : daglat para sa ''Anno Domini'', katumbas ng [[#KP|KP]] sa mundong Kristiyano. ; adjective, adj. ''tingnan ang '''{{lg|pang-uri}}''''' ; adverb, adv. : ''tingnan ang '''{{lg|pang-abay}}''''' ; {{anchor|aral na hiram|arál na hiram|learned borrowing|learned loan}} aral na hiram : [[#hiram|salitang hiram]] na sadyang hiniram mula sa ibang wika imbes na dumaan sa likas na panghihiram ng mga wika sa isa't isa. Kadalasang resulta ito ng pagpunan ng mga mananalita sa mga konseptong wala sa kanilang wika. Halimbawa nito sa Tagalog ang {{m|tl|bansa}}, na isang aral na hiram mula sa Malay {{m|ms|bangsa}} upang punan ang konsepto ng Espanyol {{m|es|nacion}} dahil hindi maituturing na direktang katumbas nito ang {{m|tl|bayan}}. ; arkaiko, archaic : ''tingnan ang '''{{lg|makaluma}}''''' ; {{anchor|aspect|aspekto|aspeto|grammatical aspect}} aspekto, aspeto, aspect : katangian ng pandiwa na magbago ayon sa kakumpletuhan ng kilos. Wag ikalito sa [[#panahon|panahon]], na tumutukoy sa oras o panahon kung kailan isinagawa ang kilos. Sa Tagalog, ito ang [[#naganap|naganap]], [[#nagaganap|nagaganap]], [[#magaganap|magaganap]], at [[#kagaganap|kagaganap]]. ==B== ; {{anchor|banghay|pagbabanghay|conjugation|inflection}} banghay, pagbabanghay : pagbabago sa anyo ng mga salita ayon sa kategorya kagaya ng [[#aspekto|aspekto]], [[#panahon|panahon]], o [[#kailanan|kailanan]]. Karaniwang tumutukoy ito sa Tagalog sa proseso sa mga pandiwa, [[#deklinasyon|deklinasyon]] ang katumbas sa ibang bahagi ng pananalita kagaya ng sa pangngalan, panghalip, at pang-uri. ; {{anchor|bahagi ng pananalita|part of speech|PoS|POS|BNP|BnP}} bahagi ng pananalita, BNP, BnP : kategorya ng salita ayon sa tungkulin nito sa isang pangungusap. Ilan sa mga halimbawa ang [[#pangngalan|pangngalan]], [[#panghalip|panghalip]], [[#pandiwa|pandiwa]], at [[#pang-uri|pang-uri]]. Maaaring kabilang ang mga salita sa higit sa isang kategorya, gaya ng sa Tagalog {{m|tl|pula}}, na maaaring gamitin bilang pangngalan (''ang kotse ay pula'') o pang-uri (''ang pulang kotse''). ; {{anchor|BC|BK}} BC, BK : daglat para sa Bago si Kristo, katumbas ng [[#BKP|BKP]] sa mundong Kristiyano. ; {{anchor|bihira|madalang|rare}} bihira, madalang : ipinapahiwatig na ang naturang salita o kahulugan ay kumpirmadong ginagamit sa iilang piling konteksto at hindi karaniwang makikita o ginagamit labas sa mga kontekstong ito. Ikumpara sa [[#di-karaniwan|di-karaniwan]], na kahit papaano ay ginagamit ng malaki-laking grupo ngunit hindi ng mayorya. ; {{anchor|BCE|BKP}} BKP, BCE : daglat para sa Bago ang Karaniwang Panahon, katumbas ng [[#BK|BK]] sa mundong sekular. ; borrowing, borrowed : ''tingnan ang '''{{lg|hiram}}''''' ; by extension : ''tingnan ang '''{{lg|pinalawak}}''''' ==C== ; {{anchor|c.|circa|sirka}} circa, sirka, c. : ginagamit upang ipahiwatig na ang taon ay isa lamang pagtataya at hindi tumutukoy sa mismong taon. ; colloquial : ''tingnan ang '''{{lg|kolokyal}}''''' ; comparative : ''tingnan ang '''{{lg|pahambing}}''''' ; concrete noun : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; conjugation : [[#banghay|pagbabanghay]] sa pandiwa ; contemplative : ''tingnan ang '''{{lg|magaganap}}''''' ==D== ; {{anchor|abbr|abbreviation|daglat}} daglat : pinaikling anyo ng isang salita, halimbawa ay ''[[Dr.]]'' para sa [[doktor]]. ; dated : ''tingnan ang '''{{lg|luma}}''''' ; {{anchor|declination|declension|deklinasyon}} deklinasyon, declination, declension : [[#banghay|pagbabanghay]] sa pangngalan at katulad ; diaresis, diaeresis : ''tingnan ang '''{{lg|patuldok}}''''' ; di-literal : ''tingnan ang '''{{lg|matalinghaga}}''''' ==E== ; extended, extended sense : ''tingnan ang '''{{lg|pinalawak}}''''' ==F== ; figurative : ''tingnan ang '''{{lg|matalinghaga}}''''' ; first person, first-person : ''tingnan ang '''{{lg|unang panauhan}}''''' ; future tense : ''tingnan ang '''{{lg|panghinaharap}}''''' ==G== ; genitive : ''tingnan ang '''{{lg|paari}}''''' ==H== ; henitibo, kaukulang henitibo : ''tingnan ang '''{{lg|paari}}''''' ; hinaharap : ''tingnan ang '''{{lg|panghinaharap}}''''' ; {{anchor|hiram na salita|salitang hiram|salitang-hiram|hiniram|hiniram na salita|salitang hiniram|hiram|loanword|loan word|loaned|borrowing|borrowed|borrowed term}} hiram, hiram na salita, panghihiram : salitang nagmula sa ibang wika. Iba ito sa pagbuo ng salita na nagmula sa mas matandang anyo ng parehong wika. Humihiram madalas ang Tagalog sa Espanyol at Ingles, bagamat marami rin itong wika na pinanghihiraman. Ilan sa mga halimbawa ang {{m|tl|trak}} at {{m|tl|magasin}} mula Ingles at {{m|tl|oras}} at {{m|tl|maleta}} mula naman sa Espanyol. Maaari itong binago nang lubusan upang umakma sa pagbaybay ng wikang humiram gaya ng {{m|tl|kumpisal}} mula Espanyol {{m|es|confesar}}, o hindi, lalo na kung umaakma ang orihinal na baybay sa pagbaybay ng wikang humihiram gaya ng {{m|tl|bola}}, na nagmula sa Espanyol {{m|es|bola}}. Ikumpara sa ''[[#kalko|kalko]]'', kung saan tanging kahulugan lamang ang hiniram. ==I== ; {{anchor|second person|second-person|2nd person|pangalawang panauhan|ikalawang panauhan}} ikalawang panauhan, pangalawang panauhan : [[#panauhan|panauhan]] na tumutukoy sa kausap ng nagsasalita, halimbawa sa Tagalog ang mga panghalip na ''[[ikaw]]'', ''[[ka]]'', at ''[[kayo]]''. ; {{anchor|third person|third-person|3rd person|pangatlong panauhan|ikatlong panauhan}} ikatlong panauhan, pangatlong panauhan : [[#panauhan|panauhan]] na tumutukoy sa pinag-uusapan ng nagsasalita kung saan hindi siya kabilang, halimbawa sa Tagalog ang mga panghalip na ''[[siya]]'', ''[[niya]]'', at ''[[sila]]''. ; imperpektibo, imperfective : ''tingnan ang '''{{lg|nagaganap}}''''' ; inflection : ''tingnan ang '''{{lg|banghay}}''''' ; inherited : ''tingnan ang '''{{lg|mana}}''''' ; {{anchor|isahan|isa|singular|pang-isahan|sing.|isahang bilang}} isahan : [[#kailanan|kailanan]] na nagpapahiwatig na iisa lamang ang bagay. ==K== ; {{anchor|kagaganap|kakaganap}} kagaganap, kakaganap : [[#aspekto|aspekto]] na nagpapahiwatig na kamakailan lang natapos ang isang kilos, halimbawa, ''kakakain''. ; {{anchor|number|grammatical number|kailanan|bilang}} kailanan : kategorya ng balarila na naglalarawan sa dami o bilang ng isang bagay. Ilan sa mga halimbawa ang [[#maramihan|maramihan]] at [[#isahan|isahan]] ; kasalukuyan : ''tingnan ang '''{{lg|pangkasalukuyan}}''''' ; kaso : ''tingnan ang '''{{lg|kaukulan}}''''' ; {{anchor|case|grammatical case|kaukulan|kaso}} kaukulan : isa sa mga anyo ng pangngalan depende sa tungkulin nito sa isang pangungusap, ilan sa mga halimbawa nito ang [[#palagyo|palagyo]] at [[#paari|paari]]. ; {{anchor|colloquial|kolokyal}} kolokyal : ipinapahiwatig na ang naturang salita o kahulugan ay ginagamit sa isang partikular na barayti ng wika. Ginagamit lamang ang mga salitang ito sa kalapit o kaswal na konteksto. Maaaring katumbas ng ''[[#di-pormal|di-pormal]]'' sa ibang mga wika, at kung itinatangi ang dalawa kagaya ng sa Tagalog, mas malakas ang kolokyal kesa di-pormal. ; komparatibo, kumparatibo : ''tingnan ang '''{{lg|pahambing}}''''' ; kongkretong pangngalan, pangngalang kongkreto : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; kontemplatibo : ''tingnan ang '''{{lg|magaganap}}''''' ; {{anchor|KP|CE}} KP, CE : daglat para sa Karaniwang Panahon, katumbas ng [[#AD|AD]] sa mundong sekular ==L== ; learned borrowing, learned loan : ''tingnan ang '''{{lg|aral na hiram}}''''' ; {{anchor|obsolete|lipas na|obs.}} lipas na : hindi na ginagamit, at hindi na maiintindihan ng karaniwang tao. Mas malakas kesa ''[[#makaluma|makaluma]]'', at di hamak na mas malakas kesa ''[[#luma|luma]]''. Iba ito sa ''[[#historikal|historikal]]'', na ginagamit pa sa kasalukuyan ngunit tumutukoy sa isang bagay na wala na. ; loanword, loan word : ''tingnan ang '''{{lg|hiram}}''''' ; {{anchor|dated|luma|laos}} luma, laos : ginagamit noon, ngunit hindi na ngayon, bagamat ginagamit pa rin ng nakakatandang henerasyon. Kumbaga, laos na, gaya ng {{m|tl|walastik}}. Mas mahina sa ''[[#makaluma|makaluma]]'', na hindi na ginagamit maliban kung gustong magtunog-luma, o ''[[#lipas na|lipas na]]'', na wala na'ng gumagamit at nakakaintindi sa kahit anong konteksto. ==M== ; {{anchor|contemplative|magaganap|kontemplatibo}} magaganap : [[#aspekto|aspekto]] na nagpapahiwatig na hindi pa nagsisimula ang isang kilos, halimbawa, ''kakain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#panghinaharap|panghinaharap]] dahil sa pagsasagawa sa kilos sa hinaharap (ikumpara ang ''kakain ako'' sa ''kakain ako mamaya''). ; {{anchor|makaluma|archaic|arkaiko}} makaluma : hindi na madalas gamitin, at kung gamitin man sa kasalukuyan ay upang magbigay ng tono ng kalumaan gaya ng mga nobelang historikal. Halimbawa ang paggamit sa salitang ''[[kalatas]]'' imbes na ''[[papel]]''. Mas mahina kesa ''[[#lipas na|lipas na]]'', na hindi na talaga ginagamit at maiintindihan, ngunit mas malakas pa rin kesa ''[[#luma|luma]]'', na naiintindihan pa rin at ginagamit ng marami-rami na bahagi ng mas matandang henerasyon. ; {{anchor|inherited|inherited term|inheritance|mana|manang salita|minanang salita|minana}} mana, manang salita, pagmamana : tumutukoy sa mga salitang nagmula sa isang lumang salita mula sa magulang wika nito sa pamamagitan ng likas na pagbabago ng tunog at walang karagdagang paglalapi, hindi tulad ng sa mga [[#hiram|hiram]]. Halimbawa, nagmula ang salitang {{m|tl|dahon}} sa magulang wika nitong Proto-Pilipino {{m|phi-pro|*dahun}}. ; {{anchor|maramihan|marami|pangmaramihan|plural|pl.|maramihang bilang}} maramihan : [[#kailanan|kailanan]] na nagpapahiwatig na higit sa isa ang dami ng mga bagay. Sa Tagalog, minamarkahan ito ng partikulong ''[[mga]]'', habang sa ibang wika, binabanghay ito gaya ng sa Ingles {{m|en|books}}, na anyong maramihan ng {{m|en|book}}. ; {{anchor|figurative|non-literal|di-literal|matalinghaga}} matalinghaga : hindi [[#literal|literal]], pawang tumutukoy sa mga [[metapora]], [[idyoma]], at katulad na paraan ng pananalita na hindi dapat unawain sa literal nitong kahulugan gaya ng ''[[balat-sibuyas]] ''("madaling umiyak; iyakin"). ==N== ; {{anchor|perpektibo|naganap|perfective}} naganap : [[#aspekto|aspekto]] na nagpapahiwatig na tapos na ang isang kilos, halimbawa, ''kumain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#pangnakaraan|pangnakaraan]] dahil sa pagkakumpleto ng kilos (ikumpara ang ''kumain ako'' sa ''kumain na ako''). Wag ikalito sa ''[[#perpekto|perpekto]]'', na wala sa Tagalog ngunit mabubuo sa mga wikang may panahon kagaya ng sa Ingles. ; {{anchor|imperpektibo|nagaganap|imperfective}} nagaganap : [[#aspekto|aspekto]] na nagpapahiwatig na hindi pa tapos ang isang kilos, halimbawa, ''kumakain''. Sa Tagalog, karaniwan itong naipagkakamali sa [[#panahon|panahong]] [[#pangkasalukuyan|pangkasalukuyan]] dahil sa pagsasagawa sa kilos sa kasalukuyan (ikumpara ang ''kumakain ako'' sa ''kumakain ako ngayon''). Wag ikalito sa ''[[#imperpekto|imperpekto]]'', na wala sa Tagalog ngunit mabubuo sa mga wikang may panahon kagaya ng sa Ingles. ; nakaraan, nagdaan : ''tingnan ang '''{{lg|pangnakaraan}}''''' ; {{anchor|nilipat|transferred|transferred sense}} nilipat : ipinapahiwatig na ang orihinal na kahulugan ng isang salita ay ginamit upang tumukoy sa isang partikular na konseptong may kaugnayan dito. Halimbawa, sa Latin, pumapatungkol ang salitang {{m|la|liber}} sa paglaya, ngunit nagkaroon ito ng nilipat na kahulugan para tumukoy sa mga malalayang tao (hindi alipin). Ikumpara sa ''[[#pinalawak|pinalawak]]'', na pumapatungkol naman sa kahulugan na pinalawak upang tumukoy sa ibang konseptong katulad nito. ; nominatibo, nominative, kaukulang nominatibo : ''tingnan ang '''{{lg|palagyo}}''''' ; non-literal : ''tingnan ang '''{{lg|matalinghaga}}''''' ; noun, n. : ''tingnan ang '''{{lg|pangngalan}}''''' ==O== ; obsolete, obs. : ''tingnan ang '''{{lg|lipas na}}''''' ==P== ; {{anchor|genitive|genitive case|kaukulang paari|paari}} paari, kaukulang paari : [[#kaukulan|kaukulan]] na nagpapahiwatig sa pag-aari o kaugnayan, sa Tagalog, minamarkahan ito ng ''[[ng]]'' para sa mga di-tao at ''[[ni]]'' (''[[nina]]'' kapag maramihan) para sa mga tao. ; {{anchor|pahambing|kumparatibo|komparatibo|comparative}} pahambing : [[#banghay|pagbabanghay]] sa isang pang-uri upang ipakita ang antas ng paghahambing na higit sa karaniwan ngunit hindi nasa tugatog. Sa Tagalog, ginagamit ang partikulong ''[[mas]]'' gaya ng ''mas masarap'' upang ipakita ang antas na ito. ; {{anchor|nominative|nominative case|kaukulang palagyo|palagyo}} palagyo, kaukulang palagyo : [[#kaukulan|kaukulan]] na nagpapahiwatig sa gumagawa ng kilos, sa Tagalog, minamarkahan ito ng ''[[ang]]'' para sa mga di-tao o ''[[si]]'' (''[[sina]]'' kapag maramihan) para sa mga tao. ; {{anchor|ablative|ablative case|kaukulang palayo|palayo}} palayo, kaukulang palayo : [[#kaukulan|kaukulan]] na nagpapahiwatig ng paglayo mula sa isang bagay. Para sa mga wikang meron nito, ginagamit ito nang mag-isa o may kasamang pang-ukol. Pinakamalapit na halimbawa sa Tagalog ay ang paggamit sa pang-ukol na ''[[mula]]'', kagaya ng sa ''mula Buendia''. May mga wikang tulad ng Latin na meron nito ngunit nakakuha ng maraming gamit bukod sa pagpapahiwatig ng paglayo. ; {{anchor|panahon|tense|grammatical tense}} panahon : katangian ng pandiwa na magbago depende sa oras o panahon kung kailan isinagawa ang kilos. Wag ikalito sa [[#aspekto|aspekto]], na tumutukoy sa kakumpletuhan ng kilos. Walang ganito sa Tagalog; pinakamalapit na katumbas ang paggamit sa mga salitang nagpapahiwatig ng oras gaya ng ''[[ngayon]]'', ''[[na]]'', ''[[kanina]]'', ''[[kasalukuyan]]'', at ''[[mamaya]]''. Ilan sa mga halimbawa ang [[#pangnakaraan|pangnakaraan]], [[#panghinaharap|panghinaharap]], at [[#pangkasalukuyan|pangkasalukuyan]]. ; {{anchor|person|grammatical person|panauhan}} panauhan : kategorya sa balarila na naglalarawan sa kaugnayan ng nagsasalita sa pinag-uusapan, ilan sa mga halimbawa ang [[#unang panauhan|unang panauhan]], [[#ikalawang panauhan|ikalawang panauhan]], at [[#ikatlong panauhan|ikatlong panauhan]]. ; {{anchor|pandiwa|pnd|v.|vb.|verb}} pandiwa : [[#bahagi ng pananalita|bahagi ng pananalita]] na tumutukoy sa kilos, kaganapan, o katayuan. Tinatawag na [[#pagbabanghay|pagbabanghay]] ang proseso ng pagbabago ng anyo nito ayon sa tungkulin nito sa pangungusap. ; {{anchor|pang-abay|pnb|adverb|adv.}} pang-abay : [[#bahagi ng pananalita|bahagi ng pananalita]] na naglalarawan sa pang-uri, pandiwa, o kapwa pang-abay. Sa Tagalog, umaakto ito na parang pang-uri at [[#banghay|binabanghay]] din sa kaparehong paraan, ang pagkakaiba lamang ay kung anong bahagi ng pananalita ang inilalarawan nito. Halimbawa ay ''mabilis maglakad'', kung saan ''mabilis'' ang pang-abay sa pandiwang ''maglakad''. Pansinin na magagamit din ang mga ito bilang pang-uri, gaya ng sa ''mabilis na lakad''. ; {{anchor|panghalip|pnh|pron.|pro.|pronoun}} panghalip : [[#bahagi ng pananalita|bahagi ng pananalita]] na humahalili sa isang pangngalan at tumutukoy sa paksa ng pinag-uusapan. Maaari itong humalili sa pangalan ng tao na nasa usapan gaya ng mga panghalip panao {{m|tl|ikaw}} at {{m|tl|ako}}, o tumukoy sa ibang tao ({{m|tl|siya}}) o bagay ({{m|tl|iyon}}). ; {{anchor|pang-uri|pnu|adjective|adj.}} pang-uri : [[bahagi ng pananalita]] na naglalarawan sa pangngalan o panghalip. Marami, ngunit hindi lahat, ng mga pang-uri sa Tagalog ang kinakabitan ng unlaping {{m|tl|ma-}} gaya ng ''maganda''. Halimbawa ay ''pulang mansanas'' o ''mansanas na pula'', sa parehong kaso, ''pula'' ang pang-uri. ; {{anchor|panghinaharap|hinaharap|future tense|panahong panghinaharap}} panghinaharap : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isasagawa sa hinaharap. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa hinaharap gaya ng ''[[mamaya]]'' o ''[[bukas]]''. Sa Ingles, minamarkahan ito ng mga salitang {{m|en|will}} o {{m|en|shall}}. ; pang-isahan : ''tingnan ang '''{{lg|isahan}}''''' ; {{anchor|pangkasalukuyan|kasalukuyan|panahong pangkasalukuyan|present tense}} pangkasalukuyan : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isinasagawa sa ngayon. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa kasalukuyan gaya ng ''[[ngayon]]'' o ''[[na]]''. Sa Ingles, karaniwang binabanghay ang mga pandiwa gamit ang hulaping {{m|en|-ing}} para maipahiwatig ang panahong ito. ; pangmaramihan : ''tingnan ang '''{{lg|maramihan}}''''' ; {{anchor|pangnakaraan|nakaraan|nagdaan|pangnagdaan|panahong pangnakaraan|past tense}} pangnakaraan, pangnagdaan : [[#panahon|panahon]] na nagpapahiwatig na ang kilos ay isinagawa sa nakaraan. Sa Tagalog, minamarkahan ito ng mga salitang umuukol sa nakaraan gaya ng ''[[kanina]]'' o ''[[kahapon]]''. Halimbawa ay ang salitang Ingles na {{m|en|saw}}, ang anyong pangnakaraan ng {{m|en|see}}. ; {{anchor|noun|pangngalan|n.|png}} pangngalan : [[#bahagi ng pananalita|bahagi ng pananalita]] na tumutukoy sa [[tao]], [[bagay]], [[lugar]], o [[konsepto]]. ; {{anchor|basal na pangngalan|pangngalang basal|abstract noun|abstraktong pangngalan|pangngalang abstrakto}} pangngalang basal, basal na pangangalan : [[#pangngalan|pangngalan]] na tumutukoy sa mga konsepto, kumpara sa mga [[#pangngalang tahas|pangngalang tahas]], na tumutukoy naman sa mga pisikal na bagay. ; {{anchor|tahas na pangngalan|pangngalang tahas|concrete noun|kongkretong pangngalan|pangngalang kongkreto}} pangngalang tahas, tahas na pangangalan : [[#pangngalan|pangngalan]] na tumutukoy sa mga pisikal na bagay, kumpara sa mga [[#pangngalang basal|pangngalang basal]], na tumutukoy naman sa mga konsepto. ; part of speech, POS, PoS : ''tingnan ang '''{{lg|bahagi ng pananalita}}''''' ; past tense : ''tingnan ang '''{{lg|pangnakaraan}}''''' ; {{anchor|pasukdol|superlative|superlatibo}} pasukdol : [[#banghay|pagbabanghay]] sa pang-uri upang ipakita ang antas ng paghahambing na higit sa lahat. Sa Tagalog, ikinakabit ang mga unlaping {{m|tl|pinaka-}} o {{m|tl|napaka-}} gaya ng ''pinakamasarap'' o ''napakasarap'' upang ipakita ang antas na ito. ; {{anchor|absolutive|absolutibo|kaukulang absolutibo|kaukulang patanggap|patanggap}} patanggap, kaukulang patanggap : [[#kaukulan|kaukulan]] na nagpapahiwatig sa tumatanggap o nakakaranas ng resulta ng kilos. ; {{anchor|diaresis|diaeresis|patuldok}} patuldok : [[#tuldik|tuldik]] ( ¨ ) na karaniwang inilalagay sa taas ng isang patinig. Sa mga wikang Pilipino, ginagamit lamang ito para sa titik ''e'' (''ë'') upang kumatawan sa tunog na schwa sa ilang mga wika gaya ng Maranaw (''Mëranaw''). Sa ibang mga wika, inilalagay ito sa mga patinig upang sabihin na dapat itong bigkasin nang hiwalay at hindi bilang [[diptonggo]], gaya ng {{m+|fr|naïf|t=walang muwang}}, o para sabihin na iba ang pagbigkas sa naturang patinig kumpara sa karaniwan, gaya ng sa Aleman {{m|de|über|t=ibabaw}} at {{m|de|König|t=hari}}, sa prosesong tinatawag na [[#umlaut|umlaut]]. ; perpektibo, perfective : ''tingnan ang '''{{lg|naganap}}''''' ; person : ''tingnan ang '''{{lg|panauhan}}''''' ; {{anchor|pinalawak|extended sense|by extension}} pinalawak : ipinapahiwatig na ang orihinal na kahulugan nito ay pinalawak upang tumukoy sa mas maraming konsepto na hindi kasama sa orihinal na kahulugan nito. Halimbawa, tumutukoy ang salitang {{m|tl|mabigat}} sa literal na pisikal na bigat, ngunit nagkaroon ito kalaunan ng pinalawak na kahulugan na "nakakapagod, mahirap, seryoso" gaya ng sa ''mabigat na parusa''. Ikumpara ito sa ''[[#nilipat|nilipat]]'', na tumutukoy naman sa paglipat ng kahulugan upang tumukoy sa isang partikular na konseptong may kaugnayan dito. ; plural, pl : ''tingnan ang '''{{lg|maramihan}}''''' ; pnb<!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pang-abay}}''''' ; pnd <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pandiwa}}''''' ; png <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pangngalan}}''''' ; pnh <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|panghalip}}''''' ; pnu <!-- daglat sa Diksiyonaryo.ph --> : ''tingnan ang '''{{lg|pang-uri}}''''' ; present tense : ''tingnan ang '''{{lg|pangkasalukuyan}}''''' ; pronoun, pron., pro. : ''tingnan ang '''{{lg|panghalip}}''''' ==R== ; rare : ''tingnan ang '''{{lg|bihira}}''''' ==S== ; salitang-hiram, salitang hiram : ''tingnan ang '''{{lg|hiram}}''''' ; second person, second-person : ''tingnan ang '''{{lg|ikalawang panauhan}}''''' ; singular, sing. : ''tingnan ang '''{{lg|isahan}}''''' ; superlatibo, superlative : ''tingnan ang '''{{lg|pasukdol}}''''' ==T== ; tense : ''tingnan ang '''{{lg|panahon}}''''' ; third person, third-person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ; tiyempo : ''tingnan ang '''{{lg|panahon}}''''' ; transferred, transferred sense : ''tingnan ang '''{{lg|nilipat}}''''' ; {{anchor|tuldik|diacritic|diacritical mark|diakritiko|diyakritiko|dayakritiko|accent|accent mark|aksent}} tuldik : simbolong ikinakabit o inilalagay sa isang titik upang baguhin ang tunog nito. Sa Tagalog at mga wikang Pilipino, may tatlong tuldik na ginagamit, [[#pahilis|pahilis]] ( ´ ), [[#paiwa|paiwa]] ( ` ), at [[#pakupya|pakupya]] ( ^ ), na ginagamit upang ipakita ang pagbigkas sa mga salita para maitangi ito sa mga may kaparehong baybay. Bukod dito, ginagamit din sa ilang mga wikang Pilipino ang tuldik na [[#patuldok|patuldok]], gaya ng sa Maranaw, upang isulat ang tunog na schwa. ==U== ; {{anchor|umlaut}} umlaut : pagbabago sa tunog kung saan binabago ang isang patinig upang umayon sa patinig ng kasunod nitong pantig. Ikumpara sa ''[[#ablaut|ablaut]]''. Ginagamit rin ang kataga para sa tuldik na [[#patuldok|patuldok]], upang ilarawan ang isang patinig na sumailalim sa prosesong ito. ; {{anchor|first person|first-person|1st person|unang panauhan}} unang panauhan : [[#panauhan|panauhan]] na tumutukoy sa nagsasalita o grupo ng mga nagsasalita, halimbawa sa Tagalog ang mga panghalip na ''[[ako]]'', ''[[ko]]'', at ''[[kami]]''. ==V== ; verb, v., vb. : ''tingnan ang '''{{lg|pandiwa}}''''' ==Z== ; {{anchor|zero-grade|zero grade}} zero-grade : sa Proto-Indo-Europeo, tumutukoy sa anyo ng [[#ablaut|ablaut]] ng isang ugat na hindi nagtataglay ng mga pangunahing ponemang patinig {{ic|*/e/}} at {{ic|*/o/}}. Halimbawa, {{m|ine-pro||*bʰr̥-}} ang ''zero-grade'' ng Indo-Europeong ugat {{m|ine-pro|*bʰer-|t=magbuhat, magpasan}}. 6gefna9xsw66lpiakxgeqnhazhnsl42 Module:la-nominal 828 36648 178449 171494 2026-10-27T01:11:45Z GinawaSaHapon 3989 178449 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "first", ["1&2"] = "first and second", ["2"] = "second", ["3"] = "third", ["4"] = "fourth", ["5"] = "fifth", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "adjectives", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("irregular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:Latin " .. english .. " declension|" .. english .. "-declension]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("irregular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("indeclinable") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("irregular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:Latin " .. english .. " declension|" .. english .. "-declension]]" elseif apparent_decl == "irreg" then data.title = glossary_link("irregular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("indeclinable") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. " portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " different stems" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("indeclinable") .. " portion") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "nouns") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "adjectives") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export fpkvpsbbz71142789sk9tdfg7skqffk 178451 178449 2026-10-27T01:27:55Z GinawaSaHapon 3989 178451 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "first", ["1&2"] = "first and second", ["2"] = "second", ["3"] = "third", ["4"] = "fourth", ["5"] = "fifth", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "adjectives", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("irregular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:Latin " .. english .. " declension|" .. english .. "-declension]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("irregular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("indeclinable") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("irregular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:Latin " .. english .. " declension|" .. english .. "-declension]]" elseif apparent_decl == "irreg" then data.title = glossary_link("irregular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("indeclinable") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. " portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " different stems" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("indeclinable") .. " portion") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "nouns") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export i9jkadglnhnqp9hg9qpoq20qwqgksbz 178524 178451 2026-10-27T06:55:03Z GinawaSaHapon 3989 178524 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "una", ["1&2"] = "una at ikalawa", ["2"] = "ikalawa", ["3"] = "ikatlo", ["4"] = "ikaapat", ["5"] = "ikalima", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "nouns") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export tkpdou9kmy21jiq6il3gimeix6fwsgk 178525 178524 2026-10-27T06:57:02Z GinawaSaHapon 3989 178525 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export ap0exg1rcs0dweckjqsqhrb0r734ki9 178526 178525 2026-10-27T06:58:05Z GinawaSaHapon 3989 178526 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]] na" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export roozl9k9bux77b55ajv1vtw8t19vhct 178527 178526 2026-10-27T06:58:48Z GinawaSaHapon 3989 178527 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]] na" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]] na" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export irywswjjnayqlryll7125pdi0pf13yo 178528 178527 2026-10-27T07:03:03Z GinawaSaHapon 3989 178528 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]] na") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]] na") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]] na") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]] na") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export 5eizgvanjlp25qaefqbft4ytguh6zoy 178529 178528 2026-10-27T07:03:47Z GinawaSaHapon 3989 178529 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]]" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]]") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]]") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]]") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]]") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export ap0exg1rcs0dweckjqsqhrb0r734ki9 178530 178529 2026-10-27T07:28:18Z GinawaSaHapon 3989 178530 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "unang", ["1&2"] = "una at ikalawang", ["2"] = "ikalawang", ["3"] = "ikatlong", ["4"] = "ikaapat na", ["5"] = "ikalimang", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "una", "ikalawa", "ikatlo", "ikaapat na", "ikalima" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then insert(data.categories, "Latin na " .. data.pos .. " na may pulang link sa talahanayan ng pagbabanghay") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: var(--wikt-palette-red,red)">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: var(--wikt-palette-red,red)">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, {"^(.*trīx)$", "3-def+", {"trix"}}, {"^(.*tor)$", "3-def+", {"tor"}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-def+" then -- Like 3-1+ but defective in gender return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "pang-uri", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]] na" elseif apparent_decl == "irreg+" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. " " .. data.pos end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"walang", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("di-regular")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Apendise:" .. english .. " kaukulan sa Latin|" .. english .. " kaukulan]] na" elseif apparent_decl == "irreg" then data.title = glossary_link("di-regular") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("di-mababanghay") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. " " .. singularize(data.pos) end if data.types.sufn then insert(data.subtitles, {"may", " puwedeng ''m'' → ''n'' sa mga tambalan"}) elseif data.types.not_sufn then insert(data.subtitles, {"wala", " puwedeng ''m'' → ''n'' sa mga tambalan"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ", ") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " o ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "kung hindi") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " o ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. " (na) magkaibang tangkay" ) end local subtitle_portion = concat(subtitle_portions, "; ") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("di-mababanghay") .. " na bahagi") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " may ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Apendise:Unang kaukulan sa Latin|unang kaukulan]] na") declensions_title = declensions_title:gsub("<1&2>", "[[Apendise:Unang kaukulan sa Latin|una]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na") declensions_title = declensions_title:gsub("<2>", "[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na") declensions_title = declensions_title:gsub("<3>", "[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]] na") declensions_title = declensions_title:gsub("<4>", "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat na kaukulan]] na") declensions_title = declensions_title:gsub("<5>", "[[Apendise:Ikalimang kaukulan sa Latin|ikalimang kaukulan]] na") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ", na may panlunan") end if parsed_run.num == "sg" then insert(post_text_parts, ", isahan lamang") elseif parsed_run.num == "pl" then insert(post_text_parts, ", maramihan lamang") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "." end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.n = sublist params.adj = sublist params.dim = sublist params.aug = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "comparative" or degree == "superlative" then params.positive = sublist end if degree ~= "comparative" then params.comp = sublist end if degree ~= "superlative" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "pangngalan") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "pang-uri") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export 0qlblbw2g7v7wmv98ndpuun1bsymvin Module:la-noun/data 828 37433 178531 175148 2026-10-27T08:03:56Z GinawaSaHapon 3989 178531 Scribunto text/plain local decl = {} local la_utilities_module = "Module:la-utilities" local string_char_module = "Module:string/char" local table_deep_copy_module = "Module:table/deepCopy" local table_insert_if_not_module = "Module:table/insertIfNot" local pairs = pairs local toNFD = mw.ustring.toNFD local u = require(string_char_module) local umatch = mw.ustring.match local usub = mw.ustring.sub local MACRON = u(0x304) local BREVE = u(0x306) local DIAER = u(0x308) local accent = "[" .. MACRON .. BREVE .. DIAER .. "]*" local function add_form(...) add_form = require(la_utilities_module).add_form return add_form(...) end local function deep_copy(...) deep_copy = require(table_deep_copy_module) return deep_copy(...) end local function insert_if_not(...) insert_if_not = require(table_insert_if_not_module) return insert_if_not(...) end local function glossary_link(anchor, text) text = text or anchor return "[[Apendise:Glosaryo#" .. anchor .. "|" .. text .. "]]" end local function preprocess(...) local frame = mw.getCurrentFrame() function preprocess(text) return frame:preprocess(text) end return preprocess(...) end decl["0"] = function(data, args) local forms = data.forms local stem = args[1] forms["nom_sg"] = stem forms["gen_sg"] = stem forms["dat_sg"] = stem forms["acc_sg"] = stem forms["abl_sg"] = stem forms["voc_sg"] = stem forms["nom_pl"] = stem forms["gen_pl"] = stem forms["dat_pl"] = stem forms["acc_pl"] = stem forms["abl_pl"] = stem forms["voc_pl"] = stem -- with locative if data.loc then forms["loc_sg"] = stem forms["loc_pl"] = stem end end local function alt_gen_pl_in_um(stem, forms, types, subtitles, i_stem) if types.genplum then insert_if_not(subtitles, preprocess("alternatibong paaring pangmaramihan na nagtatapos sa ''-um''")) add_form(forms, "gen_pl", stem, (i_stem and "i" or "") .. "um") elseif types.not_genplum then -- FIXME: not a contraction. insert_if_not(subtitles, "uncontracted genitive plural") end end local function dat_abl_pl_subtitle(dat_abl_loc_pl, loc) return ("dative/ablative%s plural in ''-%s''"):format(loc and "/locative" or "", dat_abl_loc_pl) end decl["1"] = function(data, args) local forms, types, loc, subtitles = data.forms, data.types, data.loc, data.subtitles local stem = args[1] -- normal 1st local nom_sg = "a" local gen_loc_sg = "ae" local dat_sg = "ae" local acc_sg = "am" local abl_sg = "ā" local voc_sg = "a" local nom_voc_pl = "ae" local gen_pl = "ārum" local dat_abl_loc_pl = "īs" local acc_pl = "ās" -- pascha if types.N then insert_if_not(subtitles, "di-tiyak") acc_sg = "a" nom_voc_pl = "a" acc_pl = "a" -- ām elseif types.am then insert_if_not(subtitles, preprocess("palagyo/pabanggit na pang-isahan na nagtatapos sa ''-ām''")) nom_sg = "ām" acc_sg = "ām" abl_sg = {"ām", "ā"} voc_sg = "ām" -- all Greek elseif types.Greek then if types.M then insert_if_not(subtitles, "panlalaki") elseif types.F then insert_if_not(subtitles, "pambabae") end insert_if_not(subtitles, "Griyegong uri") --Greek Ma if types.Ma then insert_if_not(subtitles, preprocess("palagyong pang-isahan na nagtatapos sa ''-ās''")) nom_sg = "ās" acc_sg = "ān" voc_sg = "ā" -- Greek Me elseif types.Me then insert_if_not(subtitles, preprocess("palagyong pang-isahan na nagtatapos sa ''-ēs'''")) nom_sg = "ēs" acc_sg = "ēn" abl_sg = "ē" voc_sg = "ē" -- Greek Fa elseif types.Fa then insert_if_not(subtitles, preprocess("palagyong pang-isahan na nagtatapos sa ''-ā''")) nom_sg = "ā" gen_loc_sg = "ās" acc_sg = "ān" voc_sg = "ā" -- Greek Fe else insert_if_not(subtitles, preprocess("palagyong pang-isahan na nagtatapos sa ''-ē''")) nom_sg = "ē" gen_loc_sg = "ēs" acc_sg = "ēn" abl_sg = "ē" voc_sg = "ē" end end -- ābus if types.abus then dat_abl_loc_pl = "ābus" insert_if_not(subtitles, dat_abl_pl_subtitle(dat_abl_loc_pl, loc)) elseif types.not_abus then insert_if_not(subtitles, dat_abl_pl_subtitle(dat_abl_loc_pl, loc)) end add_form(forms, "nom_sg", stem, nom_sg) add_form(forms, "gen_sg", stem, gen_loc_sg) add_form(forms, "dat_sg", stem, dat_sg) add_form(forms, "acc_sg", stem, acc_sg) add_form(forms, "abl_sg", stem, abl_sg) add_form(forms, "voc_sg", stem, voc_sg) add_form(forms, {"nom_pl", "voc_pl"}, stem, nom_voc_pl) add_form(forms, "gen_pl", stem, gen_pl) add_form(forms, {"dat_pl", "abl_pl"}, stem, dat_abl_loc_pl) add_form(forms, "acc_pl", stem, acc_pl) -- with -um genitive plural alt_gen_pl_in_um(stem, forms, types, subtitles) -- with locative if loc then add_form(forms, "loc_sg", stem, gen_loc_sg) add_form(forms, "loc_pl", stem, dat_abl_loc_pl) end end decl["2"] = function(data, args) local forms, types, subtitles, notes = data.forms, data.types, data.subtitles, data.notes local stem1, stem2 = args[1], args[2] -- normal 2nd forms["nom_sg"] = stem1 .. "us" forms["gen_sg"] = stem1 .. "ī" forms["dat_sg"] = stem1 .. "ō" forms["acc_sg"] = stem1 .. "um" forms["abl_sg"] = stem1 .. "ō" forms["voc_sg"] = stem1 .. "e" forms["nom_pl"] = stem1 .. "ī" forms["gen_pl"] = stem1 .. "ōrum" forms["dat_pl"] = stem1 .. "īs" forms["acc_pl"] = stem1 .. "ōs" forms["abl_pl"] = stem1 .. "īs" forms["voc_pl"] = stem1 .. "ī" -- all neuter if types.N then insert_if_not(subtitles, "di-tiyak") forms["nom_sg"] = stem1 .. "um" forms["voc_sg"] = stem1 .. "um" forms["nom_pl"] = stem1 .. "a" forms["acc_pl"] = stem1 .. "a" forms["voc_pl"] = stem1 .. "a" -- neuter ium if types.ium then forms["nom_sg"] = stem1 .. "ium" forms["gen_sg"] = {stem1 .. "iī", stem1 .. "ī"} forms["dat_sg"] = stem1 .. "iō" forms["acc_sg"] = stem1 .. "ium" forms["abl_sg"] = stem1 .. "iō" forms["voc_sg"] = stem1 .. "ium" forms["nom_pl"] = stem1 .. "ia" forms["gen_pl"] = stem1 .. "iōrum" forms["dat_pl"] = stem1 .. "iīs" forms["acc_pl"] = stem1 .. "ia" forms["abl_pl"] = stem1 .. "iīs" forms["voc_pl"] = stem1 .. "ia" notes["gen_sg2"] = "Makikita lamang sa lumang Latin (hanggang sa panahon ni Augustus)." -- -vom (aevom, etc.) elseif types.vom then insert_if_not(subtitles, "palagyong pang-isahan na nagtatapos sa ''-om'' pagkatapos ng ''v''") forms["nom_sg"] = stem1 .. "om" forms["acc_sg"] = stem1 .. "om" forms["voc_sg"] = stem1 .. "om" -- neuter Greek elseif types.Greek then insert_if_not(subtitles, "Griyegong uri") -- neuter Greek in -os (cētos) if types.us then insert_if_not(subtitles, "palagyo/palayon/pabanggit na nagtatapos sa ''-os''") forms["nom_sg"] = stem1 .. "os" forms["acc_sg"] = stem1 .. "os" forms["voc_sg"] = stem1 .. "os" forms["nom_pl"] = stem1 .. "ē" forms["gen_pl"] = stem1 .. "ōn" forms["acc_pl"] = stem1 .. "ē" forms["voc_pl"] = stem1 .. "ē" else forms["nom_sg"] = stem1 .. "on" forms["acc_sg"] = stem1 .. "on" forms["voc_sg"] = stem1 .. "on" end -- neuter us elseif types.us then insert_if_not(subtitles, "palagyo/palayon/pabanggit na nagtatapos sa ''-us''") forms["nom_sg"] = stem1 .. "us" forms["acc_sg"] = stem1 .. "us" forms["voc_sg"] = stem1 .. "us" forms["nom_pl"] = stem1 .. "a" forms["acc_pl"] = stem1 .. "a" forms["voc_pl"] = stem1 .. "a" elseif types.not_Greek or types.not_us then insert_if_not(subtitles, "palagyo/palayon/pabanggit na nagtatapos sa ''-um''") end -- er elseif types.er then insert_if_not(subtitles, ("palagyong pang-isahan na nagtatapos sa ''-%s''"):format(umatch(toNFD(stem1), "[eE]" .. accent .. "r$") and "er" or "r")) forms["nom_sg"] = stem1 forms["gen_sg"] = stem2 .. "ī" forms["dat_sg"] = stem2 .. "ō" forms["acc_sg"] = stem2 .. "um" forms["abl_sg"] = stem2 .. "ō" forms["voc_sg"] = stem1 forms["nom_pl"] = stem2 .. "ī" forms["gen_pl"] = stem2 .. "ōrum" forms["dat_pl"] = stem2 .. "īs" forms["acc_pl"] = stem2 .. "ōs" forms["abl_pl"] = stem2 .. "īs" forms["voc_pl"] = stem2 .. "ī" -- ius elseif types.ius then forms["nom_sg"] = stem1 .. "ius" forms["gen_sg"] = {stem1 .. "iī", stem1 .. "ī"} forms["dat_sg"] = stem1 .. "iō" forms["acc_sg"] = stem1 .. "ium" forms["abl_sg"] = stem1 .. "iō" if types.voci then -- Only for proper names and fīlius, genius forms["voc_sg"] = stem1 .. "ī" else forms["voc_sg"] = stem1 .. "ie" end forms["nom_pl"] = stem1 .. "iī" forms["gen_pl"] = stem1 .. "iōrum" forms["dat_pl"] = stem1 .. "iīs" forms["acc_pl"] = stem1 .. "iōs" forms["abl_pl"] = stem1 .. "iīs" forms["voc_pl"] = stem1 .. "iī" notes["gen_sg2"] = "Makikita lamang sa lumang Latin (hanggang sa panahon ni Augustus)." -- -vos (servos, etc.) elseif types.vos then insert_if_not(subtitles, "palagyong pang-isahan na nagtatapos sa ''-os'' pagkatapos ng ''v''") forms["nom_sg"] = stem1 .. "os" forms["acc_sg"] = stem1 .. "om" -- Greek elseif types.Greek then insert_if_not(subtitles, "Griyegong uri") forms["nom_sg"] = stem1 .. "os" forms["acc_sg"] = stem1 .. "on" if data.num == "pl" then forms["nom_pl"] = stem1 .. "oe" forms["voc_pl"] = stem1 .. "oe" else forms["nom_pl"] = {stem1 .. "ī", stem1 .. "oe"} forms["voc_pl"] = {stem1 .. "ī", stem1 .. "oe"} end elseif types.not_Greek then insert_if_not(subtitles, "di-Griyegong uri") end -- with -um genitive plural alt_gen_pl_in_um(stem2, forms, types, subtitles, types.ius or types.ium) -- with locative if data.loc then if types.ius or types.ium then forms["loc_sg"] = stem2 .. "iī" forms["loc_pl"] = stem2 .. "iīs" else forms["loc_sg"] = stem2 .. "ī" forms["loc_pl"] = stem2 .. "īs" end end end local acc_sg_i_stem_subtypes = { acc_im = { -- amussis, basis, buris, cucumis, gummis, mephitis, paraphrasis, poesis, ravis, sitis, tussis, (vis) [abl -ī]; -- cannabis, senapis, sinapis [abl -e, -ī] acc_sg = {"im"}, title = {"palayon na pang-isahan na nagtatapos sa ''-im''"}, }, acc_im_in = { -- cities, rivers, gods, e.g. Bilbilis, Syrtis, Tiberis, Anubis, Osiris [abl -ī]; -- Baetis, Tigris [acc -e, -ī] acc_sg = {"im", "in"}, title = {"palayon na pang-isahan na nagtatapos sa ''-im'' o ''-in''"}, }, acc_im_in_em = { -- e.g. tigris, river Līris acc_sg = {"im", "in", "em"}, title = {"palayon na pang-isahan na nagtatapos sa ''-im'', ''-in'' o ''-em''"}, }, acc_im_em = { acc_sg = {"im", "em"}, title = {"palayon na pang-isahan na nagtatapos sa ''-im'' o ''-em''"}, }, acc_im_occ_em = { -- febris, pelvis, puppis, restis, securis, turris [abl -ī, -e] acc_sg = {"im", "em"}, title = {"palayon na pang-isahan na nagtatapos sa ''-im'' o minsan ''-em''"}, }, acc_em_im = { -- aqualis, clavis, lens, navis [abl -e, -ī]; -- cutis, restis [abl -e] acc_sg = {"em", "im"}, title = {"palayon na pang-isahan na nagtatapos sa ''-em'' o ''-im''"}, }, } local abl_sg_i_stem_subtypes = { abl_i = { -- amussis, basis, buris, cucumis, gummis, mephitis, paraphrasis, poesis, ravis, sitis, tussis, (vis) [acc -im]; -- cities, rivers, gods, e.g. Bilbilis, Syrtis, Tiberis, Anubis, Osiris [acc -im or -in]; -- canalis "water pipe", months in -is or -er, nouns originally i-stem adjectives such as aedilis, affinis, bipennis, familiaris, sodalis, volucris, etc. [acc -em] abl_sg = {"ī"}, title = {"palayo na pang-isahan na nagtatapos sa ''-ī''"}, }, abl_i_e = { -- febris, pelvis, puppis, restis, securis, turris [acc -im, -em] abl_sg = {"ī", "e"}, title = {"palayo na pang-isahan na nagtatapos sa ''-ī'' o ''-e''"}, }, abl_i_occ_e = { -- ignis [acc -em] abl_sg = {"ī", "e"}, title = {"palayo na pang-isahan na nagtatapos sa ''-ī'' o minsan ''-e''"}, }, abl_e_i = { -- cannabis, senapis, sinapis [acc -im]; -- Baetis, Tigris [acc -im, -in]; -- aqualis, clavis, lens, navis [acc -em, -im]; -- finis, mugilis, occiput, pugil, rus, supellex, vectis [acc -em] abl_sg = {"e", "ī"}, title = {"palayo na pang-isahan na nagtatapos sa ''-e'' o ''-ī''"}, }, abl_e_occ_i = { -- amnis, anguis, avis, civis, classis, fustis, imber, orbis, pars, postis, sors, unguis, vesper [acc -em] abl_sg = {"e", "ī"}, title = {"palayo na pang-isahan na nagtatapos sa ''-e'' o minsan ''-ī''"}, }, } local function extract_stem(form, ending) local base = umatch(form, "^(.*)" .. ending .. "$") if not base then error("Form " .. form .. " should end in -" .. ending) end return base end local function count_vowels(stem) return select(2, toNFD(stem):gsub("[aeiouyAEIOUY]", "")) end decl["3"] = function(data, args) local forms, types, subtitles, notes = data.forms, data.types, data.subtitles, data.notes local stem1, stem2 = args[1], args[2] local function non_i_stem_type() return (count_vowels(stem1) > count_vowels(stem2) and "parisilabikong" or "di-parisilabikong") .. " tangkay na hindi ''i''" end --normal 3rd forms["nom_sg"] = stem1 forms["gen_sg"] = stem2 .. "is" forms["dat_sg"] = stem2 .. "ī" forms["acc_sg"] = stem2 .. "em" forms["abl_sg"] = stem2 .. "e" forms["voc_sg"] = stem1 forms["nom_pl"] = stem2 .. "ēs" forms["gen_pl"] = stem2 .. "um" forms["dat_pl"] = stem2 .. "ibus" forms["acc_pl"] = stem2 .. "ēs" forms["abl_pl"] = stem2 .. "ibus" forms["voc_pl"] = stem2 .. "ēs" local acc_sg_i_stem_subtype = false local not_acc_sg_i_stem_subtype = false for subtype, _ in pairs(types) do if acc_sg_i_stem_subtypes[subtype] then acc_sg_i_stem_subtype = true break end end for acc_sg_subtype, _ in pairs(acc_sg_i_stem_subtypes) do if types["not_" .. acc_sg_subtype] then not_acc_sg_i_stem_subtype = true break end end local abl_sg_i_stem_subtype = false local not_abl_sg_i_stem_subtype = false for subtype, _ in pairs(types) do if abl_sg_i_stem_subtypes[subtype] then abl_sg_i_stem_subtype = true break end end for abl_sg_subtype, _ in pairs(abl_sg_i_stem_subtypes) do if types["not_" .. abl_sg_subtype] then not_abl_sg_i_stem_subtype = true break end end -- all Greek if types.Greek then insert_if_not(subtitles, "Griyegong uri") -- Greek er if types.er then insert_if_not(subtitles, "barayti na may palagyong pang-isahan na nagtatapos sa ''-ēr''") stem1 = extract_stem(stem1, "ēr") forms["nom_sg"] = stem1 .. "ēr" forms["gen_sg"] = stem1 .. "eris" forms["dat_sg"] = stem1 .. "erī" forms["acc_sg"] = {stem1 .. "era", stem1 .. "erem"} forms["abl_sg"] = stem1 .. "ere" forms["voc_sg"] = stem1 .. "ēr" forms["nom_pl"] = stem1 .. "erēs" forms["gen_pl"] = stem1 .. "erum" forms["dat_pl"] = stem1 .. "eribus" forms["acc_pl"] = stem1 .. "erēs" forms["abl_pl"] = stem1 .. "eribus" forms["voc_pl"] = stem1 .. "erēs" -- Greek on elseif types.on then insert_if_not(subtitles, "barayti na may palagyong pang-isahan na nagtatapos sa ''-ōn''") stem1 = extract_stem(stem1, "ōn") forms["nom_sg"] = stem1 .. "ōn" forms["gen_sg"] = {stem1 .. "ontis", stem1 .. "ontos"} forms["dat_sg"] = stem1 .. "ontī" forms["acc_sg"] = stem1 .. "onta" forms["abl_sg"] = stem1 .. "onte" forms["voc_sg"] = stem1 .. "ōn" forms["nom_pl"] = stem1 .. "ontēs" forms["gen_pl"] = {stem1 .. "ontum", stem1 .. "ontium"} forms["dat_pl"] = stem1 .. "ontibus" forms["acc_pl"] = {stem1 .. "ontēs", stem1 .. "ontās"} forms["abl_pl"] = stem1 .. "ontibus" forms["voc_pl"] = stem1 .. "ontēs" -- Greek i-stem elseif types.I then insert_if_not(subtitles, "i-stem") forms["gen_sg"] = {stem2 .. "is", stem2 .. "eōs", stem2 .. "ios"} forms["acc_sg"] = {stem2 .. "im", stem2 .. "in", stem2 .. "em"} forms["abl_sg"] = {stem2 .. "ī", stem2 .. "e"} forms["voc_sg"] = {stem2 .. "is", stem2 .. "i"} notes["acc_sg3"] = "Makikita minsan sa Medyebal at Bagong Latin." notes["abl_sg2"] = "Makikita minsan sa Medyebal at Bagong Latin." forms["nom_pl"] = {stem2 .. "ēs", stem2 .. "eis"} forms["gen_pl"] = {stem2 .. "ium", stem2 .. "eōn"} forms["acc_pl"] = {stem2 .. "ēs", stem2 .. "eis"} forms["voc_pl"] = {stem2 .. "ēs", stem2 .. "eis"} if types.poetic_esi then forms["dat_pl"] = {stem2 .. "ibus", stem2 .. "esi"} forms["abl_pl"] = {stem2 .. "ibus", stem2 .. "esi"} notes["dat_pl2"] = "Madalas sa panulaan." notes["abl_pl2"] = "Madalas sa panulaan." end -- normal Greek else insert_if_not(subtitles, "karaniwang barayti") forms["gen_sg"] = stem2 .. "os" if umatch(toNFD(stem2), "[yY]" .. accent .. "$") then forms["acc_sg"] = stem2 .. "n" else forms["acc_sg"] = stem2 .. "a" end forms["nom_pl"] = stem2 .. "es" forms["acc_pl"] = stem2 .. "as" forms["voc_pl"] = stem2 .. "es" if umatch(toNFD(stem1), "[iyIY]" .. accent .. "s$") then -- Per Hiley, words in -is and -ys have a poetic vocative -- without the -s, but otherwise the vocative is the same -- as the nominative. forms["voc_sg"] = {stem1, (stem1:gsub("s$", ""))} notes["voc_sg2"] = "Sa panulaan." end end elseif types.not_Greek then insert_if_not(subtitles, "di-Griyegong uri") end -- polis if types.polis then stem1 = extract_stem(stem1, "polis") insert_if_not(subtitles, "tangkay na i") insert_if_not(subtitles, "bahagyang Griyegong uri") forms["nom_sg"] = stem1 .. "polis" forms["gen_sg"] = stem1 .. "polis" forms["dat_sg"] = stem1 .. "polī" forms["acc_sg"] = {stem1 .. "polim", stem1 .. "polin"} forms["abl_sg"] = stem1 .. "polī" forms["voc_sg"] = {stem1 .. "polis", stem1 .. "polī"} elseif types.not_polis then insert_if_not(subtitles, non_i_stem_type()) end -- all neuter if types.N then insert_if_not(subtitles, "di-tiyak") forms["acc_sg"] = stem1 -- neuter I stem if types.I then -- pure variety if types.pure then insert_if_not(subtitles, "purong tangkay na i") forms["abl_sg"] = stem2 .. "ī" forms["nom_pl"] = stem2 .. "ia" forms["gen_pl"] = stem2 .. "ium" forms["acc_pl"] = stem2 .. "ia" forms["voc_pl"] = stem2 .. "ia" -- non-pure variety (rare) else insert_if_not(subtitles, "tangkay na i") forms["nom_pl"] = stem2 .. "a" forms["gen_pl"] = {stem2 .. "ium", stem2 .. "um"} forms["acc_pl"] = stem2 .. "a" forms["voc_pl"] = stem2 .. "a" end -- normal neuter else insert_if_not(subtitles, non_i_stem_type()) forms["nom_pl"] = stem2 .. "a" forms["acc_pl"] = stem2 .. "a" forms["voc_pl"] = stem2 .. "a" end -- I stem elseif types.I or acc_sg_i_stem_subtype or abl_sg_i_stem_subtype then insert_if_not(subtitles, (types.not_N and "hindi di-tiyak na " or "") .. (types.pure and "purong " or "") .. "tangkay na i") forms["gen_pl"] = stem2 .. "ium" -- Per Allen and Greenough, Hiley and others, the acc_pl in -īs -- applied originally to all i-stem nouns, and was current as an -- alternative form up through Caesar. forms["acc_pl"] = {stem2 .. "ēs", stem2 .. "īs"} -- pure variety if types.pure then forms["acc_sg"] = stem2 .. "im" forms["abl_sg"] = stem2 .. "ī" forms["nom_pl"] = stem2 .. "īs" forms["acc_pl"] = stem2 .. "īs" forms["voc_pl"] = stem2 .. "īs" end local num = data.num for subtype, _ in pairs(types) do local acc_sg_i_stem_props = acc_sg_i_stem_subtypes[subtype] if acc_sg_i_stem_props then forms["acc_sg"] = {} for _, ending in ipairs(acc_sg_i_stem_props.acc_sg) do insert_if_not(forms["acc_sg"], stem2 .. ending) end if num ~= "pl" then for _, t in ipairs(acc_sg_i_stem_props.title) do insert_if_not(subtitles, t) end end break end end -- FIXME: needs to be done for neuter nouns as well. for subtype, _ in pairs(types) do local abl_sg_i_stem_props = abl_sg_i_stem_subtypes[subtype] if abl_sg_i_stem_props then forms["abl_sg"] = {} for _, ending in ipairs(abl_sg_i_stem_props.abl_sg) do insert_if_not(forms["abl_sg"], stem2 .. ending) end if num ~= "pl" then for _, t in ipairs(abl_sg_i_stem_props.title) do insert_if_not(subtitles, t) end end break end end elseif types.not_N and types.not_I then insert_if_not(subtitles, "hindi di-tiyak na " .. non_i_stem_type()) elseif types.not_N then insert_if_not(subtitles, "hindi di-tiyak") elseif types.not_I then insert_if_not(subtitles, non_i_stem_type()) end -- with locative if data.loc then -- As far as I can tell, in general both dative singular and -- ablative singular could be used for the third-declension locative, -- with different time periods preferring different forms. -- http://dcc.dickinson.edu/grammar/latin/3rd-declension-locative-case -- mentions rūrī along with either Carthāginī or Carthāgine. -- Wikipedia in https://en.wikipedia.org/wiki/Locative_case#Latin -- says this: -- -- In archaic times, the locative singular of third declension nouns -- was still interchangeable between ablative and dative forms, but in -- the Augustan Period the use of the ablative form became fixed. -- Therefore, both forms "rūrī" and "rūre" may be encountered. -- -- Lewis and Short confirm this. local loc_sg = forms["dat_sg"] if type(loc_sg) == "table" then loc_sg = deep_copy(loc_sg) else loc_sg = {loc_sg} end local abl_sg = forms["abl_sg"] if type(abl_sg) == "table" then for _, form in ipairs(abl_sg) do insert_if_not(loc_sg, deep_copy(form)) end else insert_if_not(loc_sg, abl_sg) end forms["loc_sg"] = loc_sg forms["loc_pl"] = deep_copy(forms["abl_pl"]) --The following is what we used to have, but I simply cannot believe it. --if types.Greek and not types.s then -- forms["loc_pl"] = stem2 .. "ēs" --end end end decl["4"] = function(data, args) local forms, types, subtitles, notes = data.forms, data.types, data.subtitles, data.notes local stem = args[1] -- normal 4th forms["nom_sg"] = stem .. "us" forms["gen_sg"] = stem .. "ūs" forms["dat_sg"] = stem .. "uī" forms["acc_sg"] = stem .. "um" forms["abl_sg"] = stem .. "ū" forms["voc_sg"] = stem .. "us" forms["nom_pl"] = stem .. "ūs" forms["gen_pl"] = stem .. "uum" forms["dat_pl"] = stem .. "ibus" forms["acc_pl"] = stem .. "ūs" forms["abl_pl"] = stem .. "ibus" forms["voc_pl"] = stem .. "ūs" if types.echo then insert_if_not(subtitles, "lahat ng kaukulan maliban sa paari at palayon na pang-isahan na nagtatapos sa ''-ō''") for slot in pairs(forms) do if slot ~= "gen_sg" then forms[slot] = stem .. "ō" end end add_form(forms, "acc_sg", stem, "ōn") elseif types.Callisto then insert_if_not(subtitles, "lahat ng kaukulan maliban sa paari na pang-isahan na nagtatapos sa ''-ō''") for slot in pairs(forms) do if slot ~= "gen_sg" then forms[slot] = stem .. "ō" end end end -- neuter if types.N then insert_if_not(subtitles, "di-tiyak") forms["nom_sg"] = stem .. "ū̆" forms["gen_sg"] = {stem .. "ūs", stem .. "ū"} forms["dat_sg"] = {stem .. "ū", stem .. "uī"} forms["acc_sg"] = stem .. "ū̆" forms["voc_sg"] = stem .. "ū̆" forms["nom_pl"] = stem .. "ua" forms["acc_pl"] = stem .. "ua" forms["voc_pl"] = stem .. "ua" local note1 = "Hindi sigurado ang haba ng pinakahuling patinig sa palagyo/palayon/pabanggit na pang-isahan; ayon kay [[w:Martianus Capella|Martianus Capella]], nagtatapos ito sa ''-ū'', habang ayon naman kay [[w:Servius the Grammarian|Servius]], nagtatapos ito sa ''-ŭ''." local note2 = "Ayon kay [[w:Martianus Capella|Martianus Capella]]." local note3 = "Ayon kay [[w:Servius the Grammarian|Servius]]." local note4 = "Ayon sa kanila." notes["nom_sg1"] = note1 notes["gen_sg1"] = note2 notes["gen_sg2"] = note3 notes["dat_sg1"] = note4 notes["dat_sg2"] = note2 notes["acc_sg1"] = note1 notes["voc_sg1"] = note1 end -- ubus if types.ubus then insert_if_not(subtitles, "patanggap/palayo na pangmaramihan na nagtatapos sa ''-ubus''") forms["dat_pl"] = stem .. "ubus" forms["abl_pl"] = stem .. "ubus" elseif types.not_ubus then insert_if_not(subtitles, "patanggap/palayo na pangmaramihan na nagtatapos sa ''-ibus''") end -- with locative if data.loc then forms["loc_sg"] = forms["abl_sg"] forms["loc_pl"] = forms["abl_pl"] end end decl["5"] = function(data, args) local forms, types = data.forms, data.types local stem = args[1] -- ies if types.i then stem = stem .. "i" end forms["nom_sg"] = stem .. "ēs" forms["gen_sg"] = stem .. "eī" forms["dat_sg"] = stem .. "eī" forms["acc_sg"] = stem .. "em" forms["abl_sg"] = stem .. "ē" forms["voc_sg"] = stem .. "ēs" forms["nom_pl"] = stem .. "ēs" forms["gen_pl"] = stem .. "ērum" forms["dat_pl"] = stem .. "ēbus" forms["acc_pl"] = stem .. "ēs" forms["abl_pl"] = stem .. "ēbus" forms["voc_pl"] = stem .. "ēs" -- ies if types.i then forms["gen_sg"] = stem .. "ēī" forms["dat_sg"] = stem .. "ēī" end --with locative if data.loc then forms["loc_sg"] = stem .. "ē" forms["loc_pl"] = stem .. "ēbus" end end decl["sgpl"] = function(data, args) local forms = data.forms local stem1, stem2 = args[1], args[2] insert_if_not(data.subtitles, "may hiwalay na pangmaramihan") forms["nom_sg"] = stem1 forms["gen_sg"] = stem1 forms["dat_sg"] = stem1 forms["acc_sg"] = stem1 forms["abl_sg"] = stem1 forms["voc_sg"] = stem1 forms["nom_pl"] = stem2 forms["gen_pl"] = stem2 forms["dat_pl"] = stem2 forms["acc_pl"] = stem2 forms["abl_pl"] = stem2 forms["voc_pl"] = stem2 -- with locative if data.loc then forms["loc_sg"] = stem1 forms["loc_pl"] = stem2 end end decl["indecl"] = function(data, args) local forms = data.forms local stem = args[1] insert_if_not(data.subtitles, "ginagamit lamang sa palagyo at palayon") forms["nom_sg"] = stem forms["gen_sg"] = "-" forms["dat_sg"] = "-" forms["acc_sg"] = stem forms["abl_sg"] = "-" forms["voc_sg"] = "-" forms["nom_pl"] = "-" forms["gen_pl"] = "-" forms["dat_pl"] = "-" forms["acc_pl"] = "-" forms["abl_pl"] = "-" forms["voc_pl"] = "-" -- with locative (for multiword terms) if data.loc then forms["loc_sg"] = "-" forms["loc_pl"] = "-" end data.num = "sg" end decl["irreg"] = function(data, args) local forms, subtitles, notes = data.forms, data.subtitles, data.notes local stem = args[1] forms["nom_sg"] = "-" forms["gen_sg"] = "-" forms["dat_sg"] = "-" forms["acc_sg"] = "-" forms["abl_sg"] = "-" forms["voc_sg"] = "-" forms["nom_pl"] = "-" forms["gen_pl"] = "-" forms["dat_pl"] = "-" forms["acc_pl"] = "-" forms["abl_pl"] = "-" forms["voc_pl"] = "-" if stem == "bōs" then data.decl = "3" local stem1, stem2 = "bōs", "bov" decl["3"](data, {stem1, stem2}) add_form(forms, "abl_sg", stem2, "īd") notes["abl_sg" .. #forms["abl_sg"]] = "Lumang Latin." add_form(forms, "gen_pl", "bo", "um", 1) add_form(forms, "gen_pl", stem2, "erum") add_form(forms, "dat_pl", "", "bōbus", 1) add_form(forms, "dat_pl", "", "būbus", 2) add_form(forms, "abl_pl", "", "bōbus", 1) add_form(forms, "abl_pl", "", "būbus", 2) elseif stem:match("^[dD]eus$") then data.decl = "2" local dD = stem:sub(1, 1) forms["nom_sg"] = dD .. "eus" forms["gen_sg"] = dD .. "eī" forms["dat_sg"] = dD .. "eō" forms["acc_sg"] = dD .. "eum" forms["abl_sg"] = dD .. "eō" forms["voc_sg"] = {dD .. "eus", dD .. "ee"} notes["voc_sg1"] = "Bihira noong Klasikong panahon." notes["voc_sg2"] = "Magmula noong Huling Latin." if stem == "deus" then forms["nom_pl"] = {"dī", "diī", "deī"} forms["gen_pl"] = {"deōrum", "deum"} forms["dat_pl"] = {"dīs", "diīs", "deīs"} forms["acc_pl"] = "deōs" forms["abl_pl"] = {"dīs", "diīs", "deīs"} forms["voc_pl"] = {"dī", "diī", "deī"} end elseif stem == "domus" then data.decl = "4,2" data.title = "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na pangngalan" forms["nom_sg"] = "domus" forms["gen_sg"] = {"domūs", "domī"} forms["dat_sg"] = {"domuī", "domō", "domū"} forms["acc_sg"] = "domum" forms["abl_sg"] = {"domū", "domō"} forms["voc_sg"] = "domus" forms["loc_sg"] = "domī" forms["nom_pl"] = "domūs" forms["gen_pl"] = {"domuum", "domōrum"} forms["dat_pl"] = "domibus" forms["acc_pl"] = {"domūs", "domōs"} forms["abl_pl"] = "domibus" forms["voc_pl"] = "domūs" forms["loc_pl"] = "-" data.loc = true elseif umatch(stem, "^[IÏJ]ēs[uū]" .. BREVE .. "?s$") then local ij = usub(stem, 1, 1) local uu = umatch(stem, "[uū]" .. BREVE .. "?") forms["nom_sg"] = stem forms["gen_sg"] = ij .. "ēsū" forms["dat_sg"] = ij .. "ēsū" forms["acc_sg"] = ij .. "ēs" .. uu .. "m" forms["abl_sg"] = ij .. "ēsū" forms["voc_sg"] = ij .. "ēsū" data.num = "sg" elseif stem == "Mōsēs" or stem == "Moesēs" or umatch(stem, "^M[oō]" .. BREVE .. "?[īȳ]sēs$") then local mos = usub(stem, 1, -3) forms["nom_sg"] = stem forms["gen_sg"] = {mos .. "ī", mos .. "ēī", mos .. "is", mos .. "ēn", mos .. "eōs"} forms["dat_sg"] = mos .. "ī" forms["acc_sg"] = {mos .. "ēn", mos .. "em"} forms["abl_sg"] = {mos .. "e", mos .. "ēn", mos .. "ī"} forms["voc_sg"] = {mos .. "ēs", mos .. "ē"} data.num = "sg" elseif stem:match("^[ij]ūgerum$") then data.decl = "2,3" local ij = stem:sub(1, 1) data.title = "[[Apendise:Ikalawang kaukulan sa Latin|ikalawa]]–[[Apendise:Ikatlong kaukulan sa Latin|ikatlong kaukulan]] na pangngalang pinaghalo" insert_if_not(subtitles, "di-tiyak") forms["nom_sg"] = ij .. "ūgerum" forms["gen_sg"] = ij .. "ūgerī" forms["dat_sg"] = ij .. "ūgerō" forms["acc_sg"] = ij .. "ūgerum" forms["abl_sg"] = ij .. "ūgerō" forms["voc_sg"] = ij .. "ūgerum" forms["nom_pl"] = ij .. "ūgera" forms["gen_pl"] = ij .. "ūgerum" forms["dat_pl"] = ij .. "ūgeribus" forms["acc_pl"] = ij .. "ūgera" forms["abl_pl"] = {ij .. "ūgeribus", ij .. "ūgerīs"} forms["voc_pl"] = ij .. "ūgera" notes["abl_pl2"] = "Isang beses lamang, sa:<br/>M. Terentius Varro, ''Res Rusticae'', bk I, ch. x" elseif stem == "sūs" then data.decl = "3" forms["nom_sg"] = "sūs" forms["gen_sg"] = "suis" forms["dat_sg"] = "suī" forms["acc_sg"] = "suem" forms["abl_sg"] = "sue" forms["voc_sg"] = "sūs" forms["nom_pl"] = "suēs" forms["gen_pl"] = "suum" forms["dat_pl"] = {"suibus", "sūbus", "subus"} forms["acc_pl"] = "suēs" forms["abl_pl"] = {"suibus", "sūbus", "subus"} forms["voc_pl"] = "suēs" elseif stem == "ēthos" then data.decl = "3" insert_if_not(subtitles, glossary_link("di-regular")) insert_if_not(subtitles, "Griyegong uri") forms["nom_sg"] = "ēthos" forms["gen_sg"] = "ētheos" forms["acc_sg"] = "ēthos" forms["voc_sg"] = "ēthos" forms["nom_pl"] = {"ēthea", "ēthē"} forms["dat_pl"] = {"ēthesi", "ēthesin"} forms["acc_pl"] = {"ēthea", "ēthē"} forms["abl_pl"] = {"ēthesi", "ēthesin"} forms["voc_pl"] = {"ēthea", "ēthē"} elseif stem == "Athōs" then data.decl = "2" insert_if_not(subtitles, "sobrang " .. glossary_link("di-regular")) insert_if_not(subtitles, "Griyegong uri") forms["nom_sg"] = "Athōs" forms["gen_sg"] = "Athō" forms["dat_sg"] = "Athō" forms["acc_sg"] = {"Athō", "Athōn"} forms["abl_sg"] = "Athō" forms["voc_sg"] = "Athōs" data.num = "sg" elseif stem:match("^[uv]ēnum$") then data.decl = "4,2" local uv = stem:sub(1, 1) data.title = "[[Apendise:Ikaapat na kaukulan sa Latin|ikaapat]]/[[Apendise:Ikalawang kaukulan sa Latin|ikalawang kaukulan]] na pangngalan" insert_if_not(subtitles, glossary_link("depektibo")) forms["dat_sg"] = {uv .. "ēnuī", uv .. "ēnō"} forms["acc_sg"] = uv .. "ēnum" data.num = "sg" elseif stem:match("^[uv]īs$") then data.decl = "3" local uv = stem:sub(1, 1) insert_if_not(subtitles, glossary_link("di-regular")) insert_if_not(subtitles, glossary_link("depektibo")) forms["nom_sg"] = uv .. "īs" forms["gen_sg"] = uv .. "īs" forms["dat_sg"] = uv .. "ī" forms["acc_sg"] = uv .. "im" forms["abl_sg"] = uv .. "ī" forms["voc_sg"] = uv .. "īs" forms["nom_pl"] = uv .. "īrēs" forms["gen_pl"] = uv .. "īrium" forms["dat_pl"] = uv .. "īribus" forms["acc_pl"] = {uv .. "īrēs", uv .. "īrīs"} forms["abl_pl"] = uv .. "īribus" forms["voc_pl"] = uv .. "īrēs" else error("Stem " .. stem .. " not recognized.") end end return decl -- For Vim, so we get 4-space tabs -- vim: set ts=4 sw=4 noet: jk5qslho5pk6b5p89o0kegbiy63ce4l liber 0 38956 178452 178435 2026-10-27T01:30:52Z GinawaSaHapon 3989 /* Pang-uri */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]) 178452 wikitext text/x-wiki =={{=la=}}== ===Etimolohiya 1=== {{ety|la|title=līber|id=free|:inh|itc-ola:loeber<ety:inh<itc-pro:*louðeros>>|text=++|tree=1}}<ref name=EDL1>{{R:itc:EDL|page=338|head=līber}}</ref> Kapatid ng {{cog|grc|ἐλεύθερος}}, {{cog|sa|रोधति|tr=ródhati}}, {{cog|nl|lieden}}, {{cog|de|Leute}}, at {{cog|ru|лю́ди|t=sambayanan}}. ====Pagbigkas==== * {{la-IPA|līber}} ====Pang-uri==== {{la-adj|līber|comp=līberior|sup=līberrimus|adv=līberē}} # {{senseid|la|malaya}} [[malaya]]; [[magsarili|nagsasarili]]; walang [[higpit|paghihigpit]]; hindi [[magbantay|binabantayan]] #: {{syn|la|solūtus|expers|immūnis}} #* {{Q|la|{{w|Seneca the Younger|Lucius Anneus Seneca Minor}}|{{w|Epistulae Morales ad Lucilium|Epistulae Morales ad Lucilium}}|Epistula XCII|year=65 AD|quote=''Nēmō '''līber''' est quī corporī servit.''|trans=Walang sinumang '''malaya''' na alipin ng sariling katawan.}} # {{lb|la|transferred}} malayang tao #* {{Q|la|Pl.|Cap.|3|4|94|thru=95|quote=Haud istūc rogō. Fuistin '''līber'''? — Fuī.|trans=Hindi yon ang tinatanong ko. '''Malayang tao''' ka ba? – Noon.}} #* {{Q|la|Publius Terentius Afer|Andria|769|thru=771|quote=DĀVUS: Vērum! Vīdī Cantharam / suffarcinātam! MȲSĪS: Dīs Pol habeō grātiam / quom in pariundō aliquot adfuērunt '''līberae'''!|trans=DAVUS: Totoo! Nakita ko si Canthara na binibigkis [yung sanggol]!<br/>MYSIS (sarkastiko): Sa ngalan ni Pollux, aking pinasasalamatan ang kalangitan sa mga '''malalayang babae''' na nandito sa panganganak!<br/>(Ipinapahiwatig ng tanging pagbanggit lamang kay Canthara rito na maaaring mas mapagkakatiwalaan siya bilang saksi kesa sa alipin na si Mysis.)}} # {{q|ukol sa isang kaso}} hindi pa [[tapos]]; [[bukás]] pa # {{q|ukol sa mga abogado}} walang [[kumiling|kinikilingan]] # hindi [[kabilang]] {{q|sa gastos o katulad}}; walang [[epekto]] =====Kaukulan===== {{la-adecl|līber}} * Minsan {{l|la|līberum}} ang kaukulang paaring pangmaramihan =====Hinangong kataga===== {{col4|la |līberālis |līberālitās |līberāliter |līberātiō |līberātor |līberē |līberī |līberō |līberta |lībertās |lībertīnus |lībertus }} =====Anak na kataga===== {{top3}} * {{desc|rup|libir}} * {{desc|sq|lirë|bor=1}} (pinagtatalunan) * {{desc|ca|lliure}} * {{desc|co|liberu|libaru}} * {{desc|egl|lébber|lèbber}} * {{desc|ist|leîbaro}} * {{desctree|it|libero|bor=1}} * {{desc|lij|libero}} * {{desc|lmo|liber|libar}} * {{desc|an|libre}} * {{desc|roa-ole}} ** {{desc|ast|llibre|chibre}} ** {{desc|ext|libri}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|libre|lhibre}} * {{desc|oc|liure}} * {{desc|roa-opt|livre|libre}} ** {{desc|fax|libri}} ** {{desc|gl|libre}} ** {{desctree|pt|livre}} * {{desctree|es|libre}} * {{desc|pms|lìber}} * {{desc|fur|libar}} * {{desc|rgn|lébar}} * {{desc|sc|líbberu|líveru}} * {{desc|scn|lìviru|lìbbiru|q1=laos na}} * {{desc|vec|łìbaro}} * {{desc|fro|libre|slb=1}} ** {{desctree|fr|libre}} ** {{desc|nrf|libe}} ** {{desc|wa|lîb}} {{bottom}} ====Pangngalan==== {{la-noun|līber<2>}} # {{lb|la|post-Republican}} {{singular of|la|līberī}}: [[anak]] na [[lalaki]]; anak {{q|ng isang magulang na}} #: {{syn|la|fīlius|nātus}} #* {{Q|la|Quintilian|Declamations|2|8|2|quote=Quanto alios praestat affectus diligere vitae, lucis auctorem! '''Liberi''' ac parentis non alius mihi videtur affectus quam quo rerum natura, quo mundus ipse constrictus est.|trans=May mas hihigit pa bang damdamin kesa sa pagmamahal sa gumawa ng buhay at liwanag? Tila walang pagkakaiba sa akin ang pagmamahal sa pagitan ng '''anak''' at magulang sa pagmamahal sa pagbubuklod ng kalikasan at ng mismong mundo.}} =====Paalala sa paggamit===== Hanggang sa panahon ng Republika, ginagamit lamang ang salitang ito sa anyong pangmaramihan nito (''plurale tantum''). Kahit sa pagsapit ng panahon ng Imperyo, napakabihirang gamitin ang anyong pang-isahan nito; tanging makikita lamang ito sa {{w|Kodigo ni Justiniano}}. =====Kaukulan===== {{la-ndecl|līber<2>}} ====Sanggunian==== {{reflist}} ===Etimolohiya 2=== {{etymon|la|id=balat|:inh|itc-pro:*luβros|tree=1}} {{inh+|la|itc-pro|*luβros}}, mula sa {{inh|la|ine-pro||*lubʰ-ró-s}}, mula sa {{m|ine-pro|*lewbʰ-||balatan, tanggalin (mula sa katawan), saktan|id=balatan}},<ref name=EDL2>{{R:itc:EDL|pages=337-8|head=liber, -brī}}</ref> posible mula sa {{m|ine-pro|*lew-||tanggalin (mula sa katawan)}}.<ref>{{R:ine:IEW|page=690}}</ref> May kaugnayan sa {{cog|cu|лꙋбъ||balat ng puno}}, {{cog|ru|луб||loobang balat ng puno}}, {{cog|lt|lùpti||balatan}}.<ref>{{R:Nocentini|hw=libro}}</ref> Tingnan din ang {{cog|en|leaf||dahon}}, {{m|en|lobby||pahingaan}}, {{m|en|lodge||panuluyan}}, at {{cog|grc|λυπή||sakit (masaktan)}}. ====Alternatibong pagbaybay==== * {{l|la|lib.}}, {{l|la|l.}} ====Pagbigkas==== * {{la-IPA|liber}} ====Pangngalan==== {{la-noun|liber/libr<2>}} # {{senseid|la|aklat}} [[aklat]] #* {{Q|la|Ovid|Tristia|1|1|thru=2|quote=Parvē — nec invideō — sine mē, '''liber''', ībis in urbem,<br/>eī mihi, quod dominō nōn licet īre tuō!|trans=Aking munting '''aklat''' – hindi ako naiingit [sa'yo] – kung wala ako, mapapadpad ka sa lungsod: Mula sa akin, dahil bawal lisanin ka ng iyong may-ari!<br/>(Tinutukoy ng pinaalis na makata ang aklat niya na para bang maninilbi niya ito na pinadala niya sa Roma.)}} #* {{Q|la|Seneca the Younger|Epistulae Morales ad Lucilium|1|2|3|quote=Distringit '''librōrum''' multitūdō; itaque cum legere nōn possīs quantum habuerīs, satis est habēre quantum lēgās.|trans=Naliligaw lamang ang isip [ng mambabasa] sa dami ng mga '''aklat'''; kaya, dahil hindi ka naman nakakabasa nang singdami ng meron ka, sapat na ang magmay-ari ka [ng mga aklat] ng kaya mo lamang basahin.}} # {{senseid|la|balat ng puno}} [[looban|loobang]] [[balat]] ng [[puno]] =====Kaukulan===== {{la-ndecl|liber/libr<2>}} =====Hinangong kataga===== * {{l|la|libellus}} * {{l|la|librārius}} * {{l|la|librārium}} =====Anak na kataga===== * {{desc|frp|lévro}} {{q|walang dudang anak mismo nito}} ; Mga bahagyang aral na hiram {{top3}} * {{desc|an|libro}} * {{desc|sq|libër|bor=1}} * {{desc|eu|liburu|bor=1}} * {{desc|co|libru}} * {{desc|dlm|lebro}} * {{desc|egl|lîber}} * {{desc|bor=1|en|liber|libro-}} * {{desc|fr|liber|libro-}} * {{desc|fur|libri}} * {{desc|io|libro|bor=1}} * {{desc|ist|leîbro}} * {{desc|it|libro}} * {{desc|lld|liber}} * {{desc|lij|libbro}} * {{desc|lmo|libar|liber|libru}} * {{desc|nap|libro|libbro}} * {{desc|fro|livre|slb=1}} ** {{desctree|fr|livre}} ** {{desc|nrf|livre}} * {{desc|roa-ole|}} ** {{desc|ast|llibru}} ** {{desc|ext|libru}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|lhibro|libro}} * {{desc|roa-opt|livro|libro}} ** {{desc|fax|libru}} ** {{desc|gl|libro}} ** {{desc|pt|livro}} *** {{desc|pov|libru|bor=1}} * {{desc|pro|libre}} ** {{desc|ca|llibre}} ** {{desc|oc|libre}} * {{desc|osp|libro}} ** {{desctree|es|libro}} * {{desc|pms|lìber}} * {{desc|rgn|lìbar}} * {{desc|sc|líbbaru|líbberu|libbru|líbburu}} * {{desc|scn|libbru}} * {{desc|vec|łìbro}} * {{desc|wa|lîv|live}} * {{desc|cel-bry-pro|*llɨβr|bor=1}} {{see desc}} * {{desc|sga|lebor|bor=1}} {{see desc}} {{bottom}} ====Sanggunian==== {{reflist}} ===Etimolohiya 3=== ====Pagbigkas==== * {{la-IPA|līber}} ====Pandiwa==== {{head|la|verb form|head=līber}} # {{inflection of|la|lībō||1|s|pres|pasv|subj}} ===Magbasa pa=== * {{R:la:L&S|līber, ''adj.''|liber1}} * {{R:la:L&S|līber, ''n.''|liber4}} * {{R:la:Elementary Lewis}} * {{R:la:Gaffiot}} * {{R:la:M&A}} * {{R:la:Peck}} * {{R:la:Platner}} * {{R:Smith's Persons}} * {{R:Smith's Antiquities}} ccskgrxnz2lun7qxxl7uwp8aw16u5ab 178456 178452 2026-10-27T01:41:25Z GinawaSaHapon 3989 /* Anak na kataga */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]) 178456 wikitext text/x-wiki =={{=la=}}== ===Etimolohiya 1=== {{ety|la|title=līber|id=free|:inh|itc-ola:loeber<ety:inh<itc-pro:*louðeros>>|text=++|tree=1}}<ref name=EDL1>{{R:itc:EDL|page=338|head=līber}}</ref> Kapatid ng {{cog|grc|ἐλεύθερος}}, {{cog|sa|रोधति|tr=ródhati}}, {{cog|nl|lieden}}, {{cog|de|Leute}}, at {{cog|ru|лю́ди|t=sambayanan}}. ====Pagbigkas==== * {{la-IPA|līber}} ====Pang-uri==== {{la-adj|līber|comp=līberior|sup=līberrimus|adv=līberē}} # {{senseid|la|malaya}} [[malaya]]; [[magsarili|nagsasarili]]; walang [[higpit|paghihigpit]]; hindi [[magbantay|binabantayan]] #: {{syn|la|solūtus|expers|immūnis}} #* {{Q|la|{{w|Seneca the Younger|Lucius Anneus Seneca Minor}}|{{w|Epistulae Morales ad Lucilium|Epistulae Morales ad Lucilium}}|Epistula XCII|year=65 AD|quote=''Nēmō '''līber''' est quī corporī servit.''|trans=Walang sinumang '''malaya''' na alipin ng sariling katawan.}} # {{lb|la|transferred}} malayang tao #* {{Q|la|Pl.|Cap.|3|4|94|thru=95|quote=Haud istūc rogō. Fuistin '''līber'''? — Fuī.|trans=Hindi yon ang tinatanong ko. '''Malayang tao''' ka ba? – Noon.}} #* {{Q|la|Publius Terentius Afer|Andria|769|thru=771|quote=DĀVUS: Vērum! Vīdī Cantharam / suffarcinātam! MȲSĪS: Dīs Pol habeō grātiam / quom in pariundō aliquot adfuērunt '''līberae'''!|trans=DAVUS: Totoo! Nakita ko si Canthara na binibigkis [yung sanggol]!<br/>MYSIS (sarkastiko): Sa ngalan ni Pollux, aking pinasasalamatan ang kalangitan sa mga '''malalayang babae''' na nandito sa panganganak!<br/>(Ipinapahiwatig ng tanging pagbanggit lamang kay Canthara rito na maaaring mas mapagkakatiwalaan siya bilang saksi kesa sa alipin na si Mysis.)}} # {{q|ukol sa isang kaso}} hindi pa [[tapos]]; [[bukás]] pa # {{q|ukol sa mga abogado}} walang [[kumiling|kinikilingan]] # hindi [[kabilang]] {{q|sa gastos o katulad}}; walang [[epekto]] =====Kaukulan===== {{la-adecl|līber}} * Minsan {{l|la|līberum}} ang kaukulang paaring pangmaramihan =====Hinangong kataga===== {{col4|la |līberālis |līberālitās |līberāliter |līberātiō |līberātor |līberē |līberī |līberō |līberta |lībertās |lībertīnus |lībertus }} =====Anak na kataga===== {{top3}} * {{desc|rup|libir}} * {{desc|sq|lirë|bor=1}} (pinagtatalunan) * {{desc|ca|lliure}} * {{desc|co|liberu|libaru}} * {{desc|egl|lébber|lèbber}} * {{desc|ist|leîbaro}} * {{desctree|it|libero|bor=1}} * {{desc|lij|libero}} * {{desc|lmo|liber|libar}} * {{desc|an|libre}} * {{desc|roa-ole}} ** {{desc|ast|llibre|chibre}} ** {{desc|ext|libri}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|libre|lhibre}} * {{desc|oc|liure}} * {{desc|roa-opt|livre|libre}} ** {{desc|fax|libri}} ** {{desc|gl|libre}} ** {{desctree|pt|livre}} * {{desctree|es|libre}} * {{desc|pms|lìber}} * {{desc|fur|libar}} * {{desc|rgn|lébar}} * {{desc|sc|líbberu|líveru}} * {{desc|scn|lìviru|lìbbiru|q1=luma}} * {{desc|vec|łìbaro}} * {{desc|fro|libre|slb=1}} ** {{desctree|fr|libre}} ** {{desc|nrf|libe}} ** {{desc|wa|lîb}} {{bottom}} ====Pangngalan==== {{la-noun|līber<2>}} # {{lb|la|post-Republican}} {{singular of|la|līberī}}: [[anak]] na [[lalaki]]; anak {{q|ng isang magulang na}} #: {{syn|la|fīlius|nātus}} #* {{Q|la|Quintilian|Declamations|2|8|2|quote=Quanto alios praestat affectus diligere vitae, lucis auctorem! '''Liberi''' ac parentis non alius mihi videtur affectus quam quo rerum natura, quo mundus ipse constrictus est.|trans=May mas hihigit pa bang damdamin kesa sa pagmamahal sa gumawa ng buhay at liwanag? Tila walang pagkakaiba sa akin ang pagmamahal sa pagitan ng '''anak''' at magulang sa pagmamahal sa pagbubuklod ng kalikasan at ng mismong mundo.}} =====Paalala sa paggamit===== Hanggang sa panahon ng Republika, ginagamit lamang ang salitang ito sa anyong pangmaramihan nito (''plurale tantum''). Kahit sa pagsapit ng panahon ng Imperyo, napakabihirang gamitin ang anyong pang-isahan nito; tanging makikita lamang ito sa {{w|Kodigo ni Justiniano}}. =====Kaukulan===== {{la-ndecl|līber<2>}} ====Sanggunian==== {{reflist}} ===Etimolohiya 2=== {{etymon|la|id=balat|:inh|itc-pro:*luβros|tree=1}} {{inh+|la|itc-pro|*luβros}}, mula sa {{inh|la|ine-pro||*lubʰ-ró-s}}, mula sa {{m|ine-pro|*lewbʰ-||balatan, tanggalin (mula sa katawan), saktan|id=balatan}},<ref name=EDL2>{{R:itc:EDL|pages=337-8|head=liber, -brī}}</ref> posible mula sa {{m|ine-pro|*lew-||tanggalin (mula sa katawan)}}.<ref>{{R:ine:IEW|page=690}}</ref> May kaugnayan sa {{cog|cu|лꙋбъ||balat ng puno}}, {{cog|ru|луб||loobang balat ng puno}}, {{cog|lt|lùpti||balatan}}.<ref>{{R:Nocentini|hw=libro}}</ref> Tingnan din ang {{cog|en|leaf||dahon}}, {{m|en|lobby||pahingaan}}, {{m|en|lodge||panuluyan}}, at {{cog|grc|λυπή||sakit (masaktan)}}. ====Alternatibong pagbaybay==== * {{l|la|lib.}}, {{l|la|l.}} ====Pagbigkas==== * {{la-IPA|liber}} ====Pangngalan==== {{la-noun|liber/libr<2>}} # {{senseid|la|aklat}} [[aklat]] #* {{Q|la|Ovid|Tristia|1|1|thru=2|quote=Parvē — nec invideō — sine mē, '''liber''', ībis in urbem,<br/>eī mihi, quod dominō nōn licet īre tuō!|trans=Aking munting '''aklat''' – hindi ako naiingit [sa'yo] – kung wala ako, mapapadpad ka sa lungsod: Mula sa akin, dahil bawal lisanin ka ng iyong may-ari!<br/>(Tinutukoy ng pinaalis na makata ang aklat niya na para bang maninilbi niya ito na pinadala niya sa Roma.)}} #* {{Q|la|Seneca the Younger|Epistulae Morales ad Lucilium|1|2|3|quote=Distringit '''librōrum''' multitūdō; itaque cum legere nōn possīs quantum habuerīs, satis est habēre quantum lēgās.|trans=Naliligaw lamang ang isip [ng mambabasa] sa dami ng mga '''aklat'''; kaya, dahil hindi ka naman nakakabasa nang singdami ng meron ka, sapat na ang magmay-ari ka [ng mga aklat] ng kaya mo lamang basahin.}} # {{senseid|la|balat ng puno}} [[looban|loobang]] [[balat]] ng [[puno]] =====Kaukulan===== {{la-ndecl|liber/libr<2>}} =====Hinangong kataga===== * {{l|la|libellus}} * {{l|la|librārius}} * {{l|la|librārium}} =====Anak na kataga===== * {{desc|frp|lévro}} {{q|walang dudang anak mismo nito}} ; Mga bahagyang aral na hiram {{top3}} * {{desc|an|libro}} * {{desc|sq|libër|bor=1}} * {{desc|eu|liburu|bor=1}} * {{desc|co|libru}} * {{desc|dlm|lebro}} * {{desc|egl|lîber}} * {{desc|bor=1|en|liber|libro-}} * {{desc|fr|liber|libro-}} * {{desc|fur|libri}} * {{desc|io|libro|bor=1}} * {{desc|ist|leîbro}} * {{desc|it|libro}} * {{desc|lld|liber}} * {{desc|lij|libbro}} * {{desc|lmo|libar|liber|libru}} * {{desc|nap|libro|libbro}} * {{desc|fro|livre|slb=1}} ** {{desctree|fr|livre}} ** {{desc|nrf|livre}} * {{desc|roa-ole|}} ** {{desc|ast|llibru}} ** {{desc|ext|libru}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|lhibro|libro}} * {{desc|roa-opt|livro|libro}} ** {{desc|fax|libru}} ** {{desc|gl|libro}} ** {{desc|pt|livro}} *** {{desc|pov|libru|bor=1}} * {{desc|pro|libre}} ** {{desc|ca|llibre}} ** {{desc|oc|libre}} * {{desc|osp|libro}} ** {{desctree|es|libro}} * {{desc|pms|lìber}} * {{desc|rgn|lìbar}} * {{desc|sc|líbbaru|líbberu|libbru|líbburu}} * {{desc|scn|libbru}} * {{desc|vec|łìbro}} * {{desc|wa|lîv|live}} * {{desc|cel-bry-pro|*llɨβr|bor=1}} {{see desc}} * {{desc|sga|lebor|bor=1}} {{see desc}} {{bottom}} ====Sanggunian==== {{reflist}} ===Etimolohiya 3=== ====Pagbigkas==== * {{la-IPA|līber}} ====Pandiwa==== {{head|la|verb form|head=līber}} # {{inflection of|la|lībō||1|s|pres|pasv|subj}} ===Magbasa pa=== * {{R:la:L&S|līber, ''adj.''|liber1}} * {{R:la:L&S|līber, ''n.''|liber4}} * {{R:la:Elementary Lewis}} * {{R:la:Gaffiot}} * {{R:la:M&A}} * {{R:la:Peck}} * {{R:la:Platner}} * {{R:Smith's Persons}} * {{R:Smith's Antiquities}} afd65x8c4bep9xw5x7lydyr5yhcjex5 178471 178456 2026-10-27T02:43:47Z GinawaSaHapon 3989 /* Pangngalan */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]) 178471 wikitext text/x-wiki =={{=la=}}== ===Etimolohiya 1=== {{ety|la|title=līber|id=free|:inh|itc-ola:loeber<ety:inh<itc-pro:*louðeros>>|text=++|tree=1}}<ref name=EDL1>{{R:itc:EDL|page=338|head=līber}}</ref> Kapatid ng {{cog|grc|ἐλεύθερος}}, {{cog|sa|रोधति|tr=ródhati}}, {{cog|nl|lieden}}, {{cog|de|Leute}}, at {{cog|ru|лю́ди|t=sambayanan}}. ====Pagbigkas==== * {{la-IPA|līber}} ====Pang-uri==== {{la-adj|līber|comp=līberior|sup=līberrimus|adv=līberē}} # {{senseid|la|malaya}} [[malaya]]; [[magsarili|nagsasarili]]; walang [[higpit|paghihigpit]]; hindi [[magbantay|binabantayan]] #: {{syn|la|solūtus|expers|immūnis}} #* {{Q|la|{{w|Seneca the Younger|Lucius Anneus Seneca Minor}}|{{w|Epistulae Morales ad Lucilium|Epistulae Morales ad Lucilium}}|Epistula XCII|year=65 AD|quote=''Nēmō '''līber''' est quī corporī servit.''|trans=Walang sinumang '''malaya''' na alipin ng sariling katawan.}} # {{lb|la|transferred}} malayang tao #* {{Q|la|Pl.|Cap.|3|4|94|thru=95|quote=Haud istūc rogō. Fuistin '''līber'''? — Fuī.|trans=Hindi yon ang tinatanong ko. '''Malayang tao''' ka ba? – Noon.}} #* {{Q|la|Publius Terentius Afer|Andria|769|thru=771|quote=DĀVUS: Vērum! Vīdī Cantharam / suffarcinātam! MȲSĪS: Dīs Pol habeō grātiam / quom in pariundō aliquot adfuērunt '''līberae'''!|trans=DAVUS: Totoo! Nakita ko si Canthara na binibigkis [yung sanggol]!<br/>MYSIS (sarkastiko): Sa ngalan ni Pollux, aking pinasasalamatan ang kalangitan sa mga '''malalayang babae''' na nandito sa panganganak!<br/>(Ipinapahiwatig ng tanging pagbanggit lamang kay Canthara rito na maaaring mas mapagkakatiwalaan siya bilang saksi kesa sa alipin na si Mysis.)}} # {{q|ukol sa isang kaso}} hindi pa [[tapos]]; [[bukás]] pa # {{q|ukol sa mga abogado}} walang [[kumiling|kinikilingan]] # hindi [[kabilang]] {{q|sa gastos o katulad}}; walang [[epekto]] =====Kaukulan===== {{la-adecl|līber}} * Minsan {{l|la|līberum}} ang kaukulang paaring pangmaramihan =====Hinangong kataga===== {{col4|la |līberālis |līberālitās |līberāliter |līberātiō |līberātor |līberē |līberī |līberō |līberta |lībertās |lībertīnus |lībertus }} =====Anak na kataga===== {{top3}} * {{desc|rup|libir}} * {{desc|sq|lirë|bor=1}} (pinagtatalunan) * {{desc|ca|lliure}} * {{desc|co|liberu|libaru}} * {{desc|egl|lébber|lèbber}} * {{desc|ist|leîbaro}} * {{desctree|it|libero|bor=1}} * {{desc|lij|libero}} * {{desc|lmo|liber|libar}} * {{desc|an|libre}} * {{desc|roa-ole}} ** {{desc|ast|llibre|chibre}} ** {{desc|ext|libri}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|libre|lhibre}} * {{desc|oc|liure}} * {{desc|roa-opt|livre|libre}} ** {{desc|fax|libri}} ** {{desc|gl|libre}} ** {{desctree|pt|livre}} * {{desctree|es|libre}} * {{desc|pms|lìber}} * {{desc|fur|libar}} * {{desc|rgn|lébar}} * {{desc|sc|líbberu|líveru}} * {{desc|scn|lìviru|lìbbiru|q1=luma}} * {{desc|vec|łìbaro}} * {{desc|fro|libre|slb=1}} ** {{desctree|fr|libre}} ** {{desc|nrf|libe}} ** {{desc|wa|lîb}} {{bottom}} ====Pangngalan==== {{la-noun|līber<2>}} # {{lb|la|pagkatapos ng Republika}} {{singular of|la|līberī}}: [[anak]] na [[lalaki]]; anak {{q|ng isang magulang na}} #: {{syn|la|fīlius|nātus}} #* {{Q|la|Quintilian|Declamations|2|8|2|quote=Quanto alios praestat affectus diligere vitae, lucis auctorem! '''Liberi''' ac parentis non alius mihi videtur affectus quam quo rerum natura, quo mundus ipse constrictus est.|trans=May mas hihigit pa bang damdamin kesa sa pagmamahal sa gumawa ng buhay at liwanag? Tila walang pagkakaiba sa akin ang pagmamahal sa pagitan ng '''anak''' at magulang sa pagmamahal sa pagbubuklod ng kalikasan at ng mismong mundo.}} =====Paalala sa paggamit===== Hanggang sa panahon ng Republika, ginagamit lamang ang salitang ito sa anyong pangmaramihan nito (''plurale tantum''). Kahit sa pagsapit ng panahon ng Imperyo, napakabihirang gamitin ang anyong pang-isahan nito; tanging makikita lamang ito sa {{w|Kodigo ni Justiniano}}. =====Kaukulan===== {{la-ndecl|līber<2>}} ====Sanggunian==== {{reflist}} ===Etimolohiya 2=== {{etymon|la|id=balat|:inh|itc-pro:*luβros|tree=1}} {{inh+|la|itc-pro|*luβros}}, mula sa {{inh|la|ine-pro||*lubʰ-ró-s}}, mula sa {{m|ine-pro|*lewbʰ-||balatan, tanggalin (mula sa katawan), saktan|id=balatan}},<ref name=EDL2>{{R:itc:EDL|pages=337-8|head=liber, -brī}}</ref> posible mula sa {{m|ine-pro|*lew-||tanggalin (mula sa katawan)}}.<ref>{{R:ine:IEW|page=690}}</ref> May kaugnayan sa {{cog|cu|лꙋбъ||balat ng puno}}, {{cog|ru|луб||loobang balat ng puno}}, {{cog|lt|lùpti||balatan}}.<ref>{{R:Nocentini|hw=libro}}</ref> Tingnan din ang {{cog|en|leaf||dahon}}, {{m|en|lobby||pahingaan}}, {{m|en|lodge||panuluyan}}, at {{cog|grc|λυπή||sakit (masaktan)}}. ====Alternatibong pagbaybay==== * {{l|la|lib.}}, {{l|la|l.}} ====Pagbigkas==== * {{la-IPA|liber}} ====Pangngalan==== {{la-noun|liber/libr<2>}} # {{senseid|la|aklat}} [[aklat]] #* {{Q|la|Ovid|Tristia|1|1|thru=2|quote=Parvē — nec invideō — sine mē, '''liber''', ībis in urbem,<br/>eī mihi, quod dominō nōn licet īre tuō!|trans=Aking munting '''aklat''' – hindi ako naiingit [sa'yo] – kung wala ako, mapapadpad ka sa lungsod: Mula sa akin, dahil bawal lisanin ka ng iyong may-ari!<br/>(Tinutukoy ng pinaalis na makata ang aklat niya na para bang maninilbi niya ito na pinadala niya sa Roma.)}} #* {{Q|la|Seneca the Younger|Epistulae Morales ad Lucilium|1|2|3|quote=Distringit '''librōrum''' multitūdō; itaque cum legere nōn possīs quantum habuerīs, satis est habēre quantum lēgās.|trans=Naliligaw lamang ang isip [ng mambabasa] sa dami ng mga '''aklat'''; kaya, dahil hindi ka naman nakakabasa nang singdami ng meron ka, sapat na ang magmay-ari ka [ng mga aklat] ng kaya mo lamang basahin.}} # {{senseid|la|balat ng puno}} [[looban|loobang]] [[balat]] ng [[puno]] =====Kaukulan===== {{la-ndecl|liber/libr<2>}} =====Hinangong kataga===== * {{l|la|libellus}} * {{l|la|librārius}} * {{l|la|librārium}} =====Anak na kataga===== * {{desc|frp|lévro}} {{q|walang dudang anak mismo nito}} ; Mga bahagyang aral na hiram {{top3}} * {{desc|an|libro}} * {{desc|sq|libër|bor=1}} * {{desc|eu|liburu|bor=1}} * {{desc|co|libru}} * {{desc|dlm|lebro}} * {{desc|egl|lîber}} * {{desc|bor=1|en|liber|libro-}} * {{desc|fr|liber|libro-}} * {{desc|fur|libri}} * {{desc|io|libro|bor=1}} * {{desc|ist|leîbro}} * {{desc|it|libro}} * {{desc|lld|liber}} * {{desc|lij|libbro}} * {{desc|lmo|libar|liber|libru}} * {{desc|nap|libro|libbro}} * {{desc|fro|livre|slb=1}} ** {{desctree|fr|livre}} ** {{desc|nrf|livre}} * {{desc|roa-ole|}} ** {{desc|ast|llibru}} ** {{desc|ext|libru}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|lhibro|libro}} * {{desc|roa-opt|livro|libro}} ** {{desc|fax|libru}} ** {{desc|gl|libro}} ** {{desc|pt|livro}} *** {{desc|pov|libru|bor=1}} * {{desc|pro|libre}} ** {{desc|ca|llibre}} ** {{desc|oc|libre}} * {{desc|osp|libro}} ** {{desctree|es|libro}} * {{desc|pms|lìber}} * {{desc|rgn|lìbar}} * {{desc|sc|líbbaru|líbberu|libbru|líbburu}} * {{desc|scn|libbru}} * {{desc|vec|łìbro}} * {{desc|wa|lîv|live}} * {{desc|cel-bry-pro|*llɨβr|bor=1}} {{see desc}} * {{desc|sga|lebor|bor=1}} {{see desc}} {{bottom}} ====Sanggunian==== {{reflist}} ===Etimolohiya 3=== ====Pagbigkas==== * {{la-IPA|līber}} ====Pandiwa==== {{head|la|verb form|head=līber}} # {{inflection of|la|lībō||1|s|pres|pasv|subj}} ===Magbasa pa=== * {{R:la:L&S|līber, ''adj.''|liber1}} * {{R:la:L&S|līber, ''n.''|liber4}} * {{R:la:Elementary Lewis}} * {{R:la:Gaffiot}} * {{R:la:M&A}} * {{R:la:Peck}} * {{R:la:Platner}} * {{R:Smith's Persons}} * {{R:Smith's Antiquities}} bqg0gfw14x217c8pbj9cegxudm0lep9 178477 178471 2026-10-27T02:56:54Z GinawaSaHapon 3989 /* Etimolohiya 2 */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]) 178477 wikitext text/x-wiki =={{=la=}}== ===Etimolohiya 1=== {{ety|la|title=līber|id=free|:inh|itc-ola:loeber<ety:inh<itc-pro:*louðeros>>|text=++|tree=1}}<ref name=EDL1>{{R:itc:EDL|page=338|head=līber}}</ref> Kapatid ng {{cog|grc|ἐλεύθερος}}, {{cog|sa|रोधति|tr=ródhati}}, {{cog|nl|lieden}}, {{cog|de|Leute}}, at {{cog|ru|лю́ди|t=sambayanan}}. ====Pagbigkas==== * {{la-IPA|līber}} ====Pang-uri==== {{la-adj|līber|comp=līberior|sup=līberrimus|adv=līberē}} # {{senseid|la|malaya}} [[malaya]]; [[magsarili|nagsasarili]]; walang [[higpit|paghihigpit]]; hindi [[magbantay|binabantayan]] #: {{syn|la|solūtus|expers|immūnis}} #* {{Q|la|{{w|Seneca the Younger|Lucius Anneus Seneca Minor}}|{{w|Epistulae Morales ad Lucilium|Epistulae Morales ad Lucilium}}|Epistula XCII|year=65 AD|quote=''Nēmō '''līber''' est quī corporī servit.''|trans=Walang sinumang '''malaya''' na alipin ng sariling katawan.}} # {{lb|la|transferred}} malayang tao #* {{Q|la|Pl.|Cap.|3|4|94|thru=95|quote=Haud istūc rogō. Fuistin '''līber'''? — Fuī.|trans=Hindi yon ang tinatanong ko. '''Malayang tao''' ka ba? – Noon.}} #* {{Q|la|Publius Terentius Afer|Andria|769|thru=771|quote=DĀVUS: Vērum! Vīdī Cantharam / suffarcinātam! MȲSĪS: Dīs Pol habeō grātiam / quom in pariundō aliquot adfuērunt '''līberae'''!|trans=DAVUS: Totoo! Nakita ko si Canthara na binibigkis [yung sanggol]!<br/>MYSIS (sarkastiko): Sa ngalan ni Pollux, aking pinasasalamatan ang kalangitan sa mga '''malalayang babae''' na nandito sa panganganak!<br/>(Ipinapahiwatig ng tanging pagbanggit lamang kay Canthara rito na maaaring mas mapagkakatiwalaan siya bilang saksi kesa sa alipin na si Mysis.)}} # {{q|ukol sa isang kaso}} hindi pa [[tapos]]; [[bukás]] pa # {{q|ukol sa mga abogado}} walang [[kumiling|kinikilingan]] # hindi [[kabilang]] {{q|sa gastos o katulad}}; walang [[epekto]] =====Kaukulan===== {{la-adecl|līber}} * Minsan {{l|la|līberum}} ang kaukulang paaring pangmaramihan =====Hinangong kataga===== {{col4|la |līberālis |līberālitās |līberāliter |līberātiō |līberātor |līberē |līberī |līberō |līberta |lībertās |lībertīnus |lībertus }} =====Anak na kataga===== {{top3}} * {{desc|rup|libir}} * {{desc|sq|lirë|bor=1}} (pinagtatalunan) * {{desc|ca|lliure}} * {{desc|co|liberu|libaru}} * {{desc|egl|lébber|lèbber}} * {{desc|ist|leîbaro}} * {{desctree|it|libero|bor=1}} * {{desc|lij|libero}} * {{desc|lmo|liber|libar}} * {{desc|an|libre}} * {{desc|roa-ole}} ** {{desc|ast|llibre|chibre}} ** {{desc|ext|libri}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|libre|lhibre}} * {{desc|oc|liure}} * {{desc|roa-opt|livre|libre}} ** {{desc|fax|libri}} ** {{desc|gl|libre}} ** {{desctree|pt|livre}} * {{desctree|es|libre}} * {{desc|pms|lìber}} * {{desc|fur|libar}} * {{desc|rgn|lébar}} * {{desc|sc|líbberu|líveru}} * {{desc|scn|lìviru|lìbbiru|q1=luma}} * {{desc|vec|łìbaro}} * {{desc|fro|libre|slb=1}} ** {{desctree|fr|libre}} ** {{desc|nrf|libe}} ** {{desc|wa|lîb}} {{bottom}} ====Pangngalan==== {{la-noun|līber<2>}} # {{lb|la|pagkatapos ng Republika}} {{singular of|la|līberī}}: [[anak]] na [[lalaki]]; anak {{q|ng isang magulang na}} #: {{syn|la|fīlius|nātus}} #* {{Q|la|Quintilian|Declamations|2|8|2|quote=Quanto alios praestat affectus diligere vitae, lucis auctorem! '''Liberi''' ac parentis non alius mihi videtur affectus quam quo rerum natura, quo mundus ipse constrictus est.|trans=May mas hihigit pa bang damdamin kesa sa pagmamahal sa gumawa ng buhay at liwanag? Tila walang pagkakaiba sa akin ang pagmamahal sa pagitan ng '''anak''' at magulang sa pagmamahal sa pagbubuklod ng kalikasan at ng mismong mundo.}} =====Paalala sa paggamit===== Hanggang sa panahon ng Republika, ginagamit lamang ang salitang ito sa anyong pangmaramihan nito (''plurale tantum''). Kahit sa pagsapit ng panahon ng Imperyo, napakabihirang gamitin ang anyong pang-isahan nito; tanging makikita lamang ito sa {{w|Kodigo ni Justiniano}}. =====Kaukulan===== {{la-ndecl|līber<2>}} ====Sanggunian==== {{reflist}} ===Etimolohiya 2=== {{etymon|la|id=balat|:inh|itc-pro:*luβros|tree=1}} {{inh+|la|itc-pro|*luβros}}, mula sa {{inh|la|ine-pro||*lubʰ-ró-s}}, mula sa {{m|ine-pro|*lewbʰ-||balatan, tanggalin (mula sa katawan), saktan|id=balatan}},<ref name=EDL2>{{R:itc:EDL|pages=337-8|head=liber, -brī}}</ref> posible mula sa {{m|ine-pro|*lew-||tanggalin (mula sa katawan)}}.<ref>{{R:ine:IEW|page=690}}</ref> Kapatid ng {{cog|cu|лꙋбъ||balat ng puno}}, {{cog|ru|луб||loobang balat ng puno}}, {{cog|lt|lùpti||balatan}}.<ref>{{R:Nocentini|hw=libro}}</ref> Tingnan din ang {{cog|en|leaf||dahon}}, {{m|en|lobby||pahingaan}}, {{m|en|lodge||panuluyan}}, at {{cog|grc|λυπή||sakit (masaktan)}}. ====Alternatibong pagbaybay==== * {{l|la|lib.}}, {{l|la|l.}} ====Pagbigkas==== * {{la-IPA|liber}} ====Pangngalan==== {{la-noun|liber/libr<2>}} # {{senseid|la|aklat}} [[aklat]] #* {{Q|la|Ovid|Tristia|1|1|thru=2|quote=Parvē — nec invideō — sine mē, '''liber''', ībis in urbem,<br/>eī mihi, quod dominō nōn licet īre tuō!|trans=Aking munting '''aklat''' – hindi ako naiingit [sa'yo] – kung wala ako, mapapadpad ka sa lungsod: Mula sa akin, dahil bawal lisanin ka ng iyong may-ari!<br/>(Tinutukoy ng pinaalis na makata ang aklat niya na para bang maninilbi niya ito na pinadala niya sa Roma.)}} #* {{Q|la|Seneca the Younger|Epistulae Morales ad Lucilium|1|2|3|quote=Distringit '''librōrum''' multitūdō; itaque cum legere nōn possīs quantum habuerīs, satis est habēre quantum lēgās.|trans=Naliligaw lamang ang isip [ng mambabasa] sa dami ng mga '''aklat'''; kaya, dahil hindi ka naman nakakabasa nang singdami ng meron ka, sapat na ang magmay-ari ka [ng mga aklat] ng kaya mo lamang basahin.}} # {{senseid|la|balat ng puno}} [[looban|loobang]] [[balat]] ng [[puno]] =====Kaukulan===== {{la-ndecl|liber/libr<2>}} =====Hinangong kataga===== * {{l|la|libellus}} * {{l|la|librārius}} * {{l|la|librārium}} =====Anak na kataga===== * {{desc|frp|lévro}} {{q|walang dudang anak mismo nito}} ; Mga bahagyang aral na hiram {{top3}} * {{desc|an|libro}} * {{desc|sq|libër|bor=1}} * {{desc|eu|liburu|bor=1}} * {{desc|co|libru}} * {{desc|dlm|lebro}} * {{desc|egl|lîber}} * {{desc|bor=1|en|liber|libro-}} * {{desc|fr|liber|libro-}} * {{desc|fur|libri}} * {{desc|io|libro|bor=1}} * {{desc|ist|leîbro}} * {{desc|it|libro}} * {{desc|lld|liber}} * {{desc|lij|libbro}} * {{desc|lmo|libar|liber|libru}} * {{desc|nap|libro|libbro}} * {{desc|fro|livre|slb=1}} ** {{desctree|fr|livre}} ** {{desc|nrf|livre}} * {{desc|roa-ole|}} ** {{desc|ast|llibru}} ** {{desc|ext|libru}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|lhibro|libro}} * {{desc|roa-opt|livro|libro}} ** {{desc|fax|libru}} ** {{desc|gl|libro}} ** {{desc|pt|livro}} *** {{desc|pov|libru|bor=1}} * {{desc|pro|libre}} ** {{desc|ca|llibre}} ** {{desc|oc|libre}} * {{desc|osp|libro}} ** {{desctree|es|libro}} * {{desc|pms|lìber}} * {{desc|rgn|lìbar}} * {{desc|sc|líbbaru|líbberu|libbru|líbburu}} * {{desc|scn|libbru}} * {{desc|vec|łìbro}} * {{desc|wa|lîv|live}} * {{desc|cel-bry-pro|*llɨβr|bor=1}} {{see desc}} * {{desc|sga|lebor|bor=1}} {{see desc}} {{bottom}} ====Sanggunian==== {{reflist}} ===Etimolohiya 3=== ====Pagbigkas==== * {{la-IPA|līber}} ====Pandiwa==== {{head|la|verb form|head=līber}} # {{inflection of|la|lībō||1|s|pres|pasv|subj}} ===Magbasa pa=== * {{R:la:L&S|līber, ''adj.''|liber1}} * {{R:la:L&S|līber, ''n.''|liber4}} * {{R:la:Elementary Lewis}} * {{R:la:Gaffiot}} * {{R:la:M&A}} * {{R:la:Peck}} * {{R:la:Platner}} * {{R:Smith's Persons}} * {{R:Smith's Antiquities}} n6s499jq0caqjxcbcjbb3k77le7lyig 178511 178477 2026-10-27T06:11:03Z GinawaSaHapon 3989 /* Magbasa pa */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]) 178511 wikitext text/x-wiki =={{=la=}}== ===Etimolohiya 1=== {{ety|la|title=līber|id=free|:inh|itc-ola:loeber<ety:inh<itc-pro:*louðeros>>|text=++|tree=1}}<ref name=EDL1>{{R:itc:EDL|page=338|head=līber}}</ref> Kapatid ng {{cog|grc|ἐλεύθερος}}, {{cog|sa|रोधति|tr=ródhati}}, {{cog|nl|lieden}}, {{cog|de|Leute}}, at {{cog|ru|лю́ди|t=sambayanan}}. ====Pagbigkas==== * {{la-IPA|līber}} ====Pang-uri==== {{la-adj|līber|comp=līberior|sup=līberrimus|adv=līberē}} # {{senseid|la|malaya}} [[malaya]]; [[magsarili|nagsasarili]]; walang [[higpit|paghihigpit]]; hindi [[magbantay|binabantayan]] #: {{syn|la|solūtus|expers|immūnis}} #* {{Q|la|{{w|Seneca the Younger|Lucius Anneus Seneca Minor}}|{{w|Epistulae Morales ad Lucilium|Epistulae Morales ad Lucilium}}|Epistula XCII|year=65 AD|quote=''Nēmō '''līber''' est quī corporī servit.''|trans=Walang sinumang '''malaya''' na alipin ng sariling katawan.}} # {{lb|la|transferred}} malayang tao #* {{Q|la|Pl.|Cap.|3|4|94|thru=95|quote=Haud istūc rogō. Fuistin '''līber'''? — Fuī.|trans=Hindi yon ang tinatanong ko. '''Malayang tao''' ka ba? – Noon.}} #* {{Q|la|Publius Terentius Afer|Andria|769|thru=771|quote=DĀVUS: Vērum! Vīdī Cantharam / suffarcinātam! MȲSĪS: Dīs Pol habeō grātiam / quom in pariundō aliquot adfuērunt '''līberae'''!|trans=DAVUS: Totoo! Nakita ko si Canthara na binibigkis [yung sanggol]!<br/>MYSIS (sarkastiko): Sa ngalan ni Pollux, aking pinasasalamatan ang kalangitan sa mga '''malalayang babae''' na nandito sa panganganak!<br/>(Ipinapahiwatig ng tanging pagbanggit lamang kay Canthara rito na maaaring mas mapagkakatiwalaan siya bilang saksi kesa sa alipin na si Mysis.)}} # {{q|ukol sa isang kaso}} hindi pa [[tapos]]; [[bukás]] pa # {{q|ukol sa mga abogado}} walang [[kumiling|kinikilingan]] # hindi [[kabilang]] {{q|sa gastos o katulad}}; walang [[epekto]] =====Kaukulan===== {{la-adecl|līber}} * Minsan {{l|la|līberum}} ang kaukulang paaring pangmaramihan =====Hinangong kataga===== {{col4|la |līberālis |līberālitās |līberāliter |līberātiō |līberātor |līberē |līberī |līberō |līberta |lībertās |lībertīnus |lībertus }} =====Anak na kataga===== {{top3}} * {{desc|rup|libir}} * {{desc|sq|lirë|bor=1}} (pinagtatalunan) * {{desc|ca|lliure}} * {{desc|co|liberu|libaru}} * {{desc|egl|lébber|lèbber}} * {{desc|ist|leîbaro}} * {{desctree|it|libero|bor=1}} * {{desc|lij|libero}} * {{desc|lmo|liber|libar}} * {{desc|an|libre}} * {{desc|roa-ole}} ** {{desc|ast|llibre|chibre}} ** {{desc|ext|libri}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|libre|lhibre}} * {{desc|oc|liure}} * {{desc|roa-opt|livre|libre}} ** {{desc|fax|libri}} ** {{desc|gl|libre}} ** {{desctree|pt|livre}} * {{desctree|es|libre}} * {{desc|pms|lìber}} * {{desc|fur|libar}} * {{desc|rgn|lébar}} * {{desc|sc|líbberu|líveru}} * {{desc|scn|lìviru|lìbbiru|q1=luma}} * {{desc|vec|łìbaro}} * {{desc|fro|libre|slb=1}} ** {{desctree|fr|libre}} ** {{desc|nrf|libe}} ** {{desc|wa|lîb}} {{bottom}} ====Pangngalan==== {{la-noun|līber<2>}} # {{lb|la|pagkatapos ng Republika}} {{singular of|la|līberī}}: [[anak]] na [[lalaki]]; anak {{q|ng isang magulang na}} #: {{syn|la|fīlius|nātus}} #* {{Q|la|Quintilian|Declamations|2|8|2|quote=Quanto alios praestat affectus diligere vitae, lucis auctorem! '''Liberi''' ac parentis non alius mihi videtur affectus quam quo rerum natura, quo mundus ipse constrictus est.|trans=May mas hihigit pa bang damdamin kesa sa pagmamahal sa gumawa ng buhay at liwanag? Tila walang pagkakaiba sa akin ang pagmamahal sa pagitan ng '''anak''' at magulang sa pagmamahal sa pagbubuklod ng kalikasan at ng mismong mundo.}} =====Paalala sa paggamit===== Hanggang sa panahon ng Republika, ginagamit lamang ang salitang ito sa anyong pangmaramihan nito (''plurale tantum''). Kahit sa pagsapit ng panahon ng Imperyo, napakabihirang gamitin ang anyong pang-isahan nito; tanging makikita lamang ito sa {{w|Kodigo ni Justiniano}}. =====Kaukulan===== {{la-ndecl|līber<2>}} ====Sanggunian==== {{reflist}} ===Etimolohiya 2=== {{etymon|la|id=balat|:inh|itc-pro:*luβros|tree=1}} {{inh+|la|itc-pro|*luβros}}, mula sa {{inh|la|ine-pro||*lubʰ-ró-s}}, mula sa {{m|ine-pro|*lewbʰ-||balatan, tanggalin (mula sa katawan), saktan|id=balatan}},<ref name=EDL2>{{R:itc:EDL|pages=337-8|head=liber, -brī}}</ref> posible mula sa {{m|ine-pro|*lew-||tanggalin (mula sa katawan)}}.<ref>{{R:ine:IEW|page=690}}</ref> Kapatid ng {{cog|cu|лꙋбъ||balat ng puno}}, {{cog|ru|луб||loobang balat ng puno}}, {{cog|lt|lùpti||balatan}}.<ref>{{R:Nocentini|hw=libro}}</ref> Tingnan din ang {{cog|en|leaf||dahon}}, {{m|en|lobby||pahingaan}}, {{m|en|lodge||panuluyan}}, at {{cog|grc|λυπή||sakit (masaktan)}}. ====Alternatibong pagbaybay==== * {{l|la|lib.}}, {{l|la|l.}} ====Pagbigkas==== * {{la-IPA|liber}} ====Pangngalan==== {{la-noun|liber/libr<2>}} # {{senseid|la|aklat}} [[aklat]] #* {{Q|la|Ovid|Tristia|1|1|thru=2|quote=Parvē — nec invideō — sine mē, '''liber''', ībis in urbem,<br/>eī mihi, quod dominō nōn licet īre tuō!|trans=Aking munting '''aklat''' – hindi ako naiingit [sa'yo] – kung wala ako, mapapadpad ka sa lungsod: Mula sa akin, dahil bawal lisanin ka ng iyong may-ari!<br/>(Tinutukoy ng pinaalis na makata ang aklat niya na para bang maninilbi niya ito na pinadala niya sa Roma.)}} #* {{Q|la|Seneca the Younger|Epistulae Morales ad Lucilium|1|2|3|quote=Distringit '''librōrum''' multitūdō; itaque cum legere nōn possīs quantum habuerīs, satis est habēre quantum lēgās.|trans=Naliligaw lamang ang isip [ng mambabasa] sa dami ng mga '''aklat'''; kaya, dahil hindi ka naman nakakabasa nang singdami ng meron ka, sapat na ang magmay-ari ka [ng mga aklat] ng kaya mo lamang basahin.}} # {{senseid|la|balat ng puno}} [[looban|loobang]] [[balat]] ng [[puno]] =====Kaukulan===== {{la-ndecl|liber/libr<2>}} =====Hinangong kataga===== * {{l|la|libellus}} * {{l|la|librārius}} * {{l|la|librārium}} =====Anak na kataga===== * {{desc|frp|lévro}} {{q|walang dudang anak mismo nito}} ; Mga bahagyang aral na hiram {{top3}} * {{desc|an|libro}} * {{desc|sq|libër|bor=1}} * {{desc|eu|liburu|bor=1}} * {{desc|co|libru}} * {{desc|dlm|lebro}} * {{desc|egl|lîber}} * {{desc|bor=1|en|liber|libro-}} * {{desc|fr|liber|libro-}} * {{desc|fur|libri}} * {{desc|io|libro|bor=1}} * {{desc|ist|leîbro}} * {{desc|it|libro}} * {{desc|lld|liber}} * {{desc|lij|libbro}} * {{desc|lmo|libar|liber|libru}} * {{desc|nap|libro|libbro}} * {{desc|fro|livre|slb=1}} ** {{desctree|fr|livre}} ** {{desc|nrf|livre}} * {{desc|roa-ole|}} ** {{desc|ast|llibru}} ** {{desc|ext|libru}} ** {{desc|roa-leo|llibru}} ** {{desc|mwl|lhibro|libro}} * {{desc|roa-opt|livro|libro}} ** {{desc|fax|libru}} ** {{desc|gl|libro}} ** {{desc|pt|livro}} *** {{desc|pov|libru|bor=1}} * {{desc|pro|libre}} ** {{desc|ca|llibre}} ** {{desc|oc|libre}} * {{desc|osp|libro}} ** {{desctree|es|libro}} * {{desc|pms|lìber}} * {{desc|rgn|lìbar}} * {{desc|sc|líbbaru|líbberu|libbru|líbburu}} * {{desc|scn|libbru}} * {{desc|vec|łìbro}} * {{desc|wa|lîv|live}} * {{desc|cel-bry-pro|*llɨβr|bor=1}} {{see desc}} * {{desc|sga|lebor|bor=1}} {{see desc}} {{bottom}} ====Sanggunian==== {{reflist}} ===Etimolohiya 3=== ====Pagbigkas==== * {{la-IPA|līber}} ====Pandiwa==== {{head|la|verb form|head=līber}} # {{inflection of|la|lībō||1|s|pres|pasv|subj}} ===Magbasa pa=== * {{R:la:L&S|līber, ''adj.''|liber1}} * {{R:la:L&S|līber, ''n.''|liber4}} * {{R:la:Elementary Lewis}} * {{R:la:Gaffiot}} * {{R:la:Peck}} * {{R:la:Platner}} * {{R:Smith's Persons}} * {{R:Smith's Antiquities}} 2to46d03qatal00kzwv5afo328uek9c Module:la-adj/table 828 38962 178450 178404 2026-10-27T01:22:38Z GinawaSaHapon 3989 178450 Scribunto text/plain local export = {} local m_table = require("Module:table") local m_inflection_table = require("Module:inflection-table") local function convert(data, conv) local col = {} local row = {} local marked = {} local slots = {} local function add(i,j) local col = col[i][j] local row = row[i][j] if col==0 or row==0 then return "" end local entry = data.finish_show_form(data, slots[i][j]) if col==1 then if row==1 then return '\n| ' .. entry else return '\n| rowspan=' .. row .. ' | ' .. entry end else if row==1 then return '\n| colspan=' .. col .. ' | ' .. entry else return '\n| colspan=' .. col .. ' rowspan=' .. row .. ' | ' .. entry end end end for i=1,#conv do col[i] = {} row[i] = {} marked[i] = {} slots[i] = {} for j=1,#conv[i] do col[i][j] = 1 row[i][j] = 1 marked[i][j] = false slots[i][j] = {conv[i][j]} end end -- Return true if the contents of the two slots are equal in every -- way. This means the forms are the same, the footnote text is the -- same, and the accelerator lemmas are the same. We need to compare -- the accelerator lemmas because in some cases different slots have -- different lemmas (e.g. when noneut=1 is set, the masculine slots -- will have the masculine lemma but the feminine slots will have the -- feminine lemma). local function slots_equal(slot1, slot2) return m_table.deepEquals(data.forms[slot1], data.forms[slot2]) and m_table.deepEquals(data.notetext[slot1], data.notetext[slot2]) and (data.accel[slot1] and data.accel[slot1].lemma or nil) == (data.accel[slot2] and data.accel[slot2].lemma or nil) end --merge identical cells within a row for i=1,#conv do for j=1,#conv[i] do if col[i][j] ~= 0 then for k=j+1,#conv[i] do local slotij = conv[i][j] local slotik = conv[i][k] if not slots_equal(slotij, slotik) then break end col[i][j] = col[i][j] + 1 col[i][k] = 0 row[i][k] = 0 for _, slot in ipairs(slots[i][k]) do table.insert(slots[i][j], slot) end slots[i][k] = nil end end end end --final for i=1,#conv do for j=1,#conv[i] do conv[i][j] = add(i,j) end conv[i] = table.concat(conv[i]) end return conv end local function make_table_mfn_pl(data, mfonly) local conv = { {"nom_pl_m"}, {"gen_pl_m"}, {"dat_pl_m"}, {"acc_pl_m"}, {"abl_pl_m"}, {"voc_pl_m"}, {"loc_pl_m"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. (mfonly and 'l./b.' or 'l./b./dt.') output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_mfn_sg(data, mfonly) local conv = { {"nom_sg_m"}, {"gen_sg_m"}, {"dat_sg_m"}, {"acc_sg_m"}, {"abl_sg_m"}, {"voc_sg_m"}, {"loc_sg_m"}, } conv = convert(data, conv) local output = data.title .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | isahan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. (mfonly and 'l./b.' or 'l./b./dt.') output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_n_pl(data) local conv = { {"nom_pl_n"}, {"gen_pl_n"}, {"dat_pl_n"}, {"acc_pl_n"}, {"abl_pl_n"}, {"voc_pl_n"}, {"loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. 'di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_n_sg(data) local conv = { {"nom_sg_n"}, {"gen_sg_n"}, {"dat_sg_n"}, {"acc_sg_n"}, {"abl_sg_n"}, {"voc_sg_n"}, {"loc_sg_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | isahan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. 'di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_mf_and_n_pl(data) local conv = { {"nom_pl_m", "nom_pl_n"}, {"gen_pl_m", "gen_pl_n"}, {"dat_pl_m", "dat_pl_n"}, {"acc_pl_m", "acc_pl_n"}, {"abl_pl_m", "abl_pl_n"}, {"voc_pl_m", "voc_pl_n"}, {"loc_pl_m", "loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! l./b.' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_mf_and_n_sg(data) local conv = { {"nom_sg_m", "nom_sg_n"}, {"gen_sg_m", "gen_sg_n"}, {"dat_sg_m", "dat_sg_n"}, {"acc_sg_m", "acc_sg_n"}, {"abl_sg_m", "abl_sg_n"}, {"voc_sg_m", "voc_sg_n"}, {"loc_sg_m", "loc_sg_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | isahan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! l./b.' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f_pl(data) local conv = { {"nom_pl_m", "nom_pl_f"}, {"gen_pl_m", "gen_pl_f"}, {"dat_pl_m", "dat_pl_f"}, {"acc_pl_m", "acc_pl_f"}, {"abl_pl_m", "abl_pl_f"}, {"voc_pl_m", "voc_pl_f"}, {"loc_pl_m", "loc_pl_f"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f_sg(data) local conv = { {"nom_sg_m", "nom_sg_f"}, {"gen_sg_m", "gen_sg_f"}, {"dat_sg_m", "dat_sg_f"}, {"acc_sg_m", "acc_sg_f"}, {"abl_sg_m", "abl_sg_f"}, {"voc_sg_m", "voc_sg_f"}, {"loc_sg_m", "loc_sg_f"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | isahan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f_and_n_pl(data) local conv = { {"nom_pl_m", "nom_pl_f", "nom_pl_n"}, {"gen_pl_m", "gen_pl_f", "gen_pl_n"}, {"dat_pl_m", "dat_pl_f", "dat_pl_n"}, {"acc_pl_m", "acc_pl_f", "acc_pl_n"}, {"abl_pl_m", "abl_pl_f", "abl_pl_n"}, {"voc_pl_m", "voc_pl_f", "voc_pl_n"}, {"loc_pl_m", "loc_pl_f", "loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="3" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f_and_n_sg(data) local conv = { {"nom_sg_m", "nom_sg_f", "nom_sg_n"}, {"gen_sg_m", "gen_sg_f", "gen_sg_n"}, {"dat_sg_m", "dat_sg_f", "dat_sg_n"}, {"acc_sg_m", "acc_sg_f", "acc_sg_n"}, {"abl_sg_m", "abl_sg_f", "abl_sg_n"}, {"voc_sg_m", "voc_sg_f", "voc_sg_n"}, {"loc_sg_m", "loc_sg_f", "loc_sg_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="3" | isahan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_mfn(data, mfonly) local conv = { {"nom_sg_m"}, {"gen_sg_m"}, {"dat_sg_m"}, {"acc_sg_m"}, {"abl_sg_m"}, {"voc_sg_m"}, {"loc_sg_m"}, {"nom_pl_m"}, {"gen_pl_m"}, {"dat_pl_m"}, {"acc_pl_m"}, {"abl_pl_m"}, {"voc_pl_m"}, {"loc_pl_m"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | isahan' output = output .. '\n|class="separator" rowspan="999"|' output = output .. '\n!class="outer" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. (mfonly and 'l./b.' or 'l./b./dt.') output = output .. '\n! ' .. (mfonly and 'l./b.' or 'l./b./dt.') output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. conv[8] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. conv[9] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. conv[10] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. conv[11] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. conv[12] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] output = output .. conv[13] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] output = output .. conv[14] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_n(data) local conv = { {"nom_sg_n"}, {"gen_sg_n"}, {"dat_sg_n"}, {"acc_sg_n"}, {"abl_sg_n"}, {"voc_sg_n"}, {"loc_sg_n"}, {"nom_pl_n"}, {"gen_pl_n"}, {"dat_pl_n"}, {"acc_pl_n"}, {"abl_pl_n"}, {"voc_pl_n"}, {"loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" | isahan' output = output .. '\n|class="separator" rowspan="999"|' output = output .. '\n!class="outer" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! ' .. 'di-tiyak' output = output .. '\n! ' .. 'di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. conv[8] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. conv[9] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. conv[10] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. conv[11] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. conv[12] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] output = output .. conv[13] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] output = output .. conv[14] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_mf_and_n(data) local conv = { {"nom_sg_m", "nom_sg_n"}, {"gen_sg_m", "gen_sg_n"}, {"dat_sg_m", "dat_sg_n"}, {"acc_sg_m", "acc_sg_n"}, {"abl_sg_m", "abl_sg_n"}, {"voc_sg_m", "voc_sg_n"}, {"loc_sg_m", "loc_sg_n"}, {"nom_pl_m", "nom_pl_n"}, {"gen_pl_m", "gen_pl_n"}, {"dat_pl_m", "dat_pl_n"}, {"acc_pl_m", "acc_pl_n"}, {"abl_pl_m", "abl_pl_n"}, {"voc_pl_m", "voc_pl_n"}, {"loc_pl_m", "loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | isahan' output = output .. '\n|class="separator" rowspan="999"|' output = output .. '\n!class="outer" colspan="2" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! l./b.' output = output .. '\n! di-tiyak' output = output .. '\n! l./b.' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. conv[8] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. conv[9] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. conv[10] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. conv[11] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. conv[12] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] output = output .. conv[13] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] output = output .. conv[14] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f(data) local conv = { {"nom_sg_m", "nom_sg_f"}, {"gen_sg_m", "gen_sg_f"}, {"dat_sg_m", "dat_sg_f"}, {"acc_sg_m", "acc_sg_f"}, {"abl_sg_m", "abl_sg_f"}, {"voc_sg_m", "voc_sg_f"}, {"loc_sg_m", "loc_sg_f"}, {"nom_pl_m", "nom_pl_f"}, {"gen_pl_m", "gen_pl_f"}, {"dat_pl_m", "dat_pl_f"}, {"acc_pl_m", "acc_pl_f"}, {"abl_pl_m", "abl_pl_f"}, {"voc_pl_m", "voc_pl_f"}, {"loc_pl_m", "loc_pl_f"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="2" | isahan' output = output .. '\n|class="separator" rowspan="999"|' output = output .. '\n!class="outer" colspan="2" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. conv[8] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. conv[9] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. conv[10] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. conv[11] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. conv[12] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] output = output .. conv[13] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] output = output .. conv[14] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end local function make_table_m_and_f_and_n(data) local conv = { {"nom_sg_m", "nom_sg_f", "nom_sg_n"}, {"gen_sg_m", "gen_sg_f", "gen_sg_n"}, {"dat_sg_m", "dat_sg_f", "dat_sg_n"}, {"acc_sg_m", "acc_sg_f", "acc_sg_n"}, {"abl_sg_m", "abl_sg_f", "abl_sg_n"}, {"voc_sg_m", "voc_sg_f", "voc_sg_n"}, {"loc_sg_m", "loc_sg_f", "loc_sg_n"}, {"nom_pl_m", "nom_pl_f", "nom_pl_n"}, {"gen_pl_m", "gen_pl_f", "gen_pl_n"}, {"dat_pl_m", "dat_pl_f", "dat_pl_n"}, {"acc_pl_m", "acc_pl_f", "acc_pl_n"}, {"abl_pl_m", "abl_pl_f", "abl_pl_n"}, {"voc_pl_m", "voc_pl_f", "voc_pl_n"}, {"loc_pl_m", "loc_pl_f", "loc_pl_n"}, } conv = convert(data, conv) local output = data.title output = output .. '\n\n' output = output .. m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", } output = output .. '\n!class="outer" | ' output = output .. '\n!class="outer" colspan="3" | isahan' output = output .. '\n|class="separator" rowspan="999"|' output = output .. '\n!class="outer" colspan="3" | maramihan' output = output .. '\n|-' output = output .. '\n! ' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n! di-tiyak' output = output .. '\n! panlalaki' output = output .. '\n! pambabae' output = output .. '\n! di-tiyak' output = output .. '\n|- data-case="nom"' output = output .. '\n! [[palagyo]]' output = output .. conv[1] output = output .. conv[8] output = output .. '\n|- data-case="gen"' output = output .. '\n! [[paari]]' output = output .. conv[2] output = output .. conv[9] output = output .. '\n|- data-case="dat"' output = output .. '\n! [[patanggap]]' output = output .. conv[3] output = output .. conv[10] output = output .. '\n|- data-case="acc"' output = output .. '\n! [[palayon]]' output = output .. conv[4] output = output .. conv[11] output = output .. '\n|- data-case="abl"' output = output .. '\n! [[palayo]]' output = output .. conv[5] output = output .. conv[12] output = output .. '\n|- data-case="voc"' output = output .. '\n! [[pabanggit]]' output = output .. conv[6] output = output .. conv[13] if data.loc then output = output .. '\n|- data-case="loc"' output = output .. '\n! [[panlunan]]' output = output .. conv[7] output = output .. conv[14] end output = output .. '\n' .. m_inflection_table.make_bottom{} if data.footnotes and data.footnotes ~= '' then output = output .. '\n' .. data.footnotes end return output end function export.make_table(data) local forms, output = data.forms if not forms.nom_sg_n and not forms.nom_pl_n then if forms.nom_sg_f or forms.nom_pl_f then if data.num == "pl" then output = make_table_m_and_f_pl(data) elseif data.num == "sg" then output = make_table_m_and_f_sg(data) else output = make_table_m_and_f(data) end else local mfonly = data.noneut and not data.nomf if data.num == "pl" then output = make_table_mfn_pl(data, mfonly) elseif data.num == "sg" then output = make_table_mfn_sg(data, mfonly) else output = make_table_mfn(data, mfonly) end end elseif data.nomf then if data.num == "pl" then output = make_table_n_pl(data) elseif data.num == "sg" then output = make_table_n_sg(data) else output = make_table_n(data) end elseif not forms.nom_sg_f and not forms.nom_pl_f then if data.num == "pl" then output = make_table_mf_and_n_pl(data) elseif data.num == "sg" then output = make_table_mf_and_n_sg(data) else output = make_table_mf_and_n(data) end else if data.num == "pl" then output = make_table_m_and_f_and_n_pl(data) elseif data.num == "sg" then output = make_table_m_and_f_and_n_sg(data) else output = make_table_m_and_f_and_n(data) end end return output end return export -- For Vim, so we get 4-space tabs -- vim: set ts=4 sw=4 noet: oftfll25kx9rs2k87haelqodaxk69ku Padron:desctree 10 38965 178453 2026-10-27T01:33:31Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:etymology/templates/descendant|descendants_tree}}<noinclude>{{documentation}}</noinclude>' 178453 wikitext text/x-wiki {{#invoke:etymology/templates/descendant|descendants_tree}}<noinclude>{{documentation}}</noinclude> jextvnsqr4try0jwxxcgzfnuubngjor Module:descendants tree 828 38966 178454 2026-10-27T01:35:03Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local export = {} local debug_track_module = "Module:debug/track" local string_pattern_escape_module = "Module:string/patternEscape" local string_remove_comments_module = "Module:string/removeComments" local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function remove_comments(......' 178454 Scribunto text/plain local export = {} local debug_track_module = "Module:debug/track" local string_pattern_escape_module = "Module:string/patternEscape" local string_remove_comments_module = "Module:string/removeComments" local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function remove_comments(...) remove_comments = require(string_remove_comments_module) return remove_comments(...) end local function track(page) --[[Special:WhatLinksHere/Wiktionary:Tracking/descendants tree/PAGE]] return debug_track("descendants tree/" .. page) end local function preview_error(what, entry_name, language_name, reason) mw.log("Could not retrieve " .. what .. " for " .. language_name .. " in the entry [[" .. entry_name .. "]]: " .. reason .. ".") track(what .. " error") end local function get_content_after_senseid(content, entry_name, lang, id) local code = lang:getFullCode() local t_start, t_end -- UGH. We need to set `not_transcluded` to true otherwise the template parser won't find all the templates -- on large pages. We should probably default `not_transcluded` to true in general. for template in require("Module:template parser").find_templates(content, true) do local name = template:get_name() if name == "senseid" then local args = template:get_arguments() if args[1] == code and args[2] == id then t_start = template.index end elseif name == "etymid" then local args = template:get_arguments() if args[1] == code and args[2] == id then t_start = template.index elseif t_start ~= nil and t_end == nil then t_end = template.index end elseif name == "head" or name == "etymon" then local args = template:get_arguments() local id_arg = args.id if args[1] == code and id_arg == id then t_start = template.index elseif id_arg ~= nil and t_start ~= nil and t_end == nil then t_end = template.index end end end if t_start == nil then error("Could not find the correct senseid template in the entry [[" .. entry_name .. "]] (with language " .. code .. " and id '" .. id .. "')") end if t_end == nil then -- terminate on L2 or another "Etymology ..." header -- match L2 and remove it and everything after it content = string.gsub(content:sub(t_start), "\n==[^=].+$", "") -- match Etymology header and remove it and everything after it content = string.gsub(content, "\n===+%s*Etymology.+$", "") return content end return content:sub(t_start, t_end) end function export.get_alternative_forms(lang, entry_name, id, default_separator) local page = mw.title.new(entry_name) local content = page:getContent() local function alt_form_error(reason) preview_error("alternative forms", entry_name, lang:getFullName(), reason) end if not content then -- FIXME, should be an error alt_form_error("nonexistent page") track("alts-nonexistent-page") return "" end local _, index = string.find(content, "==[ \t]*" .. pattern_escape(lang:getFullName()) .. "[ \t]*==") if not index then -- FIXME, should be an error alt_form_error("L2 header for language not found") track("alts-lang-not-found") return "" end if id then content = get_content_after_senseid(content, entry_name, lang, id) index = 0 end local _, next_lang = string.find(content, "\n==[^=\n]+==", index, false) local _, index = string.find(content, "\n(====?=?)[ \t]*Alternative forms[ \t]*%1", index, false) if not index then _, index = string.find(content, "\n(====?=?)[ \t]*Alternative reconstructions[ \t]*%1", index, false) end if not index then -- FIXME, should be an error alt_form_error("'Alternative forms' section for language not found") track("alts-section-not-found") return "" end local langCodeRegex = pattern_escape(lang:getFullCode()) index = string.find(content, "{{alt[ei]?r?|" .. langCodeRegex .. "|[^|}]+", index) if (not index) or (next_lang and next_lang < index) then -- FIXME, should be an error alt_form_error("no 'alt' or 'alter' template in 'Alternative forms' section for language") track("alts-alter-not-found") return "" end local next_section = string.find(content, "\n(=+)[^=]+%1", index) local alternative_forms_section = string.sub(content, index, next_section) local terms_list = {} local altforms = require("Module:alternative forms") for template in require("Module:template parser").find_templates(alternative_forms_section) do if template:get_name() == "alter" then local args = template:get_arguments() if args[1] == lang:getFullCode() then saw_alter = true local formatted_altforms = altforms.display_alternative_forms(args, entry_name, "allow self link", default_separator) table.insert(terms_list, formatted_altforms) end end end if #terms_list == 0 then -- FIXME, should be an error alt_form_error("no terms in 'alt' or 'alter' template in 'Alternative forms' section for language") track("alts-no-terms-in-alter") return "" end return table.concat(terms_list, default_separator or ", ") end function export.get_descendants(lang, entry_name, id, noerror) local page = mw.title.new(entry_name) local content = page:getContent() local namespace = mw.title.getCurrentTitle().nsText local function desc_error(reason) preview_error("descendants", entry_name, lang:getFullName(), reason) end if not content then -- FIXME, should be an error desc_error("nonexistent page") track("desctree-nonexistent-page") return "" end -- Ignore HTML comments, columns and blank lines. content = remove_comments(content) :gsub("{{top%d}}%s", "") :gsub("{{mid%d}}%s", "") :gsub("{{bottom}}%s", "") :gsub("\n?{{(desc?%-%l+)|?[^}]*}}", function (template_name) if template_name == "desc-top" or template_name == "desc-bottom" or template_name == "des-top" or template_name == "des-mid" or template_name == "des-bottom" then return "" end end) :gsub("\n%s*\n", "\n") local _, index = string.find(content, "%f[^\n%z]==[ \t]*" .. lang:getFullName() .. "[ \t]*==", nil, true) if not index then _, index = string.find(content, "%f[^\n%z]==[ \t]*" .. pattern_escape(lang:getFullName()) .. "[ \t]*==", nil, false) end if not index then desc_error("L2 header for language not found") -- FIXME, should be an error track("desctree-lang-not-found") return "" end if id then content = get_content_after_senseid(content, entry_name, lang, id) index = 0 end local _, next_lang = string.find(content, "\n==[^=\n]+==", index, false) local _, index = string.find(content, "\n(====*)[ \t]*Descendants[ \t]*%1", index, false) local function desctree_no_descendants(with_lang_in_error) if noerror and (namespace == "" or namespace == "Reconstruction") then track("desctree-no-descendants") return "<small class=\"error previewonly\">(" .. "Please either change this template to {{desc}} " .. "or insert a ====Descendants==== section in [[" .. entry_name .. "#" .. lang:getFullName() .. "]])</small>" .. "[[Category:" .. lang:getFullName() .. " descendants to be fixed in desctree]]" else error(("No Descendants section was found in the entry [[%s]]%s"):format(entry_name, with_lang_in_error and (" under the header for %s"):format(lang:getFullName()) or "")) end end if not index then return desctree_no_descendants() elseif next_lang and next_lang < index then return desctree_no_descendants("with lang in error") end -- Skip past final equals sign. index = index + 1 -- Skip past spaces or tabs. while true do local new_index = string.match(content, "^[ \t]+()", index) if not new_index then break end index = new_index end local items = require("Module:array")() local frame = mw.getCurrentFrame() local previous_list_markers = "" -- Skip paragraphs at beginning of Descendants section. while true do local new_index = content:match("^\n[^%*:=][^\n]*()", index) if not new_index then break else index = new_index end end previous_index = 1 -- Find a consecutive series of list items that begins directly after the -- Descendants header. -- start_index and previous_index are used to check that list items are -- consecutive. for start_index, list_markers, item, index in string.gmatch(content:sub(index), "()\n([%*:]+) *([^\n]+)()") do if start_index ~= previous_index then break end -- Preprocess, but replace recursive calls to avoid template loop errors item = string.gsub(item, "{{desctree|", "{{#invoke:etymology/templates/descendant|descendants_tree|") item = frame:preprocess(item) local difference = #list_markers - #previous_list_markers if difference > 0 then for i = #previous_list_markers + 1, #list_markers do items:insert(list_markers:sub(i, i) == "*" and "<ul>" or "<dl>") end else if difference < 0 then for i = #previous_list_markers, #list_markers + 1, -1 do items:insert(previous_list_markers:sub(i, i) == "*" and "</li></ul>" or "</dd></dl>") end else items:insert(previous_list_markers:sub(-1, -1) == "*" and "</li>" or "</dd>") end if previous_list_markers:sub(#list_markers, #list_markers) ~= list_markers:sub(-1, -1) then items:insert(list_markers:sub(-1, -1) == "*" and "</dl><ul>" or "</ul><dl>") end end items:insert(list_markers:sub(-1, -1) == "*" and "<li>" or "<dd>") items:insert(item) previous_list_markers = list_markers previous_index = index end for i = #previous_list_markers, 1, -1 do items:insert(previous_list_markers:sub(i, i) == "*" and "</li></ul>" or "</dd></dl>") end return items:concat() end return export pqx7k3asjvcuripstqlhxn72h8o44nv Padron:Singular of 10 38967 178470 2026-10-27T02:43:43Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{ {{#if:{{{lang|}}}|check deprecated lang param usage|no deprecated lang param usage}}|lang={{{lang|}}}|<!-- -->{{#invoke:form of/templates|tagged_form_of_t|s}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178470 wikitext text/x-wiki {{ {{#if:{{{lang|}}}|check deprecated lang param usage|no deprecated lang param usage}}|lang={{{lang|}}}|<!-- -->{{#invoke:form of/templates|tagged_form_of_t|s}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> s5eaou4312nq5boevjlvoe6kgrv9gux Padron:singular of 10 38968 178472 2026-10-27T02:44:18Z GinawaSaHapon 3989 Ikinakarga sa [[Padron:Singular of]] 178472 wikitext text/x-wiki #REDIRECT [[Padron:Singular of]] 3oew754bol3lbhy7dlhlnxp4fgzryaz Padron:la-ndecl 10 38969 178473 2026-10-27T02:45:07Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:la-nominal|show_noun}}<!-- --><noinclude>{{documentation}}</noinclude>' 178473 wikitext text/x-wiki {{#invoke:la-nominal|show_noun}}<!-- --><noinclude>{{documentation}}</noinclude> c753w8bv6dkpq9kxqmf0yw4193qew64 Module:la-noun/table 828 38970 178474 2026-10-27T02:50:20Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local export = {} local m_inflection_table = require("Module:inflection-table") local Array = require 'Module:array' local function add_forms(wikitable, forms) if type(wikitable) ~= 'string' then error('Expected string, got ' .. type(wikitable)) end wikitable = wikitable:gsub('{{{([^}]+)}}}', forms) return wikitable end function export.make_table_sg(data) local output = Array(data.title, m_inflection_table.make_top{ title = '-', palette = 'cyan',...' 178474 Scribunto text/plain local export = {} local m_inflection_table = require("Module:inflection-table") local Array = require 'Module:array' local function add_forms(wikitable, forms) if type(wikitable) ~= 'string' then error('Expected string, got ' .. type(wikitable)) end wikitable = wikitable:gsub('{{{([^}]+)}}}', forms) return wikitable end function export.make_table_sg(data) local output = Array(data.title, m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", }) output:insert [=[ |- class="outer" ! ! isahan |- data-case="nom" ! palagyo | data-accel-col=1 | {{{nom_sg}}} |- data-case="gen" ! paari | data-accel-col=1 | {{{gen_sg}}} |- data-case="dat" ! patanggap | data-accel-col=1 | {{{dat_sg}}} |- data-case="acc" ! palayon | data-accel-col=1 | {{{acc_sg}}} |- data-case="abl" ! palayo | data-accel-col=1 | {{{abl_sg}}} |- data-case="voc" ! pabanggit | data-accel-col=1 | {{{voc_sg}}}]=] if data.forms.loc_sg then output:insert [=[ |- data-case="loc" ! panlunan | data-accel-col=1 | {{{loc_sg}}}]=] end output:insert('\n') output:insert(m_inflection_table.make_bottom{}) if data.footnotes and data.footnotes ~= '' then output:insert('\n' .. data.footnotes) end return add_forms(output:concat(), data.forms) end function export.make_table_pl(data) local output = Array(data.title, m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", }) output:insert [=[ |- class="outer" ! ! maramihan |- data-case="nom" ! palagyo | data-accel-col=1 | {{{nom_pl}}} |- data-case="gen" !paari | data-accel-col=1 | {{{gen_pl}}} |- data-case="dat" ! patanggap | data-accel-col=1 | {{{dat_pl}}} |- data-case="acc" ! palayon | data-accel-col=1 | {{{acc_pl}}} |- data-case="abl" ! palayo | data-accel-col=1 | {{{abl_pl}}} |- data-case="voc" ! pabanggit | data-accel-col=1 | {{{voc_pl}}}]=] if data.forms.loc_pl then output:insert [=[ |- data-case="loc" ! panlunan | data-accel-col=1 | {{{loc_pl}}}]=] end output:insert('\n') output:insert(m_inflection_table.make_bottom{}) if data.footnotes and data.footnotes ~= '' then output:insert('\n' .. data.footnotes) end return add_forms(output:concat(), data.forms) end function export.make_table(data) local output = Array(data.title, m_inflection_table.make_top{ title = '-', palette = 'cyan', class = 'sticky-left-column', lang = "la", }) output:insert [=[ |- class="outer" ! ! isahan ! maramihan |- data-case="nom" ! palagyo | data-accel-col=1 | {{{nom_sg}}} | data-accel-col=2 | {{{nom_pl}}} |- data-case="gen" !paari | data-accel-col=1 | {{{gen_sg}}} | data-accel-col=2 | {{{gen_pl}}} |- data-case="dat" ! patanggap | data-accel-col=1 | {{{dat_sg}}} | data-accel-col=2 | {{{dat_pl}}} |- data-case="acc" ! palayon | data-accel-col=1 | {{{acc_sg}}} | data-accel-col=2 | {{{acc_pl}}} |- data-case="abl" ! palayo | data-accel-col=1 | {{{abl_sg}}} | data-accel-col=2 | {{{abl_pl}}} |- data-case="voc" ! pabanggit | data-accel-col=1 | {{{voc_sg}}} | data-accel-col=2 | {{{voc_pl}}}]=] if data.forms.loc_sg or data.forms.loc_pl then output:insert [=[ |- data-case="loc" ! panlunan | data-accel-col=1 | {{{loc_sg}}} | data-accel-col=2 | {{{loc_pl}}}]=] end output:insert('\n') output:insert(m_inflection_table.make_bottom{}) if data.footnotes and data.footnotes ~= '' then output:insert('\n' .. data.footnotes) end return add_forms(output:concat(), data.forms) end return export j5nu20xb5hsrjczl1mntgmth6jjnjj9 Padron:R:itc:EDL 10 38971 178475 2026-10-27T02:51:46Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:quote|call_quote_template|en |template=cite-book |last=De Vaan |first=Michiel |authorlink=Michiel de Vaan |entry={{#if:{{{head|{{{1|}}}}}}|la:{{{head|{{{1|}}}}}}}} |title=Etymological Dictionary of Latin and the other Italic Languages |year=2008 |location=Leiden, Boston |publisher=Brill |pageparam=2 |textparam=3 |pageurl=https://www.google.com/books/edition/Etymological_Dictionary_of_Latin_and_the/ecZ1DwAAQBAJ?gbpv=1&pg=PA{{#invoke:ugly hacks|match|{{{p...' 178475 wikitext text/x-wiki {{#invoke:quote|call_quote_template|en |template=cite-book |last=De Vaan |first=Michiel |authorlink=Michiel de Vaan |entry={{#if:{{{head|{{{1|}}}}}}|la:{{{head|{{{1|}}}}}}}} |title=Etymological Dictionary of Latin and the other Italic Languages |year=2008 |location=Leiden, Boston |publisher=Brill |pageparam=2 |textparam=3 |pageurl=https://www.google.com/books/edition/Etymological_Dictionary_of_Latin_and_the/ecZ1DwAAQBAJ?gbpv=1&pg=PA{{#invoke:ugly hacks|match|{{{page|{{{pages|{{{2|}}}}}}}}}|[0-9]+|}} |series=Leiden Indo-European Etymological Dictionary Series |seriesvolume=7 |isbn=978-90-04-16797-1 }}<noinclude>{{documentation}}</noinclude> fazjo3wofukgpskxw04jx20iw5o6dyn Module:Cyrs-translit 828 38972 178476 2026-10-27T02:56:43Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local export = {} local numbers = mw.loadData("Module:Cyrs-translit/numbers") local ugsub = mw.ustring.gsub local toNFC = mw.ustring.toNFC local toNFD = mw.ustring.toNFD local U = mw.ustring.char local umatch = mw.ustring.match local usub = mw.ustring.sub local ulower = mw.ustring.lower local acute = U(0x301) local grave = U(0x300) local circumflex = U(0x302) local kamora = U(0x0311) local palatalization = U(0x0484) local titlo = U(0x0483) local dasia = U(0x04...' 178476 Scribunto text/plain local export = {} local numbers = mw.loadData("Module:Cyrs-translit/numbers") local ugsub = mw.ustring.gsub local toNFC = mw.ustring.toNFC local toNFD = mw.ustring.toNFD local U = mw.ustring.char local umatch = mw.ustring.match local usub = mw.ustring.sub local ulower = mw.ustring.lower local acute = U(0x301) local grave = U(0x300) local circumflex = U(0x302) local kamora = U(0x0311) local palatalization = U(0x0484) local titlo = U(0x0483) local dasia = U(0x0485) local psili = U(0x0486) local pokryt = U(0x0487) local vzmet = U(0xA66F) local kavyka = U(0xA67C) local breve = U(0x306) local breathing = psili .. dasia local accent = "[" .. acute .. grave .. circumflex .. breathing .. "]*" local vowels = "aAæÆeEiIoOœŒꝏꝎuUyY" local common_letters = { ["А"] = 'A', ["а"] = 'a', ["Б"] = 'B', ["б"] = 'b', ["В"] = 'V', ["в"] = 'v', ["Г"] = 'G', ["г"] = 'g', ["Д"] = 'D', ["д"] = 'd', ["Е"] = 'E', ["е"] = 'e', ["Ж"] = 'Ž', ["ж"] = 'ž', ["Ѕ"] = 'Dz', ["ѕ"] = 'dz', ["З"] = 'Z', ["з"] = 'z', ["И"] = 'I', ["и"] = 'i', ["І"] = 'I', ["і"] = 'i', -- Contrastive with "И". ["Й"] = 'J', ["й"] = 'j', ["Ꙉ"] = 'Gʹ', ["ꙉ"] = 'gʹ', ["К"] = 'K', ["к"] = 'k', ["Л"] = 'L', ["л"] = 'l', ["М"] = 'M', ["м"] = 'm', ["Н"] = 'N', ["н"] = 'n', ["О"] = 'O', ["о"] = 'o', ["Ꚙ"] = 'Ꝏ', ["ꚙ"] = 'ꝏ', ["П"] = 'P', ["п"] = 'p', ["Р"] = 'R', ["р"] = 'r', ["С"] = 'S', ["с"] = 's', ["Т"] = 'T', ["т"] = 't', ["У"] = 'U', ["у"] = 'u', ["Ꙋ"] = 'U', ["ꙋ"] = 'u', ["Ф"] = 'F', ["ф"] = 'f', ["Х"] = 'X', ["х"] = 'x', ["Ѡ"] = 'Ō', ["ѡ"] = 'ō', -- Contrastive with "О". ["Ѿ"] = 'Ōt', ["ѿ"] = 'ōt', -- Becomes "otŭ" as appropriate. ["Ѽ"] = 'Ô', ["ѽ"] = 'ô', ["Ц"] = 'C', ["ц"] = 'c', ["Ꙡ"] = 'Cʹ', ["ꙡ"] = 'cʹ', -- From a merger of "Ц" and "Ч" in Old Novgorodian. ["Ч"] = 'Č', ["ч"] = 'č', ["Џ"] = 'Dž', ["џ"] = 'dž', ["Ш"] = 'Š', ["ш"] = 'š', ["Щ"] = 'Št', ["щ"] = 'št', ["Ъ"] = 'Ŭ', ["ъ"] = 'ŭ', ["Ꙏ"] = 'Ü̆', ["ꙏ"] = 'ü̆', ["Ꙑ"] = 'Y', ["ꙑ"] = 'y', ["Ь"] = 'Ĭ', ["ь"] = 'ĭ', ["Ѣ"] = 'Ě', ["ѣ"] = 'ě', ["Ꙓ"] = 'Jě', ["ꙓ"] = 'jě', ["Ю"] = 'Ju', ["ю"] = 'ju', ["Ꙗ"] = 'Ja', ["ꙗ"] = 'ja', ["Ѥ"] = 'Je', ["ѥ"] = 'je', ["Ѧ"] = 'Ę', ["ѧ"] = 'ę', ["Ѫ"] = 'Ǫ', ["ѫ"] = 'ǫ', ["Ѩ"] = 'Ję', ["ѩ"] = 'ję', ["Ѭ"] = 'Jǫ', ["ѭ"] = 'jǫ', ["Ꙛ"] = 'Œ', ["ꙛ"] = 'œ', -- Becomes "œ̨". ["Ѯ"] = 'Ks', ["ѯ"] = 'ks', ["Ѱ"] = 'Ps', ["ѱ"] = 'ps', ["Ѳ"] = 'Θ', ["ѳ"] = 'θ', ["Ѵ"] = 'Ü', ["ѵ"] = 'ü', ["Ѷ"] = 'Ü', ["ѷ"] = 'ü', -- Contrastive with "Ѵ". ["Ꙟ"] = 'În', ["ꙟ"] = 'în', -- it is necessary to make it so that before б, п, м - gives îm ["Ҁ"] = 'Q', ["ҁ"] = 'q', [psili] = '', [kamora] = circumflex, [kavyka] = breve, ["҂"] = '', ["ⷠ"] = '<sup>b</sup>', ["ⷡ"] = '<sup>v</sup>', ["ⷢ"] = '<sup>g</sup>', ["ⷣ"] = '<sup>d</sup>', ["ⷤ"] = '<sup>ž</sup>', ["ⷥ"] = '<sup>z</sup>', ["ⷦ"] = '<sup>k</sup>', ["ⷧ"] = '<sup>l</sup>', ["ⷨ"] = '<sup>m</sup>', ["ⷩ"] = '<sup>n</sup>', ["ⷪ"] = '<sup>o</sup>', ["ⷫ"] = '<sup>p</sup>', ["ⷬ"] = '<sup>r</sup>', ["ⷭ"] = '<sup>s</sup>', ["ⷮ"] = '<sup>t</sup>', ["ⷯ"] = '<sup>x</sup>', ["ⷰ"] = '<sup>c</sup>', ["ⷱ"] = '<sup>č</sup>', ["ⷲ"] = '<sup>š</sup>', ["ⷳ"] = '<sup>št</sup>', ["ⷴ"] = '<sup>θ</sup>', ["ⷵ"] = '<sup>st</sup>', ["ⷶ"] = '<sup>a</sup>', ["ⷷ"] = '<sup>e</sup>', ["ⷸ"] = '<sup>gʹ</sup>', ["ⷹ"] = '<sup>u</sup>', ["ⷺ"] = '<sup>ě</sup>', ["ⷻ"] = '<sup>ju</sup>', ["ⷽ"] = '<sup>ę</sup>', ["ⷾ"] = '<sup>ǫ</sup>', ["ⷿ"] = '<sup>jǫ</sup>', ["ꙴ"] = '<sup>e</sup>', ["ꙵ"] = '<sup>i</sup>', ["ꙶ"] = '<sup>i</sup>', ["ꙷ"] = '<sup>u</sup>', ["ꙸ"] = '<sup>ŭ</sup>', ["ꙹ"] = '<sup>y</sup>', ["ꙺ"] = '<sup>ĭ</sup>', ["ꙻ"] = '<sup>ō</sup>', ["꙽"] = '<sup>ü̆</sup>', } local variants = { ["ᲀ"] = 'в', ["Ґ"] = 'Г', ["ґ"] = 'г', -- ["Ђ"] = 'Ꙉ', ["ђ"] = 'ꙉ', ["ᲁ"] = 'д', ["Ꙣ"] = 'Д' .. palatalization, ["ꙣ"] = 'д' .. palatalization, ["Є"] = 'Е', ["є"] = 'е', ["Э"] = 'Е', ["э"] = 'е', ["Ꙃ"] = 'Ѕ', ["ꙃ"] = 'ѕ', ["Ꙅ"] = 'Ѕ', ["ꙅ"] = 'ѕ', ["Ꙁ"] = 'З', ["ꙁ"] = 'з', ["Ӥ"] = 'И', ["ӥ"] = 'и', ["Ї"] = 'І', ["ї"] = 'і', ["Ꙇ"] = 'І', ["ꙇ"] = 'і', -- ["Ћ"] = 'Ꙉ', ["ћ"] = 'ꙉ', ["Ꙥ"] = 'Л' .. palatalization, ["ꙥ"] = 'л' .. palatalization, ["Ꙧ"] = 'М' .. palatalization, ["ꙧ"] = 'м' .. palatalization, ["Ҥ"] = 'Н' .. palatalization, ["ҥ"] = 'н' .. palatalization, ["Ѻ"] = 'О', ["ѻ"] = 'о', ["Ꙩ"] = 'О', ["ꙩ"] = 'о', ["Ꙫ"] = 'О', ["ꙫ"] = 'о', ["Ꚛ"] = 'О', ["ꚛ"] = 'о', ["Ꙭ"] = 'Ꚙ', ["ꙭ"] = 'ꚙ', ["ꙮ"] = 'о', ["ᲂ"] = 'о', ["ᲃ"] = 'с', ["ᲄ"] = 'т', ["ᲅ"] = 'т', ["Ѹ"] = 'Ꙋ', ["ѹ"] = 'ꙋ', ["ᲈ"] = 'ꙋ', ["Ꙍ"] = 'Ѡ', ["ꙍ"] = 'ѡ', ["Ы"] = 'Ꙑ', ["ы"] = 'ꙑ', ["ᲆ"] = 'ъ', ["ꙿ"] = 'ꙏ', ["ᲇ"] = 'ѣ', ["Я"] = 'Ꙗ', ["я"] = 'ꙗ', ["Ꙕ"] = 'Ю', ["ꙕ"] = 'ю', ["Ꙙ"] = 'Ѧ', ["ꙙ"] = 'ѧ', ["Ꙝ"] = 'Ѩ', ["ꙝ"] = 'ѩ', } -- A second round of substitutions, e.g. if the final output isn't a precomposed character, but needs to behave like one during processing. local final_substitutions = { ["Œ"] = "Œ̨", ["œ"] = "œ̨", [titlo] = ":", [pokryt] = "<sup>:</sup>", [vzmet] = ":" } -- Letters converted to their iotated equivalents when word-initial. local common_iotated_initial = { ["Ѣ"] = 'Ꙓ', ["ѣ"] = 'ꙓ', } -- Letters converted to their iotated equivalents after vowels. local common_iotated_after_vowel = { ["Е"] = 'Ѥ', ["е"] = 'ѥ', ["Ѣ"] = 'Ꙓ', ["ѣ"] = 'ꙓ', ["Ѧ"] = 'Ѩ', ["ѧ"] = 'ѩ', } local lang_letters = {} local lang_iotated_initial = {} local lang_iotated_after_vowel = {} local uo_is_u = {} -- Old East Slavic lang_letters["orv"] = setmetatable({ ["Ѕ"] = 'Z', ["ѕ"] = 'z', ["Щ"] = 'Šč', ["щ"] = 'šč', ["ⷳ"] = '<sup>šč</sup>', }, {__index = common_letters}) lang_iotated_initial["orv"] = setmetatable({ ["Е"] = 'Ѥ', ["е"] = 'ѥ', ["Ѧ"] = 'Ѩ', ["ѧ"] = 'ѩ', }, {__index = common_iotated_initial}) -- Old Novgorodian lang_letters["zle-ono"] = setmetatable({ ["Ѕ"] = 'Z', ["ѕ"] = 'z', ["Ц"] = 'Cʹ', ["ц"] = 'cʹ', ["Ч"] = 'Cʹ', ["ч"] = 'cʹ', ["Щ"] = 'Scʹ', ["щ"] = 'scʹ', ["ⷰ"] = '<sup>cʹ</sup>', ["ⷱ"] = '<sup>cʹ</sup>', ["ⷳ"] = '<sup>scʹ</sup>', }, {__index = common_letters}) lang_iotated_initial["zle-ono"] = lang_iotated_initial["orv"] uo_is_u["zle-ono"] = true -- Old Pskovian lang_letters["zle-ops"] = setmetatable({ -- In addition to zle-ono above. ["Щ"] = 'Śk', ["щ"] = 'śk', ["Ѣ"] = 'Æ', ["ѣ"] = 'æ', ["Ꙓ"] = 'Jæ', ["ꙓ"] = 'jæ', ["ⷳ"] = '<sup>śk</sup>', }, {__index = lang_letters["zle-ono"]}) lang_iotated_initial["zle-ops"] = setmetatable({ -- In addition to zle-ono above. ["Ѫ"] = 'Ѭ', ["ѫ"] = 'ѭ', }, {__index = lang_iotated_initial["zle-ono"]}) lang_iotated_after_vowel["zle-ops"] = setmetatable({ ["Ѫ"] = 'Ѭ', ["ѫ"] = 'ѭ', }, {__index = common_iotated_after_vowel}) uo_is_u["zle-ops"] = true local function handle_v(prev, v) return prev .. (v == "Ѵ" and "В" or "в") end local function handle_ou(o, ac) return (ulower(o) == o and "у" or "У") .. ac end local function handle_rough_breathing(base1, base2, diacritics) -- Mark rough breathing with "h". local base2_lower = ulower(base2) if not vowels:match(base2_lower) then return base1 .. base2 .. diacritics .. "h" end local base1_lower = ulower(base1) if not vowels:match(base1_lower) then return base1 .. (base2_lower == base2 and "h" or "H") .. base2_lower .. diacritics end return (base1_lower == base1 and "h" or "H") .. base1 .. base2 .. diacritics end function export.tr(text, lang, sc) if not sc then sc = require("Module:languages").getByCode(lang, nil, true):findBestScript(text):getCode() end if sc ~= "Cyrs" then return nil end local input = text -- Decompose any acute and grave accents. text = ugsub(toNFD(text), "[^" .. acute .. grave .. "]+", toNFC) -- Canonicalize any variants. text = text:gsub(".[\128-\191]*", variants) if lang == "zle-ono" or lang == "zle-ops" then text = ugsub(text, "([ꙠꙡЦцЧчЩщ])([ꙖꙗѤѥꙒꙓѨѩѬѭЮю])", function (consonant, vowel) return consonant..({ ["Ꙗ"] = 'А', ["ꙗ"] = 'а', ["Ѥ"] = 'Е', ["ѥ"] = 'е', ["Ꙓ"] = 'Ѣ', ["ꙓ"] = 'ѣ', ["Ѩ"] = 'Ѧ', ["ѩ"] = 'ѧ', ["Ѭ"] = 'Ѫ', ["ѭ"] = 'ѫ', ["Ю"] = 'У', ["ю"] = 'у', })[vowel] end) text = ugsub(text, "([жЖ][гГ])", "%1"..palatalization) text = ugsub(text, "([ГгКкХх])([Вв]?[ИиІіЬьѢѣѴѵ])", "%1"..palatalization.."%2") end if lang == "zle-ops" then text = ugsub(text, "([ЗзЖжСсШшѮѯѰѱЅѕЏџ])([ИиІіЬьѢѣѦѧАаЕе])", function(consonant, vowel) consonant = ({ ["Ж"] = "З", ["ж"] = "з", ["Ш"] = "С", ["ш"] = "с", ["Џ"] = "Ѕ", ["џ"] = "ѕ", })[consonant] or consonant return consonant..palatalization..vowel end) end -- Transliterate the palatalization mark as prime. text = text:gsub(palatalization, "ʹ") -- Treat "Ѵ" as the consonant "В" (transliterated "V") in diphthongs that -- correspond to Ancient Greek "αυ", "ευ" and "ηυ" (equivalent to "аѵ", "еѵ" -- and "иѵ"). Note that "ιυ" ("іѵ") is not a diphthong, and "ου" ("оѵ") is -- a long vowel. However, this doesn't apply to "Ѷ", as the diacritic means -- it must be treated as a vowel. text = ugsub(text, "([аАеЕиИꙗꙖѥѤ]" .. accent .. ")([ѵѴ])", handle_v) local letters = lang_letters[lang] or common_letters -- Convert "ѿ" to "ѡт" if followed by a non-iotated vowel (including those -- which iotate only after vowels) or a palatalization mark, and "ѡтъ" in -- all other cases. text = ugsub(text, "([ѿѾ])(" .. accent .. ")()", function(ot, ac, loc) ot = (ot == "Ѿ" and "Ѡ" or "ѡ") .. ac .. "т" local nxt = toNFD(usub(text, loc, loc):gsub(".[\128-\191]*", letters)) if not umatch(nxt, "^[" .. vowels .. "ʹ]") then ot = ot .. "ъ" end return ot end) -- Handle any vowels which are iotated at the start of words. local iotated_initial = lang_iotated_initial[lang] or common_iotated_initial -- Not possible to input iotated_initial directly, as mw.ustring.gsub -- doesn't respect metamethods... text = ugsub(text, "^.", function (m) return iotated_initial[m] end) text = ugsub(text, "([^-%(%)%[%]%{%}…%w])(.)", function (a, b) local iotated = iotated_initial[b] or b return a..iotated end) -- Handle any vowels which are iotated after another vowel. local iotated_after_vowel = lang_iotated_after_vowel[lang] or common_iotated_after_vowel text = ugsub(text, "()(" .. accent .. ")(.)", function(loc, ac, letter) local iotated = iotated_after_vowel[letter] if iotated then loc = loc - 1 local prev = toNFD((loc == 0 and "" or usub(text, loc, loc)):gsub(".[\128-\191]*", letters)) if umatch(prev, "[" .. vowels .. "]%W*$") then return ac .. iotated end end end) -- Treat "ъі" as "ꙑ", and make "ъ" tense ("ŷ") before "и" or an iotated -- vowel. text = ugsub(text, "([Ъъ])(" .. accent .. ")()([иИіІ]?)", function(yer, ac, loc, i) local nxt = toNFD(usub(text, loc, loc):gsub(".[\128-\191]*", letters)):match("^[iIjJ]") if nxt ~= nil then return (yer == "Ъ" and "Ꙑ" or "ꙑ") .. ((i == "і" or i == "І") and ac or circumflex .. ac .. i) end end) -- In some languages, treat "уо" ("uo") as "у" ("u"). if uo_is_u[lang] then -- Not "ꚙ", which is an orthographically doubled "о". text = ugsub(text, "([уУѵѴѷѶ]" .. accent .. ")[оО]", "%1") end -- гг transliterated as нг text = ugsub(text, "([гГ])(["..titlo.."]?[гГ])", function (a, b) return ({ ["г"] = "н", ["Г"] = "Н" })[a] .. b end) -- Treat "оу" ("ou") as "у" ("u") (but not "ꚙ"). text = ugsub(text, "([оО])(" .. accent .. ")[уУѵѴѷѶ]", handle_ou) -- Substitute any numbers. for key, repl in pairs(numbers) do text = ugsub(text, key, repl) end -- Main substitution. text = text:gsub(".[\128-\191]*", letters) -- Handle any rough breathing marks. -- FIXME: this can't handle various edge cases. text = ugsub(toNFD(text), "(%w)(%w?)([^%w%s]*)[" .. dasia .. "]", handle_rough_breathing) if umatch(text, "[" .. breathing .. "]") then error("Invalid breathing marks in input " .. mw.dumpObject(input)) end -- Final substitutions. text = text:gsub(".[\128-\191]*", final_substitutions) return toNFC(text) end return export f6dgara84a1t0m8qnj77rbg6mzmukvm Module:Cyrs-translit/numbers 828 38973 178478 2026-10-27T02:57:39Z GinawaSaHapon 3989 Nilikha ang pahina na may 'return { ["[:·.]а҃[.·:]"] = "1", ["[:·.]в҃[.·:]"] = "2", ["[:·.]г҃[.·:]"] = "3", ["[:·.]д҃[.·:]"] = "4", ["[:·.]е҃[.·:]"] = "5", ["[:·.]є҃[.·:]"] = "5", ["[:·.]ѕ҃[.·:]"] = "6", ["[:·.]ꙅ҃[.·:]"] = "6", ["[:·.]з҃[.·:]"] = "7", ["[:·.]ꙁ҃[.·:]"] = "7", ["[:·.]и҃[.·:]"] = "8", ["[:·.]ѳ҃[.·:]"] = "9", ["[:·.]і҃[.·:]"] = "10", ["[:·.]а҃і[.·:]"] = "11", ["[:·.]в҃і[.·:]"] = "12", ["[:·.]г҃...' 178478 Scribunto text/plain return { ["[:·.]а҃[.·:]"] = "1", ["[:·.]в҃[.·:]"] = "2", ["[:·.]г҃[.·:]"] = "3", ["[:·.]д҃[.·:]"] = "4", ["[:·.]е҃[.·:]"] = "5", ["[:·.]є҃[.·:]"] = "5", ["[:·.]ѕ҃[.·:]"] = "6", ["[:·.]ꙅ҃[.·:]"] = "6", ["[:·.]з҃[.·:]"] = "7", ["[:·.]ꙁ҃[.·:]"] = "7", ["[:·.]и҃[.·:]"] = "8", ["[:·.]ѳ҃[.·:]"] = "9", ["[:·.]і҃[.·:]"] = "10", ["[:·.]а҃і[.·:]"] = "11", ["[:·.]в҃і[.·:]"] = "12", ["[:·.]г҃і[.·:]"] = "13", ["[:·.]д҃і[.·:]"] = "14", ["[:·.]е҃і[.·:]"] = "15", ["[:·.]є҃і[.·:]"] = "15", ["[:·.]ѕ҃і[.·:]"] = "16", ["[:·.]ꙅ҃і[.·:]"] = "16", ["[:·.]з҃і[.·:]"] = "17", ["[:·.]ꙁ҃і[.·:]"] = "17", ["[:·.]и҃і[.·:]"] = "18", ["[:·.]ѳ҃і[.·:]"] = "19", ["[:·.]к҃[.·:]"] = "20", ["[:·.]к҃а[.·:]"] = "21", ["[:·.]к҃в[.·:]"] = "22", ["[:·.]к҃г[.·:]"] = "23", ["[:·.]к҃д[.·:]"] = "24", ["[:·.]к҃е[.·:]"] = "25", ["[:·.]к҃є[.·:]"] = "25", ["[:·.]к҃ѕ[.·:]"] = "26", ["[:·.]к҃ꙅ[.·:]"] = "26", ["[:·.]к҃з[.·:]"] = "27", ["[:·.]к҃ꙁ[.·:]"] = "27", ["[:·.]к҃и[.·:]"] = "28", ["[:·.]к҃ѳ[.·:]"] = "29", ["[:·.]л҃[.·:]"] = "30", ["[:·.]л҃а[.·:]"] = "31", ["[:·.]л҃в[.·:]"] = "32", ["[:·.]л҃г[.·:]"] = "33", ["[:·.]л҃д[.·:]"] = "34", ["[:·.]л҃е[.·:]"] = "35", ["[:·.]л҃є[.·:]"] = "35", ["[:·.]л҃ѕ[.·:]"] = "36", ["[:·.]л҃ꙅ[.·:]"] = "36", ["[:·.]л҃з[.·:]"] = "37", ["[:·.]л҃ꙁ[.·:]"] = "37", ["[:·.]л҃и[.·:]"] = "38", ["[:·.]л҃ѳ[.·:]"] = "39", ["[:·.]м҃[.·:]"] = "40", ["[:·.]м҃а[.·:]"] = "41", ["[:·.]м҃в[.·:]"] = "42", ["[:·.]м҃г[.·:]"] = "43", ["[:·.]м҃д[.·:]"] = "44", ["[:·.]м҃е[.·:]"] = "45", ["[:·.]м҃є[.·:]"] = "45", ["[:·.]м҃ѕ[.·:]"] = "46", ["[:·.]м҃ꙅ[.·:]"] = "46", ["[:·.]м҃з[.·:]"] = "47", ["[:·.]м҃ꙁ[.·:]"] = "47", ["[:·.]м҃и[.·:]"] = "48", ["[:·.]м҃ѳ[.·:]"] = "49", ["[:·.]н҃[.·:]"] = "50", ["[:·.]н҃а[.·:]"] = "51", ["[:·.]н҃в[.·:]"] = "52", ["[:·.]н҃г[.·:]"] = "53", ["[:·.]н҃д[.·:]"] = "54", ["[:·.]н҃е[.·:]"] = "55", ["[:·.]н҃є[.·:]"] = "55", ["[:·.]н҃ѕ[.·:]"] = "56", ["[:·.]н҃ꙅ[.·:]"] = "56", ["[:·.]н҃з[.·:]"] = "57", ["[:·.]н҃ꙁ[.·:]"] = "57", ["[:·.]н҃и[.·:]"] = "58", ["[:·.]н҃ѳ[.·:]"] = "59", ["[:·.]ѯ҃[.·:]"] = "60", ["[:·.]ѯ҃а[.·:]"] = "61", ["[:·.]ѯ҃в[.·:]"] = "62", ["[:·.]ѯ҃г[.·:]"] = "63", ["[:·.]ѯ҃д[.·:]"] = "64", ["[:·.]ѯ҃е[.·:]"] = "65", ["[:·.]ѯ҃є[.·:]"] = "65", ["[:·.]ѯ҃ѕ[.·:]"] = "66", ["[:·.]ѯ҃ꙅ[.·:]"] = "66", ["[:·.]ѯ҃з[.·:]"] = "67", ["[:·.]ѯ҃ꙁ[.·:]"] = "67", ["[:·.]ѯ҃и[.·:]"] = "68", ["[:·.]ѯ҃ѳ[.·:]"] = "69", ["[:·.]о҃[.·:]"] = "70", ["[:·.]о҃а[.·:]"] = "71", ["[:·.]о҃в[.·:]"] = "72", ["[:·.]о҃г[.·:]"] = "73", ["[:·.]о҃д[.·:]"] = "74", ["[:·.]о҃е[.·:]"] = "75", ["[:·.]о҃є[.·:]"] = "75", ["[:·.]о҃ѕ[.·:]"] = "76", ["[:·.]о҃ꙅ[.·:]"] = "76", ["[:·.]о҃з[.·:]"] = "77", ["[:·.]о҃ꙁ[.·:]"] = "77", ["[:·.]о҃и[.·:]"] = "78", ["[:·.]о҃ѳ[.·:]"] = "79", ["[:·.]ѻ҃[.·:]"] = "70", ["[:·.]ѻ҃а[.·:]"] = "71", ["[:·.]ѻ҃в[.·:]"] = "72", ["[:·.]ѻ҃г[.·:]"] = "73", ["[:·.]ѻ҃д[.·:]"] = "74", ["[:·.]ѻ҃е[.·:]"] = "75", ["[:·.]ѻ҃є[.·:]"] = "75", ["[:·.]ѻ҃ѕ[.·:]"] = "76", ["[:·.]ѻ҃ꙅ[.·:]"] = "76", ["[:·.]ѻ҃з[.·:]"] = "77", ["[:·.]ѻ҃ꙁ[.·:]"] = "77", ["[:·.]ѻ҃и[.·:]"] = "78", ["[:·.]ѻ҃ѳ[.·:]"] = "79", ["[:·.]п҃[.·:]"] = "80", ["[:·.]п҃а[.·:]"] = "81", ["[:·.]п҃в[.·:]"] = "82", ["[:·.]п҃г[.·:]"] = "83", ["[:·.]п҃д[.·:]"] = "84", ["[:·.]п҃е[.·:]"] = "85", ["[:·.]п҃є[.·:]"] = "85", ["[:·.]п҃ѕ[.·:]"] = "86", ["[:·.]п҃ꙅ[.·:]"] = "86", ["[:·.]п҃з[.·:]"] = "87", ["[:·.]п҃ꙁ[.·:]"] = "87", ["[:·.]п҃и[.·:]"] = "88", ["[:·.]п҃ѳ[.·:]"] = "89", ["[:·.]ч҃[.·:]"] = "90", ["[:·.]ч҃а[.·:]"] = "91", ["[:·.]ч҃в[.·:]"] = "92", ["[:·.]ч҃г[.·:]"] = "93", ["[:·.]ч҃д[.·:]"] = "94", ["[:·.]ч҃е[.·:]"] = "95", ["[:·.]ч҃є[.·:]"] = "95", ["[:·.]ч҃ѕ[.·:]"] = "96", ["[:·.]ч҃ꙅ[.·:]"] = "96", ["[:·.]ч҃з[.·:]"] = "97", ["[:·.]ч҃ꙁ[.·:]"] = "97", ["[:·.]ч҃и[.·:]"] = "98", ["[:·.]ч҃ѳ[.·:]"] = "99", ["[:·.]ҁ҃[.·:]"] = "90", ["[:·.]ҁ҃а[.·:]"] = "91", ["[:·.]ҁ҃в[.·:]"] = "92", ["[:·.]ҁ҃г[.·:]"] = "93", ["[:·.]ҁ҃д[.·:]"] = "94", ["[:·.]ҁ҃е[.·:]"] = "95", ["[:·.]ҁ҃є[.·:]"] = "95", ["[:·.]ҁ҃ѕ[.·:]"] = "96", ["[:·.]ҁ҃ꙅ[.·:]"] = "96", ["[:·.]ҁ҃з[.·:]"] = "97", ["[:·.]ҁ҃ꙁ[.·:]"] = "97", ["[:·.]ҁ҃и[.·:]"] = "98", ["[:·.]ҁ҃ѳ[.·:]"] = "99", ["[:·.]р҃[.·:]"] = "100", ["[:·.]р҃а[.·:]"] = "101", ["[:·.]р҃в[.·:]"] = "102", ["[:·.]р҃г[.·:]"] = "103", ["[:·.]р҃д[.·:]"] = "104", ["[:·.]р҃е[.·:]"] = "105", ["[:·.]р҃є[.·:]"] = "105", ["[:·.]р҃ѕ[.·:]"] = "106", ["[:·.]р҃ꙅ[.·:]"] = "106", ["[:·.]р҃з[.·:]"] = "107", ["[:·.]р҃ꙁ[.·:]"] = "107", ["[:·.]р҃и[.·:]"] = "108", ["[:·.]р҃ѳ[.·:]"] = "109", ["[:·.]р҃і[.·:]"] = "110", ["[:·.]ра҃і[.·:]"] = "111", ["[:·.]рв҃і[.·:]"] = "112", ["[:·.]рг҃і[.·:]"] = "113", ["[:·.]рд҃і[.·:]"] = "114", ["[:·.]ре҃і[.·:]"] = "115", ["[:·.]рє҃і[.·:]"] = "115", ["[:·.]рѕ҃і[.·:]"] = "116", ["[:·.]рꙅ҃і[.·:]"] = "116", ["[:·.]рз҃і[.·:]"] = "117", ["[:·.]рꙁ҃і[.·:]"] = "117", ["[:·.]ри҃і[.·:]"] = "118", ["[:·.]рѳ҃і[.·:]"] = "119", ["[:·.]р҃к[.·:]"] = "120", ["[:·.]рк҃а[.·:]"] = "121", ["[:·.]рк҃в[.·:]"] = "122", ["[:·.]рк҃г[.·:]"] = "123", ["[:·.]рк҃д[.·:]"] = "124", ["[:·.]рк҃е[.·:]"] = "125", ["[:·.]рк҃є[.·:]"] = "125", ["[:·.]рк҃ѕ[.·:]"] = "126", ["[:·.]рк҃ꙅ[.·:]"] = "126", ["[:·.]рк҃з[.·:]"] = "127", ["[:·.]рк҃ꙁ[.·:]"] = "127", ["[:·.]рк҃и[.·:]"] = "128", ["[:·.]рк҃ѳ[.·:]"] = "129", ["[:·.]р҃л[.·:]"] = "130", ["[:·.]рл҃а[.·:]"] = "131", ["[:·.]рл҃в[.·:]"] = "132", ["[:·.]рл҃г[.·:]"] = "133", ["[:·.]рл҃д[.·:]"] = "134", ["[:·.]рл҃е[.·:]"] = "135", ["[:·.]рл҃є[.·:]"] = "135", ["[:·.]рл҃ѕ[.·:]"] = "136", ["[:·.]рл҃ꙅ[.·:]"] = "136", ["[:·.]рл҃з[.·:]"] = "137", ["[:·.]рл҃ꙁ[.·:]"] = "137", ["[:·.]рл҃и[.·:]"] = "138", ["[:·.]рл҃ѳ[.·:]"] = "139", ["[:·.]р҃м[.·:]"] = "140", ["[:·.]рм҃а[.·:]"] = "141", ["[:·.]рм҃в[.·:]"] = "142", ["[:·.]рм҃г[.·:]"] = "143", ["[:·.]рм҃д[.·:]"] = "144", ["[:·.]рм҃е[.·:]"] = "145", ["[:·.]рм҃є[.·:]"] = "145", ["[:·.]рм҃ѕ[.·:]"] = "146", ["[:·.]рм҃ꙅ[.·:]"] = "146", ["[:·.]рм҃з[.·:]"] = "147", ["[:·.]рм҃ꙁ[.·:]"] = "147", ["[:·.]рм҃и[.·:]"] = "148", ["[:·.]рм҃ѳ[.·:]"] = "149", ["[:·.]р҃н[.·:]"] = "150", ["[:·.]рн҃а[.·:]"] = "151", ["[:·.]рн҃в[.·:]"] = "152", ["[:·.]рн҃г[.·:]"] = "153", ["[:·.]рн҃д[.·:]"] = "154", ["[:·.]рн҃е[.·:]"] = "155", ["[:·.]рн҃є[.·:]"] = "155", ["[:·.]рн҃ѕ[.·:]"] = "156", ["[:·.]рн҃ꙅ[.·:]"] = "156", ["[:·.]рн҃з[.·:]"] = "157", ["[:·.]рн҃ꙁ[.·:]"] = "157", ["[:·.]рн҃и[.·:]"] = "158", ["[:·.]рн҃ѳ[.·:]"] = "159", ["[:·.]р҃ѯ[.·:]"] = "160", ["[:·.]рѯ҃а[.·:]"] = "161", ["[:·.]рѯ҃в[.·:]"] = "162", ["[:·.]рѯ҃г[.·:]"] = "163", ["[:·.]рѯ҃д[.·:]"] = "164", ["[:·.]рѯ҃е[.·:]"] = "165", ["[:·.]рѯ҃є[.·:]"] = "165", ["[:·.]рѯ҃ѕ[.·:]"] = "166", ["[:·.]рѯ҃ꙅ[.·:]"] = "166", ["[:·.]рѯ҃з[.·:]"] = "167", ["[:·.]рѯ҃ꙁ[.·:]"] = "167", ["[:·.]рѯ҃и[.·:]"] = "168", ["[:·.]рѯ҃ѳ[.·:]"] = "169", ["[:·.]р҃о[.·:]"] = "170", ["[:·.]ро҃а[.·:]"] = "171", ["[:·.]ро҃в[.·:]"] = "172", ["[:·.]ро҃г[.·:]"] = "173", ["[:·.]ро҃д[.·:]"] = "174", ["[:·.]ро҃е[.·:]"] = "175", ["[:·.]ро҃є[.·:]"] = "175", ["[:·.]ро҃ѕ[.·:]"] = "176", ["[:·.]ро҃ꙅ[.·:]"] = "176", ["[:·.]ро҃з[.·:]"] = "177", ["[:·.]ро҃ꙁ[.·:]"] = "177", ["[:·.]ро҃и[.·:]"] = "178", ["[:·.]ро҃ѳ[.·:]"] = "179", ["[:·.]р҃ѻ[.·:]"] = "170", ["[:·.]рѻ҃а[.·:]"] = "171", ["[:·.]рѻ҃в[.·:]"] = "172", ["[:·.]рѻ҃г[.·:]"] = "173", ["[:·.]рѻ҃д[.·:]"] = "174", ["[:·.]рѻ҃е[.·:]"] = "175", ["[:·.]рѻ҃є[.·:]"] = "175", ["[:·.]рѻ҃ѕ[.·:]"] = "176", ["[:·.]рѻ҃ꙅ[.·:]"] = "176", ["[:·.]рѻ҃з[.·:]"] = "177", ["[:·.]рѻ҃ꙁ[.·:]"] = "177", ["[:·.]рѻ҃и[.·:]"] = "178", ["[:·.]рѻ҃ѳ[.·:]"] = "179", ["[:·.]р҃п[.·:]"] = "180", ["[:·.]рп҃а[.·:]"] = "181", ["[:·.]рп҃в[.·:]"] = "182", ["[:·.]рп҃г[.·:]"] = "183", ["[:·.]рп҃д[.·:]"] = "184", ["[:·.]рп҃е[.·:]"] = "185", ["[:·.]рп҃є[.·:]"] = "185", ["[:·.]рп҃ѕ[.·:]"] = "186", ["[:·.]рп҃ꙅ[.·:]"] = "186", ["[:·.]рп҃з[.·:]"] = "187", ["[:·.]рп҃ꙁ[.·:]"] = "187", ["[:·.]рп҃и[.·:]"] = "188", ["[:·.]рп҃ѳ[.·:]"] = "189", ["[:·.]р҃ч[.·:]"] = "190", ["[:·.]рч҃а[.·:]"] = "191", ["[:·.]рч҃в[.·:]"] = "192", ["[:·.]рч҃г[.·:]"] = "193", ["[:·.]рч҃д[.·:]"] = "194", ["[:·.]рч҃е[.·:]"] = "195", ["[:·.]рч҃є[.·:]"] = "195", ["[:·.]рч҃ѕ[.·:]"] = "196", ["[:·.]рч҃ꙅ[.·:]"] = "196", ["[:·.]рч҃з[.·:]"] = "197", ["[:·.]рч҃ꙁ[.·:]"] = "197", ["[:·.]рч҃и[.·:]"] = "198", ["[:·.]рч҃ѳ[.·:]"] = "199", ["[:·.]р҃ҁ[.·:]"] = "190", ["[:·.]рҁ҃а[.·:]"] = "191", ["[:·.]рҁ҃в[.·:]"] = "192", ["[:·.]рҁ҃г[.·:]"] = "193", ["[:·.]рҁ҃д[.·:]"] = "194", ["[:·.]рҁ҃е[.·:]"] = "195", ["[:·.]рҁ҃є[.·:]"] = "195", ["[:·.]рҁ҃ѕ[.·:]"] = "196", ["[:·.]рҁ҃ꙅ[.·:]"] = "196", ["[:·.]рҁ҃з[.·:]"] = "197", ["[:·.]рҁ҃ꙁ[.·:]"] = "197", ["[:·.]рҁ҃и[.·:]"] = "198", ["[:·.]рҁ҃ѳ[.·:]"] = "199", ["[:·.]с҃[.·:]"] = "200", ["[:·.]т҃[.·:]"] = "300", ["[:·.]у҃[.·:]"] = "400", ["[:·.]ѵ҃[.·:]"] = "400", ["[:·.]ф҃[.·:]"] = "500", ["[:·.]х҃[.·:]"] = "600", ["[:·.]ѱ҃[.·:]"] = "700", ["[:·.]ѡ҃[.·:]"] = "800", ["[:·.]ѿ҃[.·:]"] = "800", ["[:·.]ц҃[.·:]"] = "900", ["[:·.]ѧ҃[.·:]"] = "900", ["[:·.]҂а[.·:]"] = "1000", ["[:·.]҂в[.·:]"] = "2000", ["[:·.]҂г[.·:]"] = "3000", ["[:·.]҂д[.·:]"] = "4000", ["[:·.]҂е[.·:]"] = "5000", ["[:·.]҂є[.·:]"] = "5000", ["[:·.]҂ѕ[.·:]"] = "6000", ["[:·.]҂ꙅ[.·:]"] = "6000", ["҂ꙅ҃ · х҃ · н҃ꙅ"] = "6657", ["[:·.]҂з[.·:]"] = "7000", ["[:·.]҂и[.·:]"] = "8000", ["[:·.]҂ѳ[.·:]"] = "9000", ["[:·.]҂і[.·:]"] = "10,000", ["[:·.]҂к[.·:]"] = "20,000", ["[:·.]҂л[.·:]"] = "30,000", ["[:·.]҂м[.·:]"] = "40,000", ["[:·.]҂н[.·:]"] = "50,000", ["[:·.]҂ѯ[.·:]"] = "60,000", ["[:·.]҂о[.·:]"] = "70,000", ["[:·.]҂ѻ[.·:]"] = "70,000", ["[:·.]҂п[.·:]"] = "80,000", ["[:·.]҂ч[.·:]"] = "90,000", ["[:·.]҂ҁ[.·:]"] = "90,000", ["[:·.]҂р[.·:]"] = "100,000", ["[:·.]҂с[.·:]"] = "200,000", ["[:·.]҂т[.·:]"] = "300,000", ["[:·.]҂у[.·:]"] = "400,000", ["[:·.]҂ѵ[.·:]"] = "400,000", ["[:·.]҂ф[.·:]"] = "500,000", ["[:·.]҂х[.·:]"] = "600,000", ["[:·.]҂ѱ[.·:]"] = "700,000", ["[:·.]҂ѡ[.·:]"] = "800,000", ["[:·.]҂ѿ[.·:]"] = "800,000", ["[:·.]҂ц[.·:]"] = "900,000", ["[:·.]҂ѧ[.·:]"] = "900,000", ["[:·.]҂҂а[.·:]"] = "1,000,000", } 4ltewyit7vjxqzvdz2wpa193hxznecm Padron:R:ine:IEW 10 38974 178480 2026-10-27T03:16:16Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:quote|call_template |template=cite-book |de |last=Pokorny |first=Julius |authorlink=Julius Pokorny |title=[[w:Indogermanisches etymologisches Wörterbuch|Indogermanisches etymologisches Wörterbuch]] |entry={{{head|}}} |entryurl=https://starling.rinet.ru/cgi-bin/response.cgi?basename=\data\ie\pokorny&method_pages=substring&text_pages={{#invoke:string/templates|match|{{{page|{{{1|{{{pages|}}}}}}}}}|[n0-9]+|}} |location=Bern, München |publisher=Francke V...' 178480 wikitext text/x-wiki {{#invoke:quote|call_template |template=cite-book |de |last=Pokorny |first=Julius |authorlink=Julius Pokorny |title=[[w:Indogermanisches etymologisches Wörterbuch|Indogermanisches etymologisches Wörterbuch]] |entry={{{head|}}} |entryurl=https://starling.rinet.ru/cgi-bin/response.cgi?basename=\data\ie\pokorny&method_pages=substring&text_pages={{#invoke:string/templates|match|{{{page|{{{1|{{{pages|}}}}}}}}}|[n0-9]+|}} |location=Bern, München |publisher=Francke Verlag |year=1959 |page={{{page|{{{1|}}}}}} |pages={{{pages|{{#if:{{{2|}}}|{{{1}}}, {{{2}}}}}}}} |volume={{{vol|{{{volume|{{interval|p={{#invoke:string/templates|match|{{{page|{{{1|{{{pages|0}}}}}}}}}|[n0-9]+|}}|1=1|349=2|771=3}}}}}}}} |pageurl={{#if:{{{page|{{{1|{{{pages|}}}}}}}}}|https://archive.org/details/indogermanisches0<!-- -->{{interval |p={{#invoke:string/templates|match|{{{page|{{{1|{{{pages|}}}}}}}}}|[n0-9]+|}} |1=1pokouoft/page/ |349=2pokouoft/page/n4/ |350=2pokouoft/page/ |771=3pokouoft/page/n4/ |772=3pokouoft/page/n5/ |773=3pokouoft/page/ }}<!-- -->{{#invoke:string/templates|match|{{{page|{{{1|{{{pages|}}}}}}}}}|[n0-9]+|}}<!-- -->/mode/1up?view=theater<!-- -->|}} |allowparams=head,1,page,pages,2,vol,volume }}<!-- --><noinclude>{{refcat}}{{documentation}}</noinclude> igkhdxfu7w0hsdfvt4dw94vlfvv0vyk Padron:interval 10 38975 178481 2026-10-27T03:17:30Z GinawaSaHapon 3989 Nilikha ang pahina na may '<includeonly>{{#invoke:interval|show}}</includeonly><!-- --><noinclude>{{documentation}}[[Category:Control flow templates]]</noinclude>' 178481 wikitext text/x-wiki <includeonly>{{#invoke:interval|show}}</includeonly><!-- --><noinclude>{{documentation}}[[Category:Control flow templates]]</noinclude> kb3un6bnoroefzrzzcfyy5ebdoamhrt Module:interval 828 38976 178482 2026-10-27T03:18:16Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local export = {} function export.show(frame) -- [[mw:Extension:Scirbunto/Lua_reference_manual#Accessing_parameters_from_wikitext]] -- it changes parameters order from original to unpredictable -- example: |p=15|10=1|20=2|30=3 >> |30=3|p=15|20=2|10=1 (1234 >> 4132) local args = frame:getParent().args local p = ( args["p"] and tonumber(args["p"]) or error("Missing parameter 'p' (position-X)") ) local bottom for border in pairs(args) do if border~="p"...' 178482 Scribunto text/plain local export = {} function export.show(frame) -- [[mw:Extension:Scirbunto/Lua_reference_manual#Accessing_parameters_from_wikitext]] -- it changes parameters order from original to unpredictable -- example: |p=15|10=1|20=2|30=3 >> |30=3|p=15|20=2|10=1 (1234 >> 4132) local args = frame:getParent().args local p = ( args["p"] and tonumber(args["p"]) or error("Missing parameter 'p' (position-X)") ) local bottom for border in pairs(args) do if border~="p" and border~="default" then border = tonumber(border) if p >= border then -- this border is bottom if bottom==nil or border > bottom then -- old bottom is farther bottom = border end end end end if bottom==nil then return (args["default"] or "") end bottom = args[tostring(bottom)] if bottom=="@" then return (args["default"] or "") end return bottom end return export ow9fw2s4vj8twc9f4ekdr49ksqj1r8p Padron:R:Nocentini 10 38977 178483 2026-10-27T03:19:22Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:checkparams|error}}<!-- Validate template parameters -->{{#if:{{{hw|}}}|“{{lang|it|{{{hw}}}}}” mula sa:&nbsp;|}}Alberto Nocentini, Alessandro Parenti, “l'Etimologico — Vocabolario della lingua italiana”, Le Monnier, 2010, {{ISBN| 978-88-00-20781-2}}<noinclude>{{documentation}}</noinclude>' 178483 wikitext text/x-wiki {{#invoke:checkparams|error}}<!-- Validate template parameters -->{{#if:{{{hw|}}}|“{{lang|it|{{{hw}}}}}” mula sa:&nbsp;|}}Alberto Nocentini, Alessandro Parenti, “l'Etimologico — Vocabolario della lingua italiana”, Le Monnier, 2010, {{ISBN| 978-88-00-20781-2}}<noinclude>{{documentation}}</noinclude> i7m2xa9wdoz7a2pnsc18h8ev3gxaycr Padron:R:la:L&S 10 38978 178484 2026-10-27T03:20:08Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Charlton T. Lewis and Charles Short<!-- -->|title=[[w:A Latin Dictionary|A Latin Dictionary]]<!-- -->|publisher=Clarendon Press<!-- -->|location=Oxford<!-- -->|year=1879<!-- -->|passage={{{passage|}}}<!-- -->|footer={{#if:{{{footer|}}}|{{small|{{{footer}}}}}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178484 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Charlton T. Lewis and Charles Short<!-- -->|title=[[w:A Latin Dictionary|A Latin Dictionary]]<!-- -->|publisher=Clarendon Press<!-- -->|location=Oxford<!-- -->|year=1879<!-- -->|passage={{{passage|}}}<!-- -->|footer={{#if:{{{footer|}}}|{{small|{{{footer}}}}}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> cfc05fizj9rkyfngcanks6tfh0dmud9 Padron:R:la:Elementary Lewis 10 38979 178489 2026-10-27T05:37:45Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Charlton T. Lewis<!-- -->|title=An Elementary Latin Dictionary<!-- -->|publisher=Harper & Brothers<!-- -->|location=New York<!-- -->|year=1891<!-- -->|passage={{{passage|}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178489 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Charlton T. Lewis<!-- -->|title=An Elementary Latin Dictionary<!-- -->|publisher=Harper & Brothers<!-- -->|location=New York<!-- -->|year=1891<!-- -->|passage={{{passage|}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> 6ugy2v8sztek18iq2z37fqiu56o8s4c Padron:R:la:Gaffiot 10 38980 178490 2026-10-27T05:38:23Z GinawaSaHapon 3989 Nilikha ang pahina na may '“[http://micmap.org/dicfro/search/gaffiot/{{urlencode:{{{url|{{{2|{{{entry|{{{1|{{pagename}}}}}}}}}}}}}}|PATH}} {{{entry|{{{1|{{pagename}}}}}}}}]”, in <!-- -->{{#invoke:quote|call_template |template=cite-book |last=Gaffiot |first=Félix |title=Dictionnaire illustré latin-français |publisher=Hachette |year=1934 |pageparam=p,page,pp |textparam=3 |usenodot=1 |allowparams=url,2,entry,1 |propagateparams=column,columns }}<!-- --><noinclude>{{documentation}}</noin...' 178490 wikitext text/x-wiki “[http://micmap.org/dicfro/search/gaffiot/{{urlencode:{{{url|{{{2|{{{entry|{{{1|{{pagename}}}}}}}}}}}}}}|PATH}} {{{entry|{{{1|{{pagename}}}}}}}}]”, in <!-- -->{{#invoke:quote|call_template |template=cite-book |last=Gaffiot |first=Félix |title=Dictionnaire illustré latin-français |publisher=Hachette |year=1934 |pageparam=p,page,pp |textparam=3 |usenodot=1 |allowparams=url,2,entry,1 |propagateparams=column,columns }}<!-- --><noinclude>{{documentation}}</noinclude> l4uhynn11qbobtjqk7vv7nzz8dhapj0 178515 178490 2026-10-27T06:13:53Z GinawaSaHapon 3989 178515 wikitext text/x-wiki “[http://micmap.org/dicfro/search/gaffiot/{{urlencode:{{{url|{{{2|{{{entry|{{{1|{{pagename}}}}}}}}}}}}}}|PATH}} {{{entry|{{{1|{{pagename}}}}}}}}]”, mula sa <!-- -->{{#invoke:quote|call_template |template=cite-book |last=Gaffiot |first=Félix |title=Dictionnaire illustré latin-français |publisher=Hachette |year=1934 |pageparam=p,page,pp |textparam=3 |usenodot=1 |allowparams=url,2,entry,1 |propagateparams=column,columns }}<!-- --><noinclude>{{documentation}}</noinclude> 6ttmkmbo075xejy27fbhnqfwtlupvn1 Module:R:Perseus/collision-data/EL 828 38981 178491 2026-10-27T05:39:34Z GinawaSaHapon 3989 Nilikha ang pahina na may 'return require("Module:table").listToSet{"a", "A", "abdico", "abscidi", "Academicus", "accensus", "accido", "accisus", "accitus", "acer", "actus", "adeo", "adfectus", "adfinis", "aditus", "adlego", "adolesco", "adsensus", "adsero", "adversum", "adversus", "aedes", "aerarius", "aggero", "agnatus", "agrestis", "alienum", "alienus", "aliquantum", "altum", "ambitus", "amictus", "amicus", "amissus", "amplexus", "animo", "animosus", "annalis", "anus", "apparatus", "app...' 178491 Scribunto text/plain return require("Module:table").listToSet{"a", "A", "abdico", "abscidi", "Academicus", "accensus", "accido", "accisus", "accitus", "acer", "actus", "adeo", "adfectus", "adfinis", "aditus", "adlego", "adolesco", "adsensus", "adsero", "adversum", "adversus", "aedes", "aerarius", "aggero", "agnatus", "agrestis", "alienum", "alienus", "aliquantum", "altum", "ambitus", "amictus", "amicus", "amissus", "amplexus", "animo", "animosus", "annalis", "anus", "apparatus", "appello", "appetitus", "appulsus", "arbitratus", "arcessitus", "armatus", "artus", "ascensus", "aspectus", "aspergo", "assa", "astu", "attactus", "auctus", "auditus", "auguratus", "augustus", "Augustus", "autumnus", "aveo", "aversor", "bene", "beta", "bona", "Bona", "caligo", "calo", "calx", "captus", "cassis", "castra", "catella", "cedo", "cello", "census", "Centaurus", "centuriatus", "centurio", "cereus", "certo", "certum", "ceterum", "cinctus", "circuitus", "circum", "circumiectus", "circumspectus", "cito", "claudo", "claviger", "Cn", "coactus", "coeptus", "cognatus", "combibo", "comitatus", "commentor", "commodum", "communio", "como", "comparatio", "comparo", "compello", "complexus", "compressus", "conatus", "conceptus", "concessus", "concido", "concio", "conditio", "conditor", "conditus", "conflictus", "congestus", "congressus", "coniectus", "conligo", "conquestus", "consensus", "consero", "conspectus", "consterno", "consulto", "contactus", "contemplatus", "contemptus", "contentus", "contextus", "continens", "contingo", "continuo", "conventus", "convictus", "copo", "corneus", "cornum", "cotes", "cruciatus", "cucullus", "cultus", "cum", "cupido", "Cupido", "de", "decem", "decido", "decurio", "decursus", "defectus", "deformo", "deiectus", "delectus", "delego", "deligo", "derisus", "despectus", "despicatus", "dialectica", "dico", "digressus", "dilectus", "dimissus", "dira", "diremptus", "dirigo", "dis", "discessus", "discursus", "dispositus", "dissensus", "dissero", "distentus", "distinctus", "divisus", "divus", "dolo", "domitus", "ductus", "dum", "duo", "ea", "edo", "educo", "effectus", "effero", "egressus", "ei", "electus", "eo", "erro", "esse", "est", "evito", "examen", "excido", "excursus", "exercitus", "exitus", "exorsus", "exortus", "explicatus", "faber", "fastus", "fetus", "fides", "flamen", "fletus", "flexus", "foedus", "foris", "formido", "fraxinus", "fretus", "frons", "fructus", "fucus", "fundo", "furor", "fusus", "galla", "Galla", "gallus", "Gallus", "genuinus", "genus", "gestio", "gestus", "grammatica", "gressus", "habitus", "hau", "haustus", "hic", "hicine", "hoc", "honoratus", "hymenaeus", "Hymenaeus", "iactus", "iam", "ictus", "ignotus", "ilium", "Ilium", "illic", "immensum", "immutatus", "impressus", "impulsus", "imputatus", "incensus", "inceptus", "incertum", "incestus", "inchoo", "incido", "incultus", "incussus", "indago", "indico", "indictus", "indiges", "Indiges", "indutus", "infectus", "inflatus", "inflexus", "infra", "infrenatus", "ingressus", "iniectus", "initus", "iniussus", "inlectus", "inrisus", "inruptus", "insero", "insomnium", "instinctus", "instratus", "instructus", "intectus", "intellectus", "intemptatus", "intentus", "intercido", "interius", "interpositus", "intra", "intro", "invisus", "invocatus", "istic", "iudicatus", "iugis", "iuris", "ius", "iussus", "iuxta", "labellum", "labor", "labrum", "lacertus", "lacto", "laniatus", "lapsus", "latius", "Latius", "latro", "latus", "lectus", "lego", "levatus", "levis", "levitas", "levo", "liber", "liceo", "ligo", "limus", "liquens", "liquor", "litus", "lotus", "lucus", "lustrum", "lusus", "luteus", "lutum", "magis", "magus", "maior", "maius", "Maius", "male", "malum", "malus", "mandatus", "mando", "mane", "manifesto", "mater", "maximus", "medicatus", "medicus", "medius", "melius", "merces", "merito", "meto", "minor", "minus", "missus", "molitus", "monitus", "mora", "moratus", "morsus", "motus", "multa", "multo", "mundus", "murreus", "muto", "narratus", "natus", "ne", "neglectus", "nexus", "nil", "nisus", "nitens", "nitor", "nive", "nixus", "non", "nostri", "notus", "Notus", "num", "obiectus", "oblitus", "obsero", "obsidium", "obtentus", "occasus", "occido", "odoratus", "odos", "oppositus", "optime", "optio", "ora", "ornatus", "orsus", "ortus", "os", "ostentus", "pactus", "palam", "palus", "paratus", "parens", "parilis", "Parilis", "paro", "partus", "passus", "pastus", "pater", "patrius", "patruus", "pecus", "peius", "percussus", "permissus", "perpetuo", "pervolo", "pessime", "physica", "pila", "pilus", "pinna", "plaga", "planus", "plausus", "plecto", "plus", "Poenus", "pone", "populus", "porrectus", "porrigo", "portitor", "positus", "possessus", "post", "potior", "potus", "prae", "praeceps", "praedico", "praegressus", "praepositus", "praesto", "praeter", "praetextus", "pressus", "pro", "processus", "profectus", "progressus", "promptus", "propago", "propter", "prospectus", "proviso", "provisus", "pubes", "pullus", "pulsus", "Pythia", "qua", "quam", "quanto", "quantus", "quassus", "questus", "qui", "quid", "quini", "quinque", "Quirinus", "quiris", "Quiris", "quis", "quo", "quoque", "raptus", "recens", "receptus", "recessus", "recido", "relatus", "relego", "reno", "reor", "repens", "repercussus", "repulsus", "res", "respectus", "retento", "ros", "rubeta", "rudens", "rudis", "rudus", "ruta", "saltus", "salve", "sat", "satio", "satis", "satus", "scitus", "scriptus", "scutula", "se", "se-", "sector", "secundo", "secus", "senatus", "sensus", "sera", "serius", "sero", "serum", "servus", "sex", "sextus", "si", "sibilus", "Sirius", "sis", "situs", "socius", "solum", "sortitus", "specula", "sponsus", "status", "suasus", "subcenturio", "subter", "successus", "succido", "suggestus", "sumptus", "super", "supera", "supra", "suspectus", "suspicio", "susurrus", "tactus", "tam", "tantum", "te", "tempus", "ter", "tertius", "testis", "tortus", "tractus", "traiectus", "tranquillo", "transgressus", "transitus", "transmissus", "tributus", "tritus", "truncus", "turbo", "tute", "tutor", "uber", "ubique", "ultra", "uncus", "unus", "usque", "usucapio", "usus", "ut", "uter", "uti", "utique", "vas", "vel", "verbero", "versus", "verum", "vestitus", "victus", "viscera", "visus", "volgo", "volo"} edwhxzqx1us1kw4ajccnrl9rvfsb9un Padron:R:la:M&A 10 38982 178492 2026-10-27T05:41:29Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{cite-book<!-- -->|author=Carl Meißner<!-- -->|author2=Henry William Auden<!-- -->|title=Latin Phrase-Book<!-- -->|location=London<!-- -->|publisher=[[w:Macmillan Publishers|Macmillan and Co.]]<!-- -->|year=1894<!-- -->|url=https://www.gutenberg.org/files/50280/50280-h/50280-h.htm<!-- -->}}<!-- -->{{#invoke:R:M&A|phrasebook}}<!-- --><!-- --><noinclude>{{documentation}}</noinclude>' 178492 wikitext text/x-wiki {{cite-book<!-- -->|author=Carl Meißner<!-- -->|author2=Henry William Auden<!-- -->|title=Latin Phrase-Book<!-- -->|location=London<!-- -->|publisher=[[w:Macmillan Publishers|Macmillan and Co.]]<!-- -->|year=1894<!-- -->|url=https://www.gutenberg.org/files/50280/50280-h/50280-h.htm<!-- -->}}<!-- -->{{#invoke:R:M&A|phrasebook}}<!-- --><!-- --><noinclude>{{documentation}}</noinclude> apnp7993h87lq7dtktkwi99oij1ltrr Module:R:M&A 828 38983 178493 2026-10-27T05:42:19Z GinawaSaHapon 3989 Nilikha ang pahina na may '--[[ This module provides the front-end to an index of Meissner and Auden's Latin phrasebook. It includes three data modules. The exported function `phrasebook' retrieves the calling template's argument or, if none exists, the calling page's name, and passes this into the table found in "Module:R:M&A/lemmas_no_collision_to_ix_phrase", which yields a set of phrase indices unambiguously containing forms of the given word. These indices are retrieved from th...' 178493 Scribunto text/plain --[[ This module provides the front-end to an index of Meissner and Auden's Latin phrasebook. It includes three data modules. The exported function `phrasebook' retrieves the calling template's argument or, if none exists, the calling page's name, and passes this into the table found in "Module:R:M&A/lemmas_no_collision_to_ix_phrase", which yields a set of phrase indices unambiguously containing forms of the given word. These indices are retrieved from the table in "Module:R:M&A/ix_to_phrase", formatted into a collapsed phrase list, and returned to the caller. When no match is found, an empty string is returned. Approximately 78% of the words in Meissner and Auden's phrase book can be de-stemmed unambigously. Those which cannot are indexed separately in the table exported by this module: "Module:R:M&A/lemmas_collision_to_ix_phrase". The corresponding additional lines are added to the bottom and prefaced with the caption: (ambiguous). If this is too obtrusive they can be perhaps further collapsed. ]]-- local export = {} local special_cases = {["a"]={false}, ["de"]={true}} function print_collapsible_list_html(ls, x) local lst = {} local count = 0 for k,x in pairs(ls) do table.insert(lst, "<li>"..x.."</li>") count = count + 1 end local expandtext = count.." "..x..(count==1 and "" or "s") table.insert(lst, 1, " <div class='mw-collapsible mw-collapsed' style='display: inline' data-expandtext='"..expandtext.."><ul>") table.insert(lst, "</ul></div>") return table.concat(lst) end function map(f, xs) local s = {} if not (xs == nil) then for i,x in pairs(xs) do s[#s+1] = f(x) end end return s end function is_member(xs, i) if (not (xs==nil)) then for k,v in pairs(xs) do if v==i then return true end end end return false end function load_lemma_nc_to_ix(w) --return lemmas_no_collision_to_ix_phrase = mw.loadData("Module:R:M&A/lemmas_no_collision_to_ix_phrase")[w] return require("Module:data tables").index_table("la_RMA_lemmas_no_collision_to_ix_phrase", w) end function print_html(w) local lemmas_collision_to_ix_phrase = mw.loadData("Module:R:M&A/lemmas_collision_to_ix_phrase") --small table, hence loaded unsharded local lsNC, lsC = load_lemma_nc_to_ix(w), lemmas_collision_to_ix_phrase[w] local ls = {} if lsNC then for k,v in pairs(lsNC) do ls[#ls+1] = v end end if lsC then for k,v in pairs(lsC) do ls[#ls+1] = v end end --local ix_to_phrase = mw.loadData("Module:R:M&A/ix_to_phrase") --needs a data_table.select_array function: table_name -> [key] -> (key -> val); TBD local ix_to_phrase = (w=="a" or w=="de") and special_cases[w][1] and require("Module:R:M&A/memory special cases")[w] or require("Module:data tables").index_table_all("la_RMA_index_to_phrases", ls) function print_phrase(i) local pL, pE = ix_to_phrase[i][1], ix_to_phrase[i][2] local prevSubst = 1 local n = 1 while prevSubst > 0 do pL, prevSubst = string.gsub(pL, "_", (n%2==1 and "<i><b>" or "</b></i>"), 1) pE, pS0 = string.gsub(pE, "_", (n%2==1 and "<i>" or "</i>"), 1) prevSubst = prevSubst + pS0 n = n + 1 end pL = string.gsub(pL, "%[%d%]", "") return (is_member(lsC, i) and "<b><i>(malabo)</i></b> " or "").. string.gsub(pE..": "..pL.."<br/>", ".:", ":") end local ls_html = print_collapsible_list_html(map(print_phrase, ls), "phrase") --return true and "True" or "False" return ((ls == nil and "") or ls_html) end function export.phrasebook(frame) local args = frame:getParent().args local w = args[1] or mw.loadData("Module:headword/data").pagename if (not args[1] or args[1] == "") and mw.title.getCurrentTitle().nsText == "Template" then return "" else return print_html(w) end end return export cuo0h5eio4w71g558vo5tm3vvofuyh7 Module:R:M&A/lemmas collision to ix phrase 828 38984 178494 2026-10-27T05:43:08Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local hw_auden_latin_lemmas_no_collision_to_ix_phrase = { ["inscriptio"]={"2414"},["defervesco"]={"2788"},["duplex"]={"1890","4328"},["carendus"]={"2361"},["scala"]={"4394","4395"},["tero"]={"320"},["esurio"]={"626"},["gigno"]={"18","19"},["em"]={"1232"},["cumulus"]={"904","905","2498"},["beatum"]={"908","1151"},["caelestis"]={"102","1929","1930","3043"},["ix"]={"3240","3496"},["vesuvius"]={"145"},["allicio"]={"2662"},["pugna"]={"4435","4436","4439","4440","4608"...' 178494 Scribunto text/plain local hw_auden_latin_lemmas_no_collision_to_ix_phrase = { ["inscriptio"]={"2414"},["defervesco"]={"2788"},["duplex"]={"1890","4328"},["carendus"]={"2361"},["scala"]={"4394","4395"},["tero"]={"320"},["esurio"]={"626"},["gigno"]={"18","19"},["em"]={"1232"},["cumulus"]={"904","905","2498"},["beatum"]={"908","1151"},["caelestis"]={"102","1929","1930","3043"},["ix"]={"3240","3496"},["vesuvius"]={"145"},["allicio"]={"2662"},["pugna"]={"4435","4436","4439","4440","4608","4723"},["opertus"]={"447"},["coniectura"]={"1393","1394","1395","1396","1397","1398","1399"},["honor"]={"3665","3946","3947"},["pecco"]={"2282"},["barba"]={"455"},["nexus"]={"825","1801","2140","2142"},["conformo"]={"1046","1721"},["forensis"]={"3597"},["dux"]={"3780"},["sui"]={"752","1607","1653","1983","2044","2409","2543","2843","2907","3177","3551","3602","3631","3709","3945","3992","3997","4142","4222","4705"},["insitus"]={"1348","3007","3072"},["perfundo"]={"536","647","1291","2497","3047"},["consterno"]={"272"},["includo"]={"2186"},["stabilio"]={"3598"},["petens"]={"1089","1092"},["quemadmodum"]={"2385"},["instituo"]={"1661","1666","2230","3057","3299","4392","4663"},["ineo"]={"202","1037","1105","1470","3279","3460","3726","3932","4276","4460"},["idoneus"]={"129","821","4349","4439","4681"},["merces"]={"1083"},["rusticor"]={"232"},["distinctus"]={"110"},["pes"]={"215","235","515","675","3998","4178","4504"},["summatim"]={"2163"},["modius"]={"3558"},["confectus"]={"595","1857","4587"},["disserendus"]={"1757","1758","1759","1760","1761","1762","1764"},["scaenicus"]={"1961","1962","2002","2038"},["orno"]={"1052","1147","1223","1976","2182","2183","3253","4664"},["obruo"]={"59","920","1575"},["eripio"]={"881","959","1431","2524","2636","3868","4572"},["diurnus"]={"222"},["inflammatio"]={"2704"},["diutius"]={"4752"},["supra"]={"4768"},["ludo"]={"2927"},["longus"]={"210","2393","4751"},["sino"]={"692"},["afflictus"]={"776","912","2534","2588"},["ritus"]={"4513"},["frons"]={"460","461","462","1377"},["benevolus"]={"1028"},["revoco"]={"1547","1550","1580","1616","1774","1785","1920","2023","2797","2965","3395"},["doctissimus"]={"1625","1629","1868"},["punctus"]={"353","3919"},["scriptus"]={"2436","2474"},["gravis"]={"97","671","685","2105","2206","3017","3488","4048","4585"},["loquendus"]={"2286","3329"},["debitus"]={"1059"},["duo"]={"3759","4184"},["nostri"]={"4593"},["solutus"]={"2099","2128","4324"},["aetas"]={"337","338","339","341","345","346","568","575","578","580","581","582","584","585","586","588","590","591","593","596","600","601","605","607","611","619","620","623","625","1289","1609","1678","1679","1695","1896","1897","1899","1901","3012","3644","3956","4165","4167"},["aequalis"]={"603"},["annoto"]={"2439"},["continuatio"]={"1801","2319"},["habito"]={"491","3187","3537"},["censeo"]={"3965","3995"},["aliquis"]={"507","2689","2690","2919","4091"},["abrogo"]={"2710","2740","3693","3943","3944","4235"},["cupiditas"]={"1206","1224","1406","2846","2847","2848","2849","2850","2851","2854","2861","2862","2863","2864","2865","2866","2870"},["hiems"]={"393","394"},["sagatus"]={"3202"},["praeiudicatus"]={"1388"},["familiaris"]={"2289","3168","3172","3173","3251"},["inventor"]={"3707"},["signifer"]={"116"},["curo"]={"368","681","683","2529","3168","3209"},["servio"]={"331","1008","1211","2854","3654"},["gemma"]={"25"},["deditio"]={"4423","4639","4640","4644"},["facetus"]={"2259","2260","2261","2263"},["versio"]={"2310"},["mitto"]={"252","2209","2413","2459","3124","3155","3903","4250","4288"},["spes"]={"1691","1692","2621","2622","2623","2626","2627","2628","2629","2630","2631","2632","2633","2634","2635","2636","2637","2638","2639","2640","2641","2642","2643","2644","2645","2646","2647","2648","2649","2650","2651","2652"},["signatus"]={"3428"},["conspiro"]={"3797"},["nosco"]={"1914"},["tribunicius"]={"3981"},["directus"]={"281"},["consecutus"]={"1522"},["acclamo"]={"2027"},["dicens"]={"2204"},["abduco"]={"1342","1408","2723","2946","3870"},["astrologia"]={"1929"},["iniquus"]={"1124","4349"},["senatus"]={"3975","3976","3983","3984","3985","3986","3987","3988","3989","3992","3999","4000","4001","4002","4003","4005","4006","4610","4635"},["color"]={"2148"},["definitio"]={"1792"},["fabella"]={"3314"},["habeo"]={"317","472","550","615","729","781","803","805","834","850","885","896","980","988","1029","1058","1121","1178","1219","1222","1279","1360","1440","1456","1458","1462","1481","1499","1579","1584","1588","1641","1646","1716","1743","1752","1764","1846","1946","2019","2092","2203","2217","2219","2430","2531","2539","2571","2621","2649","2671","2676","2677","2688","2691","2692","2697","2707","2714","2741","2745","2746","2776","2819","2862","2893","2894","2910","3041","3051","3053","3072","3120","3121","3169","3188","3237","3309","3358","3366","3412","3417","3457","3508","3575","3673","3674","3893","3901","3962","3966","3987","4041","4072","4170","4177","4202","4222","4380","4456","4773","4833"},["pericles"]={"346","347","348"},["commeo"]={"242"},["illuceo"]={"402"},["consideratus"]={"1496"},["fas"]={"4034"},["anglus"]={"557","558"},["repugno"]={"1834","1870","1871","2967"},["iudicatus"]={"4108"},["excello"]={"3767"},["salvus"]={"3702"},["gratiosus"]={"1033","3723"},["satis"]={"360","445","2539","3213","4786"},["mora"]={"1531","1533"},["divortium"]={"3365"},["res"]={"0","1","5","6","7","503","531","532","533","764","765","768","769","772","775","776","781","784","787","788","792","806","808","823","825","826","837","839","840","861","862","867","903","907","912","946","964","974","977","986","992","995","1026","1027","1157","1158","1159","1246","1254","1309","1332","1333","1347","1497","1520","1521","1582","1585","1586","1589","1590","1647","1709","1710","1768","1769","1791","1801","1804","1852","1855","1856","1857","1875","1876","1878","1879","1881","1882","1883","1889","1891","1899","1907","1909","1910","1913","1918","1930","1976","2151","2153","2162","2169","2170","2171","2181","2220","2222","2223","2224","2228","2233","2245","2538","2616","2618","2706","2894","2986","3032","3033","3105","3107","3135","3140","3168","3169","3171","3172","3173","3185","3226","3228","3248","3251","3366","3392","3410","3413","3418","3450","3561","3571","3572","3575","3576","3578","3579","3588","3589","3590","3598","3599","3600","3603","3604","3608","3609","3615","3617","3620","3679","3760","3775","3780","3785","3786","3787","3788","3789","3790","3798","3799","3801","3802","3805","3809","3835","3838","3839","3850","3886","3893","3901","3942","3954","4003","4094","4108","4213","4225","4226","4227","4228","4249","4266","4267","4381","4466","4501","4502","4506","4507","4508","4509","4511","4662","4745","4818","4830","4832","4833"},["via"]={"157","181","190","191","192","193","194","195","196","197","199","200","201","202","204","205","206","207","209","210","211","281","1663","1664","1696","1777","1781","2812","3968"},["terra"]={"9","10","11","15","16","18","19","20","21","90","91","118","164","165","166","177","187","188","215","225","303","304","492","1922","4636","4637","4642","4670","4704","4706","4716","4718"},["iussus"]={"1104"},["consul"]={"3677","3948","3949","3950","3951","3952","3953"},["meditatus"]={"2075"},["cultus"]={"1649","1656","1657","3031"},["apparatus"]={"3267","4264"},["dispergo"]={"4560"},["consumo"]={"319","1240","1253","1283","1610","3432"},["retinendus"]={"2938"},["nutrix"]={"1425"},["perlustro"]={"2152"},["subitus"]={"721","2077","3143"},["vinctus"]={"1978"},["invado"]={"676","2564","3179","4484"},["praeter"]={"2652","2996","3403","4798"},["ingredior"]={"202","215","239","240","279","611","1696","1782","2626","2812","3304"},["reicio"]={"1838","4003","4092","4532"},["inopinans"]={"4333"},["disputandus"]={"1835"},["conceptus"]={"1235"},["pergo"]={"3828","4790"},["sol"]={"103","105","131","147"},["adversor"]={"1007"},["plebeius"]={"3645"},["coerceo"]={"2858","2859","2862","4238","4239"},["extendo"]={"169"},["sitis"]={"632","635","636"},["opinio"]={"1219","1334","1381","1385","1386","1387","1388","1389","1390","1391","2197","3069","3731"},["semis"]={"3476","3477","3479"},["infamia"]={"1216","1231"},["amor"]={"2677","2678","2684","2685","2687","2688"},["non"]={"280","323","368","385","426","427","463","466","514","519","524","651","652","656","691","692","693","804","814","831","847","863","1089","1234","1248","1249","1357","1410","1450","1451","1452","1467","1504","1514","1789","1834","1872","1933","2153","2173","2217","2219","2252","2530","2542","2609","2610","3145","3152","3237","3444","3546","3601","3810","4123","4167","4173","4315","4438","4738","4739","4762","4769","4778","4781","4782","4794"},["accommodate"]={"2088"},["obsero"]={"3165"},["complector"]={"695","1032","1335","2950","4746"},["temperatus"]={"99"},["perturbatus"]={"1803"},["sicilia"]={"3412"},["studiosus"]={"1041","1403","1595","2814","2953","3632","3740","3748"},["peditum"]={"4199"},["felicitas"]={"904","905","906"},["collatus"]={"4503","4504","4505"},["differo"]={"89","326","1535","1789"},["convictus"]={"4059"},["populariter"]={"3783"},["volvo"]={"2411"},["lacteus"]={"115"},["inclaresco"]={"1197"},["pervenio"]={"243","441","476","597","965","1137","1355","1523","2555","2617","3558","3664"},["impertio"]={"1144","3333","3628"},["speculatorius"]={"4734"},["sexus"]={"551"},["vineus"]={"4391"},["questio"]={"1504","2246"},["insecutus"]={"133"},["obligo"]={"1054"},["abhinc"]={"384"},["rogus"]={"762"},["dispono"]={"1766","4344","4454"},["penetro"]={"14"},["nobiscum"]={"3567"},["repugnans"]={"1682"},["figo"]={"492"},["diligentia"]={"1241"},["publica"]={"2730","3568","3571","3572","3575","3576","3579","3580","3581","3582","3583","3588","3589","3590","3591","3592","3598","3600","3601","3602","3604","3605","3606","3607","3608","3609","3610","3611","3615","3617","3622","3623","3624","3755","3758","3760","3784","3789","3790","3798","3799","3800","3801","3802","3839","3886","3901","4045","4096"},["solacium"]={"979","981","985"},["respicio"]={"835"},["bonitas"]={"2826","2827"},["laus"]={"1145","1146","1147","1148","1149","1154","1193","1195","1203","1206","1972","2067","2371"},["sisto"]={"4335"},["dolus"]={"2921","2922"},["grande"]={"1703","2105","3488","3506"},["servus"]={"2029","3176","3651"},["cupio"]={"1044"},["maximus"]={"336","991","1076","1146","1153","2546","2551","2631","3504","4198","4216","4306","4813"},["calamitas"]={"913","914","915","916","918","919","920","921","922"},["restituo"]={"774","1027","3576","3819","3833","3859","3860","4023","4469"},["abeo"]={"287","294","508","712","1182","1570","3829","3940"},["copulo"]={"4729"},["damno"]={"3103","4109","4146","4150"},["poculum"]={"738","3220","3222","3223"},["minor"]={"614","672"},["conatus"]={"1509","1511"},["levissime"]={"4754"},["firmatus"]={"586","588"},["utilitas"]={"830","1003","1004","1006"},["plurimus"]={"3337","3338","4661"},["relaxo"]={"1303","2519"},["applico"]={"1115","1670","1734","1911","2407"},["transcendo"]={"4730"},["eloquens"]={"2064"},["nox"]={"111","408","412","414","3308","4006"},["internus"]={"76"},["experior"]={"893"},["consido"]={"2706","3191","4341"},["gravitas"]={"97"},["captio"]={"1823"},["confluo"]={"245"},["ferio"]={"461","3110","4159","4631"},["proicio"]={"517"},["dupliciter"]={"2371"},["pereo"]={"630","723","742","2419","4594"},["interpello"]={"2204"},["turpis"]={"2809","2810"},["diligens"]={"1403","1912","1921","2277","2938","3174","3175"},["suppedito"]={"570","3230","3231","3232"},["censor"]={"3965"},["praetendo"]={"820"},["nemo"]={"347","1630","1631"},["beneficium"]={"1051","1052","1053","1054","1055","1068","4038"},["iocus"]={"2256","2258"},["obstrictus"]={"2739","3051"},["locuples"]={"4049"},["origo"]={"554","2353","2354"},["edo"]={"547","638","639","716","717","1179","1722","1725","2008","2040","2042","2410","2843","3125","4054","4577","4578"},["ver"]={"391"},["sumptus"]={"743","3232","3239","3240","3241","3242","3243","3244","3245"},["faveo"]={"3089"},["opprimo"]={"4333"},["curriculum"]={"573"},["delecto"]={"1950","2495"},["plenus"]={"2452","2952"},["disputo"]={"1380","1768","1781","1795","1830","1831","1832","1833","2167","2239"},["perfectio"]={"1355","1356","1361"},["exsurgo"]={"2111"},["gradus"]={"274","275","276","277","2605","2607","3657","3658","3659","3660","3661","3663","4309","4335","4482"},["obnoxius"]={"4647"},["suffigo"]={"4161"},["comoedia"]={"1963"},["desertus"]={"42"},["abundantia"]={"992"},["violatus"]={"3059"},["nec"]={"1400","4834"},["carissimus"]={"2477"},["eximo"]={"3817","4004","4090"},["infligo"]={"740","4583","4584"},["ruo"]={"940"},["penso"]={"1066"},["praeruptus"]={"40"},["abdico"]={"3133","3938"},["orbo"]={"499"},["diluo"]={"4093"},["miseria"]={"984"},["luna"]={"105","107"},["evocatus"]={"4182"},["triumphus"]={"4608","4609","4610"},["evello"]={"1447","3081"},["adiaceo"]={"156"},["abripio"]={"4703"},["extermino"]={"3823"},["africus"]={"125"},["ardor"]={"132","2704","2705","2706"},["conspicio"]={"489"},["profero"]={"15","169","423","1180","1706","2174","2442","4054"},["mobilis"]={"3019"},["testor"]={"3092","4816"},["intervallum"]={"180","182","183","360"},["descriptio"]={"396","1915","1922","3569","4028"},["peregrinor"]={"227"},["macula"]={"1235"},["exsibilo"]={"2026"},["intemperans"]={"2857"},["ductus"]={"51","3310"},["abominor"]={"3097"},["sentio"]={"1375","1378","1858","2920","3612","3613","3756","3789","4760"},["lux"]={"399","407","547","548","698","3596"},["fabula"]={"1183","1903","1905","1964","2002","2006","2007","2008","2009","2024","2025","2031","3313","3315"},["praepono"]={"3936"},["varius"]={"927","928"},["hortus"]={"50"},["rostrum"]={"2091","4725"},["eo"]={"235","247","295","333","689","787","938","1174","1520","1527","2213","2416","3563","3623","3828","3829","3998","4064","4327","4369","4372","4373","4733"},["natus"]={"552","555","592","604","606","608","767","1565","1681","2060","3636","3637","3638","3639","3640","3641"},["coniunctivus"]={"2321"},["nescius"]={"1451"},["aequissimus"]={"2600"},["patrius"]={"2285"},["dissuadeo"]={"3682"},["cotidie"]={"1589"},["id"]={"575","1100","1518","1522","1523","1529","1848","2227","2229","2230","2235","2236","2244","3484","4794","4813","4834","4835","4838","4840"},["caput"]={"446","449","450","451","833","957","3256","3330","4095","4814"},["egregius"]={"1237","1692","3613"},["nervus"]={"1261","1262","1980","1981","1985"},["constitutus"]={"430"},["istuc"]={"4820"},["denarius"]={"3558"},["repello"]={"2878","4533"},["sapio"]={"2961"},["summitto"]={"2210","3964","4406","4525","4526"},["contextus"]={"2142"},["lis"]={"4079","4084","4085"},["remitto"]={"122","1304","1615","2519","2817","3363","3367","4031"},["arithmetica"]={"1931"},["ob"]={"1159"},["doceo"]={"1589","1592","1676","1855","1938","1982","2006","3315"},["attollo"]={"93"},["theatrum"]={"2017"},["sacrificium"]={"3104","3108"},["escensio"]={"4717"},["aspectus"]={"155","511","513","528","2150","2151","2156"},["deligo"]={"1695","4157","4439","4710","4713"},["incensus"]={"1206","1612","2684","2693","2700","2783","2806","3106"},["extorqueo"]={"474","1431","4248"},["lator"]={"3708"},["saepe"]={"826","2282"},["convello"]={"3800","4379"},["tribus"]={"3919","3920","3974"},["efficio"]={"4","892","1690","1818","1820","1828","4184","4663"},["ius"]={"589","1680","3869","4007","4008","4009","4010","4011","4012","4013","4014","4015","4028","4029","4032","4033","4034","4036","4037","4038","4613","4836","4837","4838","4841","4842","4844"},["adulescentia"]={"583"},["ferreus"]={"4729"},["vigeo"]={"581","1166","1597"},["domicilium"]={"3188","3190"},["pronuntiatio"]={"2199"},["periculum"]={"894","945","948","949","950","951","952","954","955","956","958","959","960","961","962","963","4501"},["centum"]={"616","4593"},["gusto"]={"1617"},["scisco"]={"3688"},["exerceo"]={"932","1121","1937","2673","3177","3561","3888","4019"},["progrediens"]={"350","584"},["inveterasco"]={"3391"},["exstruo"]={"3523","4355","4392"},["orator"]={"1362","2071","2342"},["ango"]={"2511","2566","2975"},["fulmen"]={"139","140","141","143"},["fautor"]={"3632"},["assiduus"]={"3283"},["documentum"]={"4817"},["nummus"]={"3430","3447","3510"},["cremo"]={"87","752"},["illudo"]={"1139","2928"},["vectigalis"]={"3887","3888","3889","3891","3894"},["procedo"]={"307","804","4304"},["praefero"]={"3964"},["honoratus"]={"3945"},["perspicuus"]={"2086","4808"},["animus"]={"488","490","677","892","1050","1056","1126","1129","1299","1301","1303","1304","1307","1337","1342","1343","1433","1468","1513","1648","1649","1734","1808","2096","2097","2407","2479","2481","2482","2483","2485","2486","2491","2504","2522","2532","2571","2572","2573","2574","2578","2579","2580","2581","2582","2583","2584","2586","2587","2588","2605","2651","2656","2683","2704","2705","2706","2757","2794","2797","2831","2859","2860","2865","2871","2887","2890","2971","3010","3016","3021","3047","3051","3061","3755","4458"},["continuus"]={"2380"},["defensor"]={"4402"},["stativus"]={"4346"},["movens"]={"3185"},["superus"]={"3024"},["convenio"]={"245","1867","3316","3464","3676","4622"},["emendatus"]={"2123"},["domus"]={"3140","3141","3142","3143","3144","3145","3146","3147","3151","3273","3275","3276","3521"},["macto"]={"3110"},["contestatus"]={"1906"},["praetorium"]={"4376","4722"},["auguro"]={"3134"},["divinitus"]={"3044","3045"},["disciplina"]={"1593","1660","1667","1668","1669","1670","1675","1746","1748","1749","1772","4238"},["comminus"]={"4254","4506"},["appellatus"]={"4635"},["incito"]={"73","2849","4695"},["parvus"]={"576","826","2206","2540","3420","3422"},["idiota"]={"1942"},["praeda"]={"4370"},["scelus"]={"2832","2833","2838","2839","2841","2842","2843","2844","2845","2970","2976","4047"},["compello"]={"1737"},["fugo"]={"4543","4546"},["legendus"]={"2446"},["late"]={"27","176"},["exigo"]={"2024","2026","3445","3515","3889"},["catena"]={"4148"},["alicubi"]={"3189","3190","3191"},["alternus"]={"419"},["posterior"]={"625"},["vulgo"]={"1175","2197"},["limo"]={"2434"},["exploro"]={"4310"},["loquor"]={"656","1856","1873","2112","2294","2295","2920","3328","4827"},["decerpo"]={"1712"},["resipisco"]={"2962"},["destringo"]={"4257"},["spargo"]={"1169","3538"},["delicia"]={"1302","2688"},["fateor"]={"4821"},["quidam"]={"4776"},["commeatus"]={"4218"},["uxor"]={"3354","3358","3365","4431"},["inhibeo"]={"4696","4697"},["indago"]={"2354"},["ad"]={"34","36","93","147","149","155","173","174","242","305","306","309","318","321","324","329","330","357","358","381","408","430","435","441","487","490","516","517","518","523","597","617","742","797","801","802","807","818","829","844","845","846","848","849","850","873","884","886","904","907","909","930","935","939","940","950","964","965","971","972","995","1004","1006","1012","1013","1046","1048","1049","1102","1115","1116","1137","1171","1224","1239","1242","1245","1284","1307","1325","1341","1344","1347","1353","1355","1373","1374","1402","1409","1480","1515","1516","1519","1521","1523","1529","1566","1580","1581","1611","1614","1658","1661","1670","1679","1681","1715","1719","1721","1728","1733","1734","1773","1774","1779","1785","1810","1830","1905","1908","1911","1920","1928","1953","1971","1973","1988","2056","2060","2061","2088","2089","2099","2196","2197","2218","2226","2232","2233","2235","2236","2249","2250","2257","2267","2304","2398","2401","2406","2407","2413","2424","2459","2460","2461","2504","2522","2602","2604","2613","2617","2630","2640","2662","2689","2726","2747","2813","2825","2837","2849","2943","2955","2963","2964","2965","2986","3005","3026","3042","3088","3118","3196","3226","3227","3228","3230","3231","3258","3259","3260","3262","3263","3264","3268","3273","3280","3322","3383","3461","3558","3581","3588","3607","3646","3647","3648","3655","3662","3664","3670","3681","3760","3809","3875","3876","3942","3980","3988","3992","4003","4032","4076","4157","4167","4173","4183","4233","4234","4249","4252","4283","4287","4288","4321","4376","4381","4435","4439","4444","4446","4454","4457","4478","4502","4508","4511","4581","4594","4650","4655","4699","4704","4706","4707","4710","4712","4713","4790","4794","4818"},["capto"]={"642","3719"},["salvo"]={"2947","3334"},["inicio"]={"467","1188","1441","2552","2629","2744","3052","3528","4488","4729"},["labor"]={"1240","1246","1248","1250","1255","1256","1257","1422","1542","2456","3005"},["pugnandus"]={"4433"},["asia"]={"12","4653","4654"},["currus"]={"253"},["incorruptus"]={"525","1910","2291","2292","4026","4050"},["clamor"]={"2022","2215"},["iustus"]={"745","758","812","4205","4268","4480","4496","4842"},["laboro"]={"627","675","994","1239","1249","1252","1264","1265","2530","3502"},["faciendum"]={"318","797","873","1245","1681"},["abrumpo"]={"3307"},["delenio"]={"1296"},["inanimatus"]={"17"},["lacrimula"]={"659"},["aer"]={"90","91","99"},["constans"]={"108","586","3017","3018"},["refrico"]={"4590"},["fons"]={"831","832","833"},["probus"]={"1450"},["dictatorius"]={"3735"},["confusus"]={"1766","1803"},["concurro"]={"246","4444","4492","4728"},["consector"]={"831"},["concitatus"]={"2488","3812"},["contremisco"]={"436"},["acer"]={"2514"},["philosophia"]={"1697","1733","1734","1735","1736","1737","1738","1739","1740","1742","1756","1767","1768","1769","1770","1771"},["lectito"]={"2441"},["nobilis"]={"3637","3767"},["remissus"]={"264"},["pridem"]={"1745"},["comparo"]={"930","1191","2604","3908","4213","4216"},["consenesco"]={"594"},["compertum"]={"1456"},["crinis"]={"455","456"},["amplifico"]={"1138","2189","3600"},["resisto"]={"2520"},["laxo"]={"3556"},["mergo"]={"1298","4727"},["dissipo"]={"1170","3251"},["praeteritus"]={"3835"},["memor"]={"1536","1539","1542"},["conficio"]={"109","135","210","573","630","1103","1268","2073","2409","2518","2532","2533","2569","3206","3410","3466","4168","4292","4312","4690"},["infectus"]={"1530"},["inhumatus"]={"763"},["nauta"]={"4672"},["culpa"]={"2970","2972","4114","4117","4118","4119","4121","4122","4124","4125"},["confirmo"]={"1707","1812","2579","2647","2711","4458"},["mel"]={"2686"},["fera"]={"1658"},["discessio"]={"3997"},["timor"]={"2552","2553","2554","2555","2559"},["brevis"]={"359"},["progressus"]={"1689"},["volo"]={"1044","1465","1522","1523","1525","2240","3324","3325","3326"},["audio"]={"1173","1174","1213","1755","2240","4821"},["instauro"]={"2041"},["humane"]={"2601"},["abstineo"]={"2875","3158","3211"},["certus"]={"114","1455","1458","1500","1501","2987"},["conscius"]={"2969","2971","2972"},["veneficium"]={"4102"},["postridie"]={"426"},["hactenus"]={"4784"},["ictus"]={"143"},["angustia"]={"778","779"},["dono"]={"3626"},["detraho"]={"1207"},["fugio"]={"1452"},["faex"]={"3650"},["adverto"]={"490"},["spina"]={"1761","1790"},["stagnum"]={"53"},["existimo"]={"4831"},["conscendo"]={"256","4668"},["excipio"]={"2144","3273","4487","4567","4585"},["vocabulum"]={"2347","2351","2360","2366","2367","2368","2373","2375"},["perceptus"]={"1646","1743"},["animatus"]={"17"},["imbecillitas"]={"1319"},["affulgeo"]={"2634"},["adorior"]={"4495"},["dion"]={"2681","3884"},["numerose"]={"1995","2129"},["passus"]={"184","456"},["effrenatus"]={"2857","2864"},["vinum"]={"3209","3216"},["inuro"]={"1230","1233","2513"},["inscriptus"]={"462","760"},["italus"]={"3826"},["substruo"]={"191"},["mendicitas"]={"999"},["praemium"]={"1076","1077","1078","1079"},["obtineo"]={"1840","2071","2387","3037","3585","3653","3656","3666","3841","3911","4011","4081"},["permitto"]={"267","268","866","867","2725","3679","3839","4427","4428","4645"},["lingua"]={"2100","2103","2278","2279","2280","2283","2295","2296","2348","3089"},["escendo"]={"2091"},["obortus"]={"648"},["ministro"]={"3219"},["permoveo"]={"2096","2202"},["suspectus"]={"2748"},["iacturus"]={"1019"},["sequor"]={"278","1039","1282","1374","1399","1518","1717","1747","1827","2372","2814","3013","3745","3752","4322"},["doctus"]={"349","922","1596","1624","1628","1629","1630","1631","1632","1633","1943"},["orbatus"]={"3624","3625"},["puerilis"]={"1675","1678","1679"},["exsto"]={"45","2418","4810","4811"},["frigus"]={"99","133","134","135","136"},["provincia"]={"3905","3906","3908","3909","3910","3911","3912","4653"},["circumspectus"]={"1497"},["medicus"]={"1698"},["rhenus"]={"69","174"},["quisque"]={"1629"},["commutatio"]={"388"},["nanctus"]={"4681"},["censura"]={"3967"},["everto"]={"1780","3183","3802","4421"},["apertus"]={"2085","3275"},["sum"]={"347","348","382","385","426","553","574","608","622","705","767","772","788","789","791","815","855","1109","1379","1412","1451","1503","1541","1586","1653","1745","1749","1787","1795","1801","1933","2172","2181","2193","2235","2256","2302","2331","2369","2371","2474","3099","3148","3294","3302","3484","3546","3692","4579","4649","4750","4751","4753","4776","4797"},["notus"]={"167","230","500","661","750","833","890","1099","1223","1515","1738","2138","2293","2391","2403","2599","2672","2885","3008","3046","3050","3126","3232","3240","3427","3468","3496","3678","3684","3702","3729","3888","3902","4019","4023","4179","4379","4398","4434","4446","4466","4650","4665"},["rus"]={"231","232","568"},["castra"]={"4302","4346","4347","4348","4350","4352","4353","4356","4358","4359"},["longitudo"]={"175"},["condicio"]={"765","767","770","771","3353","3651","4618","4619","4620","4621","4622"},["venenum"]={"735","736"},["ordo"]={"1915","1918","2181","2374","2399","2401","3634","3635","3644","4324","4325","4512"},["fallax"]={"1823"},["contentio"]={"1260","1263","1841","1846","1847","2081","2211","3742"},["interior"]={"12","1652"},["pauper"]={"993"},["consentiens"]={"1861"},["argentum"]={"3428","3429"},["consilium"]={"1470","1471","1472","1473","1474","1475","1476","1478","1479","1480","1481","1483","1484","1486","1487","1488","1489","1490","1491","1503","1506","1510","1516","1517","1527","2813","2960","3008","3616","3623","3744","3982","4380","4381"},["quaestio"]={"1829","2241","2242","2243","2246","2248","2249","4022","4041","4042"},["homo"]={"622","623","766","771","810","892","1120","1176","1181","1220","1295","1384","1564","1565","1595","1596","1624","1653","1658","1763","1768","1912","1989","2268","2856","2857","2998","2999","3017","3113","3280","3295","3407","3619","3633","3643","3644","3645","3721","3730","3731","3771","3772","3773","3774","3785"},["regius"]={"3762","3862","3884"},["ignavia"]={"1288","1289"},["infaustus"]={"3139"},["tutus"]={"4539"},["iustissimus"]={"4843"},["potior"]={"3850","4636"},["prohibeo"]={"3098","3151","3973","4218","4718"},["concilio"]={"1030","1136","3351","4615"},["caligo"]={"1323"},["utcumque"]={"792"},["suffragium"]={"3678","3679","3921"},["classiarius"]={"4671"},["abundo"]={"987","1281","1314","1634","2323","3170"},["animadversio"]={"3971"},["crastinus"]={"428"},["crassus"]={"1683"},["unus"]={"223","245","421","422","513","1448","1711","1712","1750","1860","1862","1863","2155","2156","2158","2337","3649","3652","3762","4190","4594","4761"},["propulso"]={"2751","2878","4533"},["partior"]={"1788"},["ratio"]={"369","782","834","1007","1010","1350","1491","1498","1579","1580","1728","1757","1766","1772","1774","1776","1779","1780","1781","1782","1783","1785","1817","1820","1821","1915","1920","1926","2143","2144","2958","2959","2960","2967","3010","3011","3012","3013","3451","3454","3460","3462","3463","3464","3465","3466","3469","3470","3471","3495","3605","3606","3607","3774","4027","4296"},["immoderatus"]={"3852"},["cor"]={"1466","4260"},["coniuratio"]={"3796"},["eluo"]={"1235"},["amitto"]={"323","497","878","2668","4083"},["alo"]={"81","2648","3566","4192"},["latus"]={"2102","4454","4515"},["sublimo"]={"294"},["oscen"]={"3133"},["iocandus"]={"2257","2269"},["diluceo"]={"402"},["iniquissimus"]={"3488"},["praesagio"]={"2758"},["aperio"]={"195","446","1376","1793","2132","2469","3164"},["fessus"]={"211"},["permuto"]={"3910","4624"},["tibicen"]={"1988"},["sermo"]={"1165","1181","2081","2196","2281","2285","2286","2287","2288","2289","2290","2291","2292","2293","2299","2303","2391","3299","3300","3301","3302","3303","3304","3305","3306","3307","3308","3309","3310","3311","3312","3327"},["excludo"]={"3973"},["statua"]={"1227","2000"},["natio"]={"189","557"},["iustitium"]={"4030","4031"},["mollities"]={"3005"},["depello"]={"633","1371","2523","2605","2639","2751","2898","3660","3882","4531"},["expostulo"]={"1164"},["excurro"]={"161","231"},["recenseo"]={"4193"},["limen"]={"3153"},["constantia"]={"1786","1869","2614"},["ai"]={"4822"},["aequum"]={"2019","4024"},["gladiator"]={"2043","2046"},["traductio"]={"3648"},["ante"]={"367","384","399","501","502","503","519","574","1212","2149","3835","3927"},["indignatio"]={"2807","2808"},["amans"]={"1403","3778"},["schola"]={"1673","1674","1694","1746","1752","1753"},["cardo"]={"117"},["percipio"]={"530","1011","1290","1644","2494","2510","2548","3548"},["percutio"]={"142","461","4159","4396","4725"},["egredior"]={"237","241","2231","4716"},["copia"]={"875","987","1487","2172","3230","3232","3319","4181","4188","4189","4190","4191","4196","4197","4366","4433","4449","4544","4582"},["induo"]={"3195","4242"},["proficiscens"]={"229","230"},["elatior"]={"2595"},["speciosior"]={"1412"},["supersedeo"]={"4771"},["september"]={"426"},["auxilium"]={"968","972","973"},["occaeco"]={"892","2851"},["ipse"]={"14","333","355","824","958","1589","1855","1856","2127","4803"},["inanis"]={"1252"},["epicus"]={"1959","1960"},["vilitas"]={"3557"},["seria"]={"2273"},["regnum"]={"3849","3855","3856","3857","3860"},["petitus"]={"1710"},["factio"]={"3738"},["arca"]={"4064"},["subigo"]={"4641"},["mendacium"]={"2925"},["vilis"]={"3420"},["florens"]={"3774"},["de"]={"22","23","142","204","205","211","236","238","297","298","409","410","444","473","474","480","531","538","578","710","711","713","741","742","812","982","1069","1070","1164","1186","1187","1188","1207","1214","1243","1247","1347","1349","1369","1370","1371","1372","1396","1470","1481","1482","1528","1544","1580","1607","1634","1638","1644","1653","1658","1690","1691","1720","1727","1740","1750","1754","1760","1767","1768","1774","1795","1815","1830","1832","1844","1848","1890","1958","1983","1992","1996","2001","2013","2063","2064","2117","2125","2131","2139","2147","2151","2165","2167","2188","2192","2195","2203","2223","2239","2240","2245","2252","2264","2276","2283","2301","2314","2325","2337","2338","2394","2409","2417","2425","2433","2479","2506","2530","2605","2606","2607","2619","2620","2625","2654","2663","2702","2723","2740","2743","2745","2772","2789","2830","2881","2914","2941","2956","3000","3002","3044","3132","3160","3177","3181","3235","3278","3301","3303","3309","3342","3348","3363","3380","3389","3414","3468","3471","3499","3502","3540","3551","3612","3613","3614","3618","3622","3645","3649","3659","3660","3667","3668","3715","3756","3795","3822","3823","3837","3916","3941","3945","3946","3950","3989","3992","3996","4012","4040","4041","4061","4062","4074","4090","4098","4101","4102","4106","4134","4142","4155","4605","4607","4608","4614","4696","4715","4738","4763","4776","4783","4785","4786","4825","4846"},["enixe"]={"1236"},["donum"]={"4038"},["coepi"]={"666","3498"},["expugno"]={"4417","4726"},["ineleganter"]={"1766"},["redigo"]={"773","807","995","1550","1773","1778","1796","2640","3865","4032","4638","4653","4655"},["solitarius"]={"3298"},["exsolvo"]={"3513","3514"},["ciceronis"]={"1740","2437","4736","4788"},["viginti"]={"382","383","384","614"},["committendus"]={"4441"},["circumactus"]={"375"},["industria"]={"1241","1528"},["persecutus"]={"2172"},["oleum"]={"1253"},["vagina"]={"4256"},["migro"]={"713"},["dissipatus"]={"1802","3280","4560"},["audientia"]={"2098"},["decresco"]={"107"},["intellegentia"]={"1325","1349"},["sublatus"]={"3499"},["graviter"]={"670","694","2507","2780","4136"},["commentor"]={"2074","2298"},["declivis"]={"35"},["disco"]={"1587","1646","1665","1933","1979","1983","2006","2296"},["nummulus"]={"3449"},["angustior"]={"2368"},["prae"]={"656","1639","2912","4547"},["accusatio"]={"4086"},["prudenter"]={"2960"},["paternus"]={"3380"},["derelictus"]={"901"},["promunturium"]={"160","162","4686"},["ortus"]={"104","146","553","558","3305","3641"},["flos"]={"580","3543"},["fautrix"]={"891"},["menstruum"]={"3489"},["lucubro"]={"1251"},["remotus"]={"2258","3331"},["longinquo"]={"185","186"},["annus"]={"377","379","381","382","383","384","385","386","396","397","574","606","608","609","610","611","612","613","614","615","616","617","618","620","3845","3927","3930"},["subsidium"]={"930","4406","4453","4525"},["dirigo"]={"216","2986","4688"},["longius"]={"169","307","327","328","591","2194","2195","4793"},["senesco"]={"107"},["syllaba"]={"2392","2393","2395"},["tyrannis"]={"3849","3853","3854"},["alter"]={"421","422"},["seditio"]={"3793","3794"},["per"]={"50","196","315","473","702","703","822","871","1167","1177","1289","1422","2256","2465","2915","2916","2921","2932","4167","4259","4319","4489","4609","4805","4829"},["eminus"]={"4254","4506"},["scribo"]={"1880","1957","2315","2316","2405","2408","2459","3364","3376","3706","3708","4169","4186"},["cogo"]={"1818","3890","3985","4186","4190","4300","4639"},["hodiernus"]={"428"},["mirus"]={"4834","4835"},["voluptarius"]={"1295"},["incola"]={"3779"},["circuitus"]={"2319"},["clades"]={"4575","4576"},["radix"]={"23","31","4341"},["caecus"]={"892"},["altissimus"]={"33","299","3657","3658"},["colligo"]={"541","635","685","1000","1030","1152","1198","1393","1711","1818","2561","2573","2765","4378","4705"},["aliter"]={"783","808","2920","4833"},["confertus"]={"196"},["singularis"]={"1361","3762","3847","4477","4478"},["intempestus"]={"411"},["turbulentus"]={"3780","3785"},["penitus"]={"1559","1644","1729","1730","1743","2754","3081"},["sponsio"]={"2742"},["addo"]={"275","2321","2578","2729"},["interdico"]={"3815","3826"},["meritus"]={"1059"},["praesto"]={"1031","2719","2734","2743","2933"},["decerno"]={"3119","3905","3999","4152","4473","4610"},["numeratus"]={"3427"},["parento"]={"3114"},["refringo"]={"3883","4413"},["chorus"]={"2033","2034"},["avis"]={"3133"},["positus"]={"769","816","824","1825","4395"},["defunctus"]={"3665"},["fallacia"]={"2922","2923"},["flecto"]={"2482","4316"},["incohatus"]={"1349"},["officiosus"]={"2951"},["iocatus"]={"2256"},["aura"]={"3716","3718","3719","3721","3736"},["granditas"]={"2113"},["transversus"]={"285"},["prudens"]={"3615"},["conflicto"]={"671","923"},["arcanus"]={"1483"},["divino"]={"1965","1966","3040"},["depravo"]={"2824"},["dirimo"]={"1849","4006","4468","4617"},["opus"]={"324","1085","1243","1244","1245","1934","1935","1936","2434","3519","3520","3536","4383","4405","4744"},["doleo"]={"2506","2508"},["victor"]={"4425","4426","4427","4595","4596"},["celo"]={"1377"},["scaena"]={"2010","2011","2012","2013","2014"},["tam"]={"3004"},["communico"]={"1478","1479"},["glarea"]={"191"},["sustineo"]={"273","3937","4124","4410","4486","4696"},["historia"]={"1709","1877","1878","1880","1884","1888","1903","1907","1908","1909","1911","1912"},["explosus"]={"1745"},["suaviter"]={"535"},["crudelitas"]={"1215","2672","2673","2674"},["confugio"]={"971","1736","2726"},["exturbo"]={"3182"},["infra"]={"769","1143","4768"},["palma"]={"1080","1081"},["mortuus"]={"751","752","3028","3377"},["ignis"]={"77","78","79","80","81","87","88","89","144","145","2906","3815","4375","4405"},["erogo"]={"3431"},["elogium"]={"759"},["moveo"]={"280","534","640","655","1090","1372","2484","2663","2699","2744","2798","3185","3660","3974","3976","4270","4302","4531"},["incedo"]={"2807","4309","4327"},["fossa"]={"4354","4389"},["aliquatenus"]={"842"},["contio"]={"2090","2091","3671","4456"},["perdomo"]={"4641"},["dictator"]={"3959","3961"},["aridus"]={"2120","4666"},["acquiesco"]={"1608"},["aegre"]={"644","2507","2780"},["illecebra"]={"1296"},["aegritudo"]={"2526","2527","2532","2533","2534","2535","2536"},["solvendus"]={"3444"},["tectum"]={"3150"},["rarus"]={"4264","4325","4527"},["exposco"]={"4441"},["mars"]={"4499"},["tertius"]={"434","609","619","1116","2030","3952"},["apparo"]={"2039","3253"},["deductus"]={"787"},["axis"]={"117"},["vestis"]={"3195","3196","3204"},["expertus"]={"1591"},["impetro"]={"1095","1514"},["edoctus"]={"1586"},["applaudo"]={"2020"},["conservo"]={"1212","1555","3066","4432"},["stella"]={"108","112","113"},["quivis"]={"1629"},["affirmo"]={"1457"},["cuneus"]={"4522"},["accendo"]={"77","82","2583","2848"},["ludus"]={"755","1672","2002","2039","2040","2041","2045","2047","2048"},["sensim"]={"277"},["violo"]={"2721","3068","3109","4612","4613","4632"},["scriptor"]={"625","1882","1889","1963","1964","2309","2404","2427","2443","2449","3707"},["produco"]={"2010","2392","3308","4055","4445"},["pravitas"]={"1390"},["implacabilis"]={"2774"},["diu"]={"4500"},["geographia"]={"1922"},["constructio"]={"2320"},["propensus"]={"1042","2955"},["minime"]={"4834"},["elicio"]={"641","2339","2903"},["simultas"]={"3294"},["suppeto"]={"543","569","571","2220","3232"},["ferrum"]={"196","4375","4473","4579"},["otium"]={"1279","1282","1284","3594"},["exsulo"]={"3831"},["sugo"]={"1425"},["amoenus"]={"43"},["numero"]={"3433","4207"},["inspectans"]={"512"},["ludibrium"]={"899","2929","2930","2932"},["amplexor"]={"1282"},["gladiatorius"]={"2042","2044","2045"},["intersum"]={"1483","1753","3033","4475"},["triplex"]={"4328","4450"},["proficio"]={"1668","1689","2542"},["somnus"]={"690","691","692","693","695","696","699","700","702","704","705","3209"},["luctus"]={"2543","2545","2546","2547","2548","2549","2550","2551"},["deprecor"]={"4164"},["respondeo"]={"121","1064","2171","2250","2254","2655","3126","4173"},["magnitudo"]={"1789"},["initium"]={"793","794","795","2093","4273"},["extra"]={"64","241","2258","2983","2996","4114","4251"},["minerva"]={"1683"},["aggredior"]={"797","1244","2089","4076","4483","4494"},["creatus"]={"3923"},["percontans"]={"2252"},["fructus"]={"1011","1012","1013","3548","3549"},["consensio"]={"1868"},["accensus"]={"2777","2846"},["discrimen"]={"355","946","947","953","954","956","957","958","4501"},["pons"]={"3527","3528","3530","3531"},["abalieno"]={"1050"},["humanus"]={"764","765","768","769","1658","3043"},["additus"]={"2185"},["verbero"]={"4400"},["corrigo"]={"1430","1662"},["testudo"]={"4393"},["condo"]={"751","1956","3135","3526","3549","3706","3977"},["cena"]={"3256","3259","3260","3261","3263","3264","3265"},["affero"]={"467","727","800","811","844","849","905","943","975","1003","1004","1020","1171","1194","1441","1531","1704","1714","1806","1807","1808","1817","2442","2451","2493","2498","2512","2531","2545","2629","2740","2897","3052","4575","4759"},["frater"]={"3339"},["exercitus"]={"4215","4219","4221"},["conculco"]={"515"},["spatium"]={"182","218","329","330","361","2562"},["populus"]={"3578"},["aestivo"]={"389"},["matrimonium"]={"3355","3360","3361"},["magister"]={"1667","2058","3961"},["lacrimo"]={"653","654","657"},["mathematica"]={"1925"},["sero"]={"3538","3551"},["tecum"]={"1852","1866"},["filia"]={"3349","3359","3360","3361","3362"},["consuetudo"]={"369","2286","2288","2290","2291","2386","3286","3287","3290","3291","3292","3388","3390","3391","3393","3394","3395","3396","3397","3402","3403"},["metor"]={"4350"},["superstitio"]={"3077","3078","3079","3080","3081"},["extenuo"]={"2189","2644"},["onero"]={"2886"},["dictus"]={"4770"},["caelum"]={"92","93","96","97","98","100","101","110","117","137","138","1149","3088"},["publicus"]={"743","3616","3896"},["agricultura"]={"3535"},["gratulor"]={"3348","4605"},["suavitas"]={"392"},["aspicio"]={"548"},["stimulo"]={"2974"},["familiaritas"]={"1111","3285","3286"},["postliminium"]={"3837"},["occidens"]={"147","149","602"},["comprobatus"]={"1909"},["annalis"]={"1709","1884","1893","1894","1900"},["confligo"]={"4496"},["oriens"]={"147","149"},["creo"]={"4","955","3677","3921","3927","3948","3959"},["persuadeo"]={"1461","1463","1464","1465"},["actio"]={"1770","2004","2198","2200","4087"},["hasta"]={"4254","4430"},["philosophandus"]={"1785"},["incitatio"]={"2704"},["lectisternium"]={"3121"},["diluculum"]={"404"},["adhibitus"]={"2995"},["confundo"]={"1414","3803"},["celebro"]={"754","1976","3117"},["moderatio"]={"2992"},["severitas"]={"523","1725","2275"},["defectio"]={"106"},["citius"]={"425"},["peractus"]={"375"},["historicus"]={"1906"},["inductus"]={"3311"},["intereo"]={"630","940"},["multo"]={"3827","4144","4154"},["rector"]={"3614"},["interpositus"]={"1534"},["deferveo"]={"583","2870"},["ignotus"]={"4704"},["roma"]={"555"},["submergo"]={"59"},["institutum"]={"3011","3405","3570","3572"},["externus"]={"533","537","768","1914","3056","4269"},["principatus"]={"2070","3666","3667","3668","3842"},["ambages"]={"2087"},["vitiosus"]={"2291"},["optimus"]={"1099","1359","1363","1593","1612","1650","3577","3765","4037","4072","4844"},["totidem"]={"2307"},["magnus"]={"137","650","813","826","843","850","904","906","1085","1090","1130","1132","1134","1218","1275","1306","1311","1312","1418","1419","1440","1477","1508","1584","1639","1693","1703","1805","2205","2214","2246","2525","2547","2592","2623","2698","2948","3421","3422","3425","3477","3506","4196","4202","4222","4305","4568","4592","4733"},["pedester"]={"221"},["oppressus"]={"3867"},["sordes"]={"2544"},["sciens"]={"1633"},["indico"]={"3118","3673","4030"},["dissuo"]={"1118"},["calumnia"]={"4085"},["coniuro"]={"3795"},["deversor"]={"3269"},["perfringo"]={"4524"},["perduellio"]={"4099"},["quaestus"]={"3416","3417","3901"},["demergo"]={"304"},["reservo"]={"864"},["extollo"]={"2190"},["actor"]={"2030"},["recedens"]={"72"},["praeiudicium"]={"1388"},["inundo"]={"65"},["concerto"]={"2340"},["tributum"]={"3891","3892","3894","3895"},["functus"]={"4210"},["pabulatio"]={"4374"},["accessio"]={"618"},["tango"]={"140","141","142","157","164","2159","2160","4830"},["tabula"]={"1998","3454","3455","4045","4097","4846"},["celebritas"]={"2047"},["negotium"]={"1101","1102","1266","1267","1268","1269","1270","1271","1274","1275","1276","3407","3408","3409","3410","3412","3413","3586","3592","3625"},["obsolesco"]={"3392"},["circumfusus"]={"90"},["sedo"]={"636","1849","2487","2796","3811"},["tragoedia"]={"1963","2031","2114"},["digressus"]={"2184","2235","2236"},["interpolo"]={"2439"},["sententia"]={"1098","1366","1368","1369","1370","1371","1372","1373","1374","1376","1377","1379","1380","1383","1384","1468","1475","1502","1744","1745","2132","2133","2135","2136","2140","2142","2143","2144","2254","2317","2359","2372","2474","2683","3061","3678","3705","3990","3991","3992","3993","3998","4104","4105","4775"},["vacillo"]={"1539"},["attineo"]={"1014"},["gloria"]={"1191","1192","1193","1195","1196","1198","1199","1200","1202","1204","1205","1206","1207","1208","1210"},["eloquentia"]={"2067","2070"},["advesperascit"]={"405"},["vasto"]={"4375"},["amputo"]={"1428"},["incertus"]={"1503"},["iubeo"]={"1691","2240","3334","3345","3366","3687","3689","3700","3703","3824","3999","4845"},["praeclarus"]={"155","1065","1700","3613","3955"},["remus"]={"4693","4694","4695","4696"},["recupero"]={"3885"},["asperitas"]={"100"},["triens"]={"3481","3484"},["fero"]={"15","61","199","335","506","784","968","1010","1021","1081","1149","1234","1381","1639","1886","2190","2253","2422","2507","2600","2601","2780","2877","2912","3402","3458","3678","3681","3919","3920","3921","3922","4105","4140","4162","4166","4167","4301","4370","4598","4619"},["efflo"]={"716","3543"},["missus"]={"2087","2464"},["subtilitas"]={"1760"},["posterus"]={"326","363"},["obnuntio"]={"3134"},["erumpo"]={"2830","3794"},["naturalis"]={"1756"},["aucupor"]={"1039"},["culta"]={"3228"},["tractatio"]={"1594"},["ratiocinatio"]={"1821"},["contamino"]={"2832"},["umbratilis"]={"1640"},["geometricus"]={"1925","1927"},["quindecim"]={"3119"},["infinitus"]={"1712","2225","3852"},["restinguo"]={"2705","2779","2796"},["concludo"]={"1818","1819","1926"},["retro"]={"4697"},["amoveo"]={"4125"},["evomo"]={"145","2791"},["inclinatio"]={"369"},["aegroto"]={"666","672","680"},["iuvo"]={"1486"},["pabulatus"]={"4373"},["cogito"]={"368"},["absum"]={"178","179","386","1657","3097","4115","4116"},["spiritus"]={"560","561","564","717","1966","2592","2593","3770","3862","3884"},["elementum"]={"6","7","1676","1677","2400"},["indulgeo"]={"1305","2516","2665","2792","2957","3216"},["signo"]={"2468"},["exstructus"]={"3255"},["oppugno"]={"3874","4388"},["hostis"]={"196","454","963","4218","4333","4368","4433","4435","4438","4482","4483","4484","4485","4488","4489","4490","4491","4493","4494","4495","4496","4510","4515","4516","4517","4519","4529","4530","4531","4532","4533","4535","4542","4543","4544","4545","4546","4547","4550","4561","4562","4563","4565","4566","4568","4570","4571","4572","4575","4580","4581","4582","4600","4730"},["poesis"]={"1961","1971","1973"},["consto"]={"445","857","1459","1504","1872","2611","3018","3422","3423","3464"},["centesima"]={"3472","3473","3474","3475","3490"},["fabulor"]={"1903"},["armo"]={"4664"},["relinquo"]={"313","677","1218","1443","1444","1845","4322","4357","4411","4792"},["numquam"]={"1558"},["parum"]={"804","2293","2345"},["vultus"]={"491","521","522","523","524"},["divitiae"]={"2134"},["admodum"]={"599"},["circumiectus"]={"90"},["frequentia"]={"42"},["dies"]={"223","330","338","379","397","406","407","409","413","414","417","418","419","420","421","422","423","426","427","428","429","430","431","432","714","715","1535","2476","3005","3116","3117","3119","4004","4016","4440"},["recedo"]={"3593"},["digressio"]={"2184"},["bilis"]={"2791","2798"},["messis"]={"3547"},["cito"]={"2442","4051"},["compositus"]={"435"},["astringo"]={"2130","2841","3062"},["consensus"]={"3","1863"},["perverto"]={"4035"},["reapse"]={"1416"},["spectator"]={"1930"},["circiter"]={"4593"},["infigo"]={"4258"},["focus"]={"3161"},["ascisco"]={"3627","4633"},["tredecim"]={"608"},["defigo"]={"1345","3610","4260"},["curatio"]={"682"},["victus"]={"1655","3224","3225"},["cohors"]={"4360"},["recens"]={"1538","4528"},["inscribo"]={"2000","2415","2416"},["perfungor"]={"961"},["artificiosus"]={"1778"},["patiens"]={"136","637","1256"},["plato"]={"1365"},["impunitus"]={"4163"},["exsanguis"]={"2120"},["obsidio"]={"4385","4386","4408","4409","4410","4411"},["iuppiter"]={"2040"},["periclitor"]={"894","957"},["magis"]={"3005"},["perduco"]={"617","802","1353","1373","3655"},["ora"]={"4685","4707"},["provenio"]={"25"},["prima"]={"400","578","1676","1822"},["satin"]={"2966"},["exprobro"]={"1162"},["iaceo"]={"1598","1738","1780","3440","3599"},["atrox"]={"4479"},["deliciae"]={"2686","2687"},["hoc"]={"352","760","783","810","846","847","981","985","1159","1367","1455","1525","1526","1732","1825","1826","1854","1865","1866","2243","2308","2361","2371","2373","2388","2425","2443","2473","2819","3220","3955","4759","4761","4763","4764","4765","4783","4789","4792","4801","4802","4803","4804","4805","4806","4818"},["ille"]={"346","349","658","809","985","1558","1653","1744","1745","1750","1947","2127","2389","3270","3765","4787","4791"},["stringo"]={"4257"},["domo"]={"4387"},["maturus"]={"720"},["officio"]={"1007","1323","3532"},["palliatus"]={"3200"},["somnium"]={"707","708","709"},["nunc"]={"622","2244","2245"},["honestas"]={"2821"},["pertinax"]={"1835"},["tergo"]={"4565"},["ago"]={"23","24","568","609","718","780","938","957","1060","1061","1254","1269","1289","1309","1609","1848","1967","2007","2028","2029","2153","2216","2244","2273","2425","2960","2980","3014","3091","3116","3131","3147","3298","3335","3336","3524","3562","3672","3765","3777","3783","3966","3967","4013","4014","4021","4067","4095","4160","4303","4361","4362","4363","4370","4391","4399","4547","4608","4614","4693"},["periclum"]={"341"},["quoquo"]={"286"},["digredior"]={"2192","2231"},["perpetro"]={"3107"},["iudico"]={"2985","4024","4067","4106"},["noto"]={"1229","1917","3972"},["versus"]={"1974","1976"},["traho"]={"554","1203","1613","1614","4282"},["gravissimus"]={"4754","4813"},["tragicus"]={"1963","2183"},["immutatio"]={"2379"},["afficio"]={"535","744","779","1017","1022","1052","1076","1145","1199","1223","1229","2492","2509","2527","2693","2696","2873","2882","3827","3864","4127","4156"},["elatio"]={"2110"},["conspicuus"]={"489"},["grandior"]={"587"},["fuco"]={"2923"},["servilis"]={"3879","3881"},["cesso"]={"123"},["contradico"]={"1874"},["instruo"]={"2901","3253","3254","4449","4450","4664"},["quaterni"]={"3475"},["subiectus"]={"531","1787","2359","4649"},["mater"]={"552"},["suus"]={"621","976","1142","1368","1369","2438","2538","2789","3252","3654","4637","4642","4806"},["africanus"]={"4610"},["eleganter"]={"1766","3267"},["respuo"]={"4621"},["proelium"]={"4435","4437","4441","4442","4459","4460","4461","4462","4463","4464","4465","4467","4468","4469","4470","4471","4472","4475","4479","4480","4492","4496","4498","4574","4596","4599"},["concoquo"]={"3206"},["cantus"]={"1980","1981"},["obsecro"]={"1084","2728"},["carus"]={"2676","2679","2680"},["peritus"]={"1762","1942","3615"},["aptus"]={"1797","1801"},["litteratus"]={"1624"},["detrecto"]={"4175","4436"},["romae"]={"555"},["excedo"]={"170","237","579","613","712","4541"},["munio"]={"194","4352","4353"},["exiens"]={"378"},["abhorreo"]={"539","1410","1950","2290","2756","2955","3007"},["reclamo"]={"2018"},["vallum"]={"4355"},["desisto"]={"1370","1471","1511"},["denuntio"]={"2907","4265"},["parvulus"]={"576"},["tritus"]={"193","444","2391","3198"},["gaudeo"]={"2496"},["tollo"]={"93","468","549","638","639","741","1149","1427","1442","1849","2215","2551","2636","2834","3049","3080","3694","4004","4160","4301","4677","4709"},["clausus"]={"4719"},["intercipio"]={"2470","4731"},["sacrifico"]={"3104"},["velim"]={"1464"},["irrumpo"]={"4415"},["quaero"]={"1039","1204","2229","2243","2244","2245","2354","3233","3720","3722","4040","4061","4062","4812"},["occumbo"]={"731"},["aes"]={"3428","3505","3506","3507","3508","3513","3698"},["impotens"]={"2856","3851"},["sempiternus"]={"1200","3836"},["conflagro"]={"85"},["cano"]={"1990","4376","4481","4536","4537"},["lacrima"]={"646","647","648","649","656","658","660"},["obstringo"]={"1054","2841","3064"},["pecuarius"]={"3561"},["grandis"]={"592","3425"},["societas"]={"2283","3277","3279","3280"},["satisne"]={"2966"},["respondendus"]={"2101"},["metus"]={"1794","2556","2557","2558","2560","2561"},["lustro"]={"2152","4193"},["auceps"]={"2395"},["supplicium"]={"2845","4134","4152","4155","4156"},["profiteor"]={"1401","1697","1698","1699","1748","1939","3915","4172"},["cohaereo"]={"1798","1800"},["humilis"]={"1347","2589","3638","3639"},["pinguis"]={"1683"},["consisto"]={"853","2615","4334","4340","4521","4712","4714"},["soleo"]={"1678","1679","3401"},["index"]={"2414"},["circumscribo"]={"2988"},["lictor"]={"3963"},["degenero"]={"2822","2823"},["sonitus"]={"2209","2332"},["post"]={"313","1197","1564","1565"},["sanitas"]={"2118","2963","2965"},["moratus"]={"2998"},["concertatio"]={"2341"},["antecedo"]={"605"},["abdo"]={"1606","2440"},["calcar"]={"262"},["inflammo"]={"83","1224","2096","2778","2805","2850"},["epistula"]={"2459","2460","2461","2462","2463","2468","2469","2470","2471"},["ascendo"]={"257","3661","3662","4395","4668"},["augurium"]={"3131"},["laetus"]={"3541"},["indomitus"]={"2865"},["assequor"]={"311","1393","1394","1507","3663","4563"},["enodo"]={"2354"},["eiusdem"]={"2283"},["quandam"]={"1360","1361"},["incitatior"]={"2111","2704"},["auspicato"]={"3135"},["si"]={"570","571","790","2329","4153","4812"},["nanciscor"]={"129","251","821","876","891"},["certo"]={"1788","3013","3161"},["exuo"]={"2667","3204","3880","4243"},["rusticus"]={"3536"},["muto"]={"524","1475","3196","3197","3629","3830","4296"},["aut"]={"383","1924"},["appono"]={"3208","3265"},["infirmitas"]={"1319"},["grates"]={"1061","3091"},["rescindo"]={"3371","3531","3714","4107","4108"},["percello"]={"2582","3874"},["frumentum"]={"3546","4215","4216"},["exspectatio"]={"1693","2652","2653","2654","2655","2656","2657","2659"},["huc"]={"288","2343"},["profligo"]={"4535"},["ostium"]={"3163","3164"},["repetitus"]={"2195"},["accommodo"]={"1046","1049","1325","1779","2197"},["advoco"]={"3671"},["prodeo"]={"2011","2983","3157","4056"},["anceps"]={"927","4498","4499","4500"},["molliter"]={"3246"},["firmus"]={"1805"},["os"]={"1155","1176","1178","1756","1757","1860","1862","1925","1931","1932","2344","3089","3302"},["galea"]={"4242"},["quinque"]={"385","386"},["fenus"]={"3436","3437","3438","3484","3485","3486","3488"},["tribuo"]={"322","1051","1074","1075","1144","1222","1238","2709","3041","3628","3669","3731"},["certe"]={"1449"},["officium"]={"750","2933","2936","2937","2938","2939","2943","2945","2948","2949","2950","2952","4650"},["imago"]={"120","1332","1361","1362"},["discendus"]={"1672"},["cohortor"]={"4457"},["navis"]={"4661","4733"},["temperatio"]={"98"},["coetus"]={"3295"},["mordicus"]={"483"},["simulacrum"]={"1999"},["patronus"]={"4074"},["clarior"]={"347","4803","4827"},["consulatus"]={"3922","3955","3958"},["expono"]={"953","1078","1923","2139","2145","2147","2153","2163","3419","4670"},["alacer"]={"2577"},["puer"]={"576","610","1669","1676"},["virus"]={"2789"},["tibia"]={"1980","1986","1987","1988"},["opifex"]={"5"},["delictus"]={"2970"},["vicissitudo"]={"413","926"},["frumentatus"]={"4373"},["scopulus"]={"4699"},["promptus"]={"2100","2257","4801"},["cupidus"]={"3780","3785","3787"},["latius"]={"2367"},["plaudo"]={"2020"},["obvius"]={"249"},["praeficio"]={"3936","4219","4220"},["rivulus"]={"831"},["veritas"]={"437","1402","1403","1405","1951"},["ludicrus"]={"2001"},["tempestivus"]={"3266"},["affectus"]={"671","2480"},["semel"]={"365","4757"},["fama"]={"637","1165","1166","1167","1170","1172","1191","1207","1209","1210","1211","1212","1215","1218"},["plane"]={"2085","2549"},["hinc"]={"658","1828","3310"},["athenae"]={"2127"},["ignoro"]={"1450"},["fugiens"]={"1257","4564","4567","4568"},["concupisco"]={"1225","3853"},["levo"]={"2536","3556"},["occupatus"]={"3587"},["evinco"]={"1812"},["compositio"]={"2318"},["struo"]={"2901"},["procumbo"]={"301","517"},["nego"]={"1091","1092","3071","3076","4762"},["prodigium"]={"3129"},["acus"]={"4830"},["firmo"]={"4342","4356"},["animadverto"]={"2675","4128"},["mutuus"]={"3441","3442"},["immineo"]={"949","4277"},["tabesco"]={"2518"},["rumor"]={"1165","1166","1168","1169","1171"},["senectus"]={"595","597","598"},["importo"]={"3418"},["imbuo"]={"1386","1677","3046"},["consero"]={"4490"},["patria"]={"734","3183","3778","3833","3834"},["membrum"]={"674"},["solitudo"]={"3296"},["pompa"]={"753","2334"},["corpus"]={"315","540","663","1300","3209","3611","4430","4589"},["privo"]={"498","726"},["voco"]={"345","939","954","1437","1843","1844","2749","2768","3259","3461","3984","4015"},["caro"]={"3234"},["subterfugio"]={"4175"},["versatus"]={"1582"},["creber"]={"2136","4345","4404"},["fortiter"]={"4226"},["temere"]={"888","1491","2960","3014"},["exordium"]={"3311"},["poema"]={"1956"},["usura"]={"3436","3472","3478","3479","3480","3481","3483","3489"},["tu"]={"1094","1100","1176","1463","1464","1465","1487","1524","1987","2491","3220","3221","3338","3995","4822"},["genus"]={"557","771","836","840","1603","1787","1789","2373","3630","3637","3643","3767"},["finitimus"]={"165"},["reparo"]={"1024"},["musica"]={"1979"},["studeo"]={"1040","1622","2953","3535","3746","3786"},["sancio"]={"3059","3690","3691","4153"},["irrigo"]={"52"},["ac"]={"365","771","808","1240","1619","1954","2062","2222","2372","2686","2920","2923","2994","3011","3064","3188","3190","3246","3276","3596","3804","3946","4034","4606","4719","4786"},["cursus"]={"563"},["refello"]={"1816"},["collapsus"]={"3143"},["apparatissimus"]={"2049"},["adeo"]={"951","3036","3130","3320","3321","3384"},["incido"]={"250","334","477","620","665","913","948","1161","1189","1190","1336","2546","2563","2637","3302","3303","3507"},["horreo"]={"457"},["affectio"]={"663","2479"},["pecuniarius"]={"3450"},["eicio"]={"2026","2685","3820","3822","3975","4701"},["privatus"]={"3595","4065"},["beate"]={"908"},["praeteriens"]={"2161","4766"},["studium"]={"1042","1203","1241","1593","1594","1597","1602","1604","1611","1612","1613","1615","1616","1638","1650","1733","1735","1940","1971","2193","2406","2702","2703","2954","2956","3739","3743","3760","3873","4283"},["creditor"]={"3494"},["demo"]={"1431","2740","3881"},["imprimo"]={"3074"},["indoles"]={"1686","3016"},["assuetus"]={"3387"},["effringo"]={"3166"},["tracto"]={"1742","1979","3579","3583","4691"},["iniens"]={"377","390","578","3012"},["artus"]={"436","695"},["terrestris"]={"221","1924"},["dissimulatio"]={"2382"},["contumacius"]={"2597"},["consolatio"]={"980"},["arbitror"]={"769","1143"},["ardeo"]={"85","131","2511","2684","2702","2775","2785","2847","4279"},["datus"]={"870","2460","2478","2724","3341","3465"},["admoveo"]={"1684","4060","4321","4394"},["praetermitto"]={"878","2176","4799"},["adumbratus"]={"1349"},["catonium"]={"2126"},["opera"]={"662","1236","1237","1238","1239","1240","1248","1253","1258","1670","3954"},["collecta"]={"1212"},["pecunia"]={"1001","3250","3375","3425","3426","3427","3431","3432","3433","3434","3435","3436","3437","3438","3439","3440","3441","3442","3443","3445","3446","3451","3456","3457","3495","3502","3504","3890","3898","3899","4096","4144"},["inimicitia"]={"1109","1121","1122","1123"},["cibarius"]={"3215"},["celeritas"]={"312","1318","1331","2101"},["iterum"]={"365","3952"},["vertens"]={"376"},["saxum"]={"40","121","190","298"},["solutio"]={"2103","2280"},["increbresco"]={"122","1168"},["consentio"]={"1858","1860"},["rusticanus"]={"234"},["perrumpo"]={"4326","4407","4489"},["hesternus"]={"428"},["repudium"]={"3364","3367"},["intentus"]={"1273"},["pugno"]={"1870","1871","3161","4476","4499","4503","4512","4513","4527"},["nobilito"]={"1197"},["fletus"]={"650"},["perago"]={"1507"},["cotidianus"]={"2196","2287","2289","3224","3232","3327"},["necessitudo"]={"3293"},["excuso"]={"687","4176"},["structura"]={"2318","2320"},["tectus"]={"78","3151","3276"},["secundus"]={"124","889","903","2030","3257","4465"},["exhaurio"]={"738","3223"},["coram"]={"1155","3328"},["induco"]={"1423","1513","2014","2154","2348","2458","2632","2642","2662","2903","3389"},["navalis"]={"4723"},["commoveo"]={"2484","2485","2512","2653","2660"},["cogitatio"]={"1326","1328","1329","1330","1333","1335","1336","1337","1341","1343","1344","1346","1347","1357","2632","3608","3609"},["defatigo"]={"4526","4528"},["circensis"]={"2038"},["sto"]={"1502","1839","2738","3422","3599","3747","4500","4606","4714"},["praesum"]={"3580","3934","4020","4042","4221","4232"},["interpretatio"]={"2310","2350"},["concilium"]={"3670","3673"},["oblatus"]={"706","870","872"},["togatus"]={"3200","3652"},["rhetor"]={"2058","2334"},["adhortor"]={"4457"},["agmen"]={"4297","4298","4299","4300","4303","4307","4308","4320","4327","4328"},["acclivis"]={"35"},["extrinsecus"]={"824"},["planissimus"]={"3703"},["motus"]={"108","2483","2487"},["comprobo"]={"1707","1812"},["eximius"]={"1147","1359"},["molestia"]={"2451"},["nomen"]={"1553","1562","1563","2328","2350","2351","2355","2361","2371","3456","3457","3915","4088","4172","4173"},["fluens"]={"907","2116"},["emo"]={"3420","3421","4209"},["super"]={"63"},["propago"]={"169","1562"},["sanctus"]={"3029","3692"},["absolvo"]={"1354","2169","3410","4151","4745"},["imbutus"]={"1647","1654","1765","3078"},["acies"]={"486","496","4445","4448","4449","4450","4451","4452","4473","4474","4489","4497","4530"},["pulsus"]={"537"},["immodestia"]={"4236"},["decedo"]={"205","238","711","720","1369","2013","2941","3941","4012"},["auris"]={"445","500"},["consulto"]={"1482"},["significo"]={"2177","2180","2357","2361","2365"},["sensus"]={"525","526","527","529","530","531","534","535","536","538","539","2476","2671"},["aboleo"]={"1570"},["insula"]={"4686"},["repono"]={"3038"},["alpis"]={"30","69"},["revello"]={"3166","4414"},["reconditus"]={"1637","1652","2133"},["colloquor"]={"2465","4064"},["deliberandus"]={"329","330"},["rex"]={"3858","3859"},["interscindo"]={"3531"},["statuo"]={"1724","2981","3242","3424"},["resono"]={"121"},["conscisco"]={"725","737"},["gesto"]={"479","2689"},["clavus"]={"3582","4692"},["uxorius"]={"3353"},["imitatio"]={"1952","1954"},["propitius"]={"3023"},["argumentum"]={"1805","1806","1807","1808","1809","1812","1813","1814","1815","1816","2003","2217","2218"},["amplissimus"]={"1076","3634","3663"},["visus"]={"705"},["obduco"]={"2521"},["mensa"]={"3254","3255","3257"},["urbs"]={"13","83","155","163","178","239","244","305","306","387","559","676","1167","3135","3821","3823","4342","4343","4408"},["adsum"]={"357","974","1310","2612","3034","3591","3986","4017"},["partus"]={"4603"},["considero"]={"1493"},["compitum"]={"212"},["iudicium"]={"1469","1945","1946","1948","1949","3010","3014","3573","3808","4015","4017","4018","4019","4020","4027","4082","4107"},["reprehendo"]={"1159"},["retineo"]={"1555","1557","2816","2979","3390","3653"},["adigo"]={"3063","4180"},["icio"]={"141"},["pictura"]={"1996"},["fortuito"]={"888"},["paludatus"]={"3202"},["do"]={"200","269","329","330","469","510","662","735","755","760","869","873","874","875","883","884","937","1051","1080","1101","1154","1163","1236","1237","1288","1435","1436","1484","1573","1670","1727","1837","2009","2021","2042","2043","2271","2459","2461","2466","2475","2562","2666","2730","2731","2744","2924","3060","3125","3126","3218","3291","3300","3319","3320","3343","3359","3361","3362","3437","3442","3628","3706","3954","4002","4054","4120","4126","4137","4147","4172","4195","4207","4365","4442","4539","4542","4549","4550","4553","4620","4627","4650","4680","4683","4700"},["vaco"]={"1271","4113"},["fenero"]={"3473"},["praestringo"]={"496"},["quotus"]={"433"},["ordior"]={"3299"},["reposco"]={"3470"},["ultra"]={"2984"},["nihil"]={"327","328","846","915","980","1004","1094","2529","2692","2817","3415","4738","4818","4819"},["inerro"]={"113"},["informo"]={"1326","1350","1661","1679"},["piscis"]={"3234"},["deliberatio"]={"1495"},["antiquus"]={"342","774"},["convivium"]={"3253","3264","3266"},["quaerendus"]={"817","2247"},["breviter"]={"2159","2168","2262","4742","4746"},["obsitus"]={"3201"},["lectissimus"]={"2325"},["gratia"]={"1034","1035","1036","1037","1038","1039","1057","1058","1059","1060","1062","1065","1127","1128","3717","3720","3724","3725","3726"},["insolentius"]={"2594"},["ianua"]={"3166"},["arroganter"]={"4778"},["superior"]={"37","372","1822","3958","4073","4337","4518","4596"},["inutilis"]={"4167"},["exporto"]={"3418"},["detrimentum"]={"1018","1024","3954","4592"},["intueor"]={"513"},["contingo"]={"1096","3293"},["pannus"]={"3201"},["simulatus"]={"660"},["incitatus"]={"273","4721"},["exsulto"]={"2499"},["numerus"]={"1352","1932","1936","1978","1994","2130","3037","3038","3816"},["auctoritas"]={"1130","1131","1132","1133","1134","1135","1136","1137","1138","1139","1717","1718","3724","4001"},["aio"]={"1682","2385"},["claudico"]={"2200"},["venter"]={"3210"},["immortalis"]={"1061","1192","1199","1808","3091","3096"},["disto"]={"180"},["ianuarius"]={"2475"},["inexpiabilis"]={"3059"},["operio"]={"446","495"},["susceptum"]={"1510"},["benevolentia"]={"1029","1030","1031","1032"},["mille"]={"184","4146"},["colo"]={"1106","1228","1599","1648","2718","2933","3030","3040","3533"},["umbraculum"]={"1694"},["nullus"]={"324","843","882","960","1072","1250","1276","1491","1533","1534","1560","1764","1766","1833","2213","2336","2344","2346","2671","2937","2960","2972","2995","3014","3055","3575","3750","3807","3808","3810","4033"},["vexo"]={"671","2978","3801"},["careo"]={"527","757","758","2361","2829","3158","3596","3597","3825","4113"},["leno"]={"2029"},["capilli"]={"457","458"},["paries"]={"451","3332"},["laelius"]={"2415","2416"},["ambulo"]={"3347"},["muliebris"]={"551"},["somnio"]={"710"},["concedo"]={"1837","3669"},["ingenium"]={"1311","1312","1313","1314","1315","1316","1317","1318","1319","1330","1331","1648","1649","1687","1688","1693","2147","2957","3016"},["illustro"]={"1197","1739","2148"},["tiro"]={"2062","4206"},["remissio"]={"2211"},["causa"]={"356","466","772","789","811","812","813","814","815","816","817","818","819","821","822","823","824","825","864","1044","1226","1301","1566","1706","2185","3602","3745","3765","3776","3777","4039","4044","4065","4066","4067","4068","4069","4070","4071","4072","4073","4074","4075","4076","4077","4081","4083","4106"},["aedes"]={"3968"},["verbum"]={"1087","1732","1864","2090","2113","2119","2121","2132","2138","2141","2164","2166","2171","2173","2220","2304","2305","2306","2307","2308","2318","2319","2320","2322","2323","2324","2325","2326","2328","2329","2330","2331","2332","2333","2336","2337","2338","2339","2340","2341","2342","2343","2344","2345","2346","2348","2349","2351","2352","2353","2354","2358","2360","2372","2374","2376","2378","2379","2383","2396","2449","2458","2474","2883","2884","2924","3087","3326","3339","4736","4754"},["malacia"]={"4679"},["accido"]={"441","516","790","910","1400","3045"},["guberno"]={"3579"},["corrumpo"]={"1297","2824"},["emineo"]={"4811"},["initus"]={"1498","3462"},["exsequor"]={"748","1103","1267","2173","2933","2936","3409"},["canticum"]={"2034","2037"},["vivo"]={"232","418","569","612","908","992","1278","3234","3235","3237","3238","3246","3288","3296","3297","4029"},["senex"]={"599"},["erro"]={"1420","1919","2282"},["agger"]={"4353"},["ara"]={"3161"},["invisus"]={"2759","3723"},["suppressus"]={"2208"},["priscus"]={"1904","2326"},["honoro"]={"1222"},["perdo"]={"3004"},["vox"]={"120","121","1861","1862","1981","2205","2206","2207","2208","2211","2213","2214","2357","2359","2361","2393","2885","3128"},["git"]={"2757"},["comprehendo"]={"79","1335","1643","1644","4747"},["uro"]={"131"},["ut"]={"133","327","336","349","787","818","863","874","886","1236","1262","1263","1264","1265","1341","1379","1381","1382","1466","1467","1470","1485","1514","1517","1518","1520","1527","1541","1617","1653","1682","1801","1827","1828","1905","1977","2236","2237","2369","2371","2384","2385","2607","2682","2692","2819","3064","3346","3398","3400","3401","3540","3623","3681","3691","3692","3712","3795","3986","3999","4123","4135","4622","4735","4736","4737","4738","4739","4742","4745","4746","4747","4748","4749","4754","4755","4756","4757","4758","4759","4768","4782","4796","4799"},["sapientia"]={"1733","1735","3669"},["callum"]={"2521"},["rima"]={"3147"},["prorsus"]={"2346","4831"},["definio"]={"177","1791","2369"},["sulla"]={"2205"},["sono"]={"2357"},["inflo"]={"1986"},["culmen"]={"30"},["classis"]={"3431","4663","4664","4711","4727","4728"},["fiducia"]={"2712","2714","2715"},["institutio"]={"1675"},["occurro"]={"4493"},["consecutio"]={"823"},["admitto"]={"268","3282","3322","4122"},["imbibo"]={"1385","1424"},["medeor"]={"1023"},["removeo"]={"494","2751","3592"},["quattuor"]={"420","4410"},["ioco"]={"2273"},["peculatus"]={"3900","4096"},["interrogo"]={"2251","3990"},["accedo"]={"306","904","1245","1374","1409","2196","2572","3042","3588","4076"},["pervulgatus"]={"1175","4753"},["materia"]={"2221","2224","2225"},["pestis"]={"676","918","942"},["commenticius"]={"1364"},["tyrannus"]={"3858"},["congredior"]={"3317"},["procuro"]={"3129"},["solvo"]={"699","745","2248","2469","3102","3434","3443","3514","3518","3711","4139","4675","4676","4678"},["infirmo"]={"664","2711"},["peragro"]={"225"},["cerno"]={"504","532","858","3384"},["edax"]={"3207"},["idem"]={"1375","1858","2365","2366","3756"},["administro"]={"3168","3579","3911","3933","4018","4289"},["ulciscendus"]={"2369"},["dimitto"]={"475","878","897","3673","4005","4163","4194","4438","4571","4602"},["maledictum"]={"2886"},["cibus"]={"3205","3206","3207","3208","3213","3214"},["obvolutus"]={"448"},["offero"]={"734","869","952","953"},["bonus"]={"544","1015","1768","2102","2570","3169","3170","3183","3380","3765","4025"},["periurium"]={"3067"},["emigro"]={"3193"},["nomino"]={"1226","1706"},["accessus"]={"70"},["legio"]={"4184","4185"},["eadem"]={"782","789"},["diffusus"]={"1426","1802"},["declino"]={"204","2231"},["hostia"]={"3110"},["rapio"]={"1423","4307"},["conversio"]={"2310","3784"},["ineptia"]={"1334"},["consultum"]={"3124","4000"},["stipo"]={"1000","1001"},["dimico"]={"3161","4474"},["nitor"]={"1398","2622"},["finiens"]={"95"},["haereo"]={"260","1561","1729","2201","2517"},["medius"]={"119","4488","4489"},["veto"]={"2390","3703"},["floreo"]={"581","989","1036","1131","1195","1196","1597","1972","2066","2067","3630","3724"},["sano"]={"683"},["quendam"]={"3722"},["hereditas"]={"3379","3382","3383","3384"},["lapsus"]={"2282"},["conscribo"]={"2408","3368","4169"},["dubius"]={"776","1171","1438","1443","1445"},["frequens"]={"3986"},["teneo"]={"127","577","1367","2623"},["credo"]={"1466","1467","3070","3436","4828"},["situs"]={"151","154","155","163","761","851","859","1923"},["patens"]={"4398"},["adversans"]={"1682"},["obeo"]={"714","1267","3409","3912"},["illuc"]={"288"},["videndus"]={"1406"},["significatio"]={"2178"},["vulgus"]={"1179","1182","3780"},["peiero"]={"3067"},["el"]={"480","4570"},["iacens"]={"2588"},["distineo"]={"2511"},["perfunctus"]={"3946","4210"},["nos"]={"598","1171","1824","1865","1885","1888","2347","2948","3289","3903"},["administrans"]={"3617"},["reliquus"]={"572"},["civis"]={"3765","3779","3780"},["languor"]={"1287","2451"},["delibero"]={"1482"},["tessera"]={"4365"},["procella"]={"4704"},["appello"]={"1226","1734","2178","2407","3917","3979","4706","4707"},["conclusiuncula"]={"1823"},["eiectus"]={"1745"},["praecipito"]={"299","3658"},["torreo"]={"132"},["amantissimus"]={"3778"},["oppugnatio"]={"4411"},["veneo"]={"4430"},["concursus"]={"4733"},["maior"]={"604","3994"},["conducticius"]={"4212"},["vernus"]={"392"},["occido"]={"103"},["ars"]={"1638","1650","1680","1772","1941","1950","1996","1997","2001","2055","2931"},["obsequor"]={"1043","1088","1097","2956"},["gravior"]={"4741"},["lautus"]={"3238","3267"},["inlatus"]={"4286"},["stimulus"]={"1205","1684"},["temperantia"]={"2991"},["exactus"]={"596"},["difficultas"]={"778","779","3503","3554"},["centurio"]={"3921"},["obtundo"]={"439"},["sequana"]={"171"},["ubertas"]={"2134","2322"},["matutinus"]={"416"},["declaro"]={"2365","3949","4816"},["liber"]={"1740","2408","2409","2410","2411","2413","2414","2430","2432","2433","2434","2437","2439"},["horridus"]={"458"},["praebeo"]={"438","873","979","1003","2226","2576","2911","2990","3318","4024"},["carcer"]={"4149"},["ingero"]={"4401"},["expeto"]={"2799","2800","2810","4133"},["commentarius"]={"2438"},["aries"]={"4396"},["vestimentum"]={"3197"},["instructus"]={"1635","3140"},["civilis"]={"1680","3615","3618","3620","3761"},["discedo"]={"287","1558","4797"},["expedio"]={"978","1268","4241","4724"},["obversor"]={"1340"},["tueor"]={"1009","1212","2933","3172","3598","3653"},["conicio"]={"484","2565","4064","4118","4148","4149","4250","4401","4542","4554"},["eruptio"]={"144","4403"},["conditus"]={"387","574"},["uterque"]={"1832"},["formido"]={"3082"},["accipio"]={"914","1018","1172","1887","2191","2370","2466","2731","2876","3136","3137","3267","3273","3379","3437","3687","3872","4576","4585","4621","4640"},["colonia"]={"3902","3904"},["caerimoniae"]={"3032"},["summus"]={"29","346","3664"},["allido"]={"4699"},["morbus"]={"665","667","668","671","678","679","684","685","687","723","2917","2918","4176"},["primoris"]={"1617","3766"},["rursus"]={"74"},["elaboro"]={"1247","1607"},["eructo"]={"145"},["evanesco"]={"1572","1744","2644"},["uberrimus"]={"1011","2224"},["insequor"]={"4561"},["deterior"]={"770"},["audiens"]={"2096","3047","4237"},["consolor"]={"982","983","984","986"},["animadvertendus"]={"4789"},["veho"]={"253","254"},["carmen"]={"1959","1967","1968","1969","1970","2034","3087"},["otiosus"]={"1277","1283","1610","3440"},["moriens"]={"495"},["expendo"]={"4139"},["oriundus"]={"555","558"},["aemulatio"]={"2371"},["meritum"]={"1071","1077"},["recentior"]={"1896"},["defendo"]={"2878","2880","2899","3653","3776","4071","4286"},["recordatio"]={"1551"},["annona"]={"3554","3555","3556","3557","3558","3559","3560"},["postulo"]={"329","3475","4098"},["artifex"]={"1762"},["agendus"]={"3013"},["graecia"]={"14"},["lustrum"]={"3977"},["indignus"]={"2780","2782"},["memoria"]={"623","1537","1543","1547","1548","1549","1550","1554","1555","1556","1557","1560","1563","1564","1566","1885","1900","1913","3836"},["facio"]={"77","196","213","214","274","728","745","747","794","799","810","875","894","962","963","993","1016","1018","1019","1045","1104","1105","1156","1186","1187","1217","1243","1395","1396","1487","1531","1682","1689","1810","1945","1956","1957","1993","1999","2022","2040","2090","2093","2094","2098","2154","2164","2336","2337","2338","2349","2512","2578","2629","2653","2708","2740","2742","2839","2840","2872","2895","2901","2933","2981","3067","3090","3101","3104","3105","3121","3239","3272","3279","3318","3319","3365","3368","3373","3376","3411","3416","3446","3448","3452","3455","3462","3467","3491","3505","3525","3527","3539","3540","3547","3561","3706","3749","3790","3793","3796","3900","3997","4162","4208","4270","4273","4291","4311","4355","4368","4390","4403","4404","4416","4433","4434","4461","4463","4464","4484","4520","4522","4523","4548","4578","4611","4616","4629","4631","4637","4663","4682","4698","4717","4723","4749"},["licet"]={"1457","4779","4829"},["lucrum"]={"1016","3491","3492"},["amicus"]={"4635"},["scientia"]={"1641","1642"},["poto"]={"3217"},["commercium"]={"2279","2463","3329"},["nimium"]={"2165","2277"},["umbra"]={"1694"},["veneror"]={"3029"},["promulgo"]={"3680"},["eodem"]={"832","4758"},["turbo"]={"75","2490","3804","4326","4330"},["fio"]={"22","531","1014","1745","1752","1761","1822","2240","2242","2285","2413","2826","2851","3225","3256","3296","3314","3374","3625","4610"},["religio"]={"1448","3030","3032","3046","3047","3048","3049","3050","3051","3052","3053","3054","3055","3056","3057","3058","3059","3066"},["profluo"]={"69"},["prope"]={"179","4116"},["respirandus"]={"2562"},["distinguo"]={"2439"},["proripio"]={"300"},["animal"]={"17","3567"},["tumultus"]={"3811"},["universitas"]={"0"},["cicero"]={"2416","2444","3337","4735"},["vinco"]={"2051","2860","4082","4599"},["commoditas"]={"3229"},["turpitudo"]={"1233"},["mihi"]={"318","327","328","507","570","653","692","705","706","790","862","863","1096","1108","1109","1119","1120","1157","1176","1338","1339","1382","1400","1441","1448","1458","1460","1461","1499","1500","1502","1504","1505","1852","1866","2218","2220","2221","2227","2237","2247","2429","2531","2539","2545","2690","2692","3270","3275","3287","3383","4776","4828"},["leviter"]={"672","1654","2160","2180"},["abstraho"]={"3870"},["neglego"]={"2879","2939","3173"},["armamenta"]={"4732"},["verto"]={"125","466","645","856","1100","1163","2299","2300","2301","2930","3053","3095","3137","3830","4120","4549"},["ultro"]={"289","4285"},["exquisitus"]={"1636","1948","2133"},["mors"]={"714","719","725","730","731","737","738","2545","2905","4164"},["cura"]={"692","1239","2533","2690","2691","3609","3610"},["phalanx"]={"4523","4524"},["obliquus"]={"282"},["longinquus"]={"189"},["rite"]={"3030","3107"},["expello"]={"3180","3820","3821","3861"},["artissimus"]={"1111","1799"},["minari"]={"2905"},["strictim"]={"2160"},["septentrio"]={"147","148","150","173"},["splendidus"]={"3253"},["divello"]={"2511"},["aspergo"]={"1216","1232","2266"},["angor"]={"2568","2569"},["vita"]={"567","568","572","573","617","629","715","717","728","729","733","739","947","953","956","996","998","1232","1233","1586","1695","1696","1954","2145","2146","2968","3011","3012","3226","3229","3230","3236","3277","3280","3298","3962"},["irrideo"]={"2927"},["dispositio"]={"2223"},["panis"]={"735","3215"},["undique"]={"33","1152","1358","4181","4534"},["prosperus"]={"661","804","907"},["inconstans"]={"3017"},["modero"]={"2601"},["perturbo"]={"2202","2490","2608","3799"},["habena"]={"264","266","267"},["proverbium"]={"2384","2386","2387","2388","2389","2390","2391"},["auspicor"]={"3131"},["ingravesco"]={"678","3555"},["placeo"]={"3996"},["pretium"]={"1258","3424"},["ansa"]={"884","885"},["redintegro"]={"1547","2581","2628","4470"},["illud"]={"1338","1367","1457","4761"},["persequor"]={"209","278","1103","1974","2166","2403","2803","4009","4131","4290","4562"},["munitus"]={"4382","4383"},["derideo"]={"2927"},["mediocritas"]={"2997"},["damnum"]={"1016","1020","1021","1024","1025","3491"},["arbitratus"]={"868"},["mediterraneus"]={"11"},["volumen"]={"2412"},["demitto"]={"449","1731","2586","4320"},["desipio"]={"2505"},["interrogatus"]={"2250"},["interregnum"]={"3809","3942"},["paucus"]={"330","618","1712","1923","2168","2169","2342","2540","3325","3768","3919","4745","4746"},["decessus"]={"71"},["illustris"]={"111","1702","3637"},["magistratus"]={"3675","3913","3923","3928","3929","3931","3932","3938","3939","3940"},["exemplum"]={"1700","1701","1702","1703","1704","1705","1706","1707","1708","1709","1710","1711","1712","1713","1718","1719","1720","1721","1722","1723","1724","1725","2449","2473"},["praesidium"]={"4332","4342","4343","4344","4356","4357"},["suspensus"]={"276","2651","2658"},["effloresco"]={"830"},["terminus"]={"177","2988"},["receptus"]={"4536","4537"},["varietas"]={"101"},["aequo"]={"47","4422"},["emergo"]={"48"},["commentum"]={"1334","1391"},["committo"]={"201","895","2716","2717","2839","2840","3761","4121","4123","4459"},["transigo"]={"1268","1851","3414"},["persevero"]={"1366"},["compressus"]={"482"},["habitus"]={"2479"},["peregrinatio"]={"226"},["constrictus"]={"3079"},["tumultuarius"]={"4205","4496"},["voluntas"]={"907","1030","1042","1046","1047","1050","1097","2968","3377","3705","3734"},["consulo"]={"662","976","977","1007","1211","3122","3130","3606","3654","3989","4136"},["iratus"]={"3023"},["flagitium"]={"2835","2836"},["caedo"]={"3110","3552","4158","4545","4581"},["pulso"]={"3163"},["sanguis"]={"520","732","4606"},["voluntarius"]={"722","4182"},["homerus"]={"574","1977"},["cervix"]={"452","453","454","3879"},["excito"]={"80","700","2022","2487","2504","2588","2630","2744","2825","2867","3028","3525","4270","4457"},["fundo"]={"16","1958","3186","4544","4545","4546"},["ullus"]={"1445","1446","1853"},["momentum"]={"354","826","843","844"},["fractus"]={"2589"},["cui"]={"1015","3494","4817"},["praetor"]={"3979","4088"},["perfectus"]={"1351","1358","1362","1363","1626","1934","2815"},["maxime"]={"989","1236"},["anteeo"]={"605"},["quot"]={"606","1384","1933"},["dormiens"]={"700"},["propero"]={"310"},["turris"]={"3525","4392"},["tum"]={"333","347","348","615","697","3302","4504"},["tonitrus"]={"138"},["ostendo"]={"1691","1708","2635"},["foras"]={"1180","3154","3155"},["inscius"]={"1451"},["frumentarius"]={"3553","4213","4214"},["praedatus"]={"4369"},["tuus"]={"788","868","2508","3339","3545","4779","4780","4841"},["recito"]={"1968","2472"},["exiguus"]={"359","795","3426","4197"},["faustus"]={"3099","3138"},["obsoletus"]={"2326","3198"},["opportunitas"]={"153"},["continens"]={"10","166","2989"},["furor"]={"2804","2805","2806"},["inficio"]={"1390"},["militia"]={"4174","4175","4177","4210"},["prorogo"]={"3845","3930"},["caritas"]={"3557"},["suspicio"]={"883","2744","2745","2746","2747","2748","2749","2750","2751","2752","2753","2754","2755","2756"},["altitudo"]={"2110"},["pectus"]={"47","1731","1732","2682","3046","4258","4259"},["iuvans"]={"3094"},["natura"]={"724","1928","2827","2828"},["gratissimus"]={"1045","1557"},["prex"]={"1086","1088","1090","1093","3086","3090"},["pello"]={"534","1985","2486","3180","3821","4529"},["aegrotus"]={"681","683"},["exanclo"]={"917"},["accuratus"]={"2079"},["cruentus"]={"4479"},["claresco"]={"1197"},["dissolvo"]={"1118","3453","3513","3514","3518","3531","3714","4093"},["adipiscor"]={"1153","1192","1201","3663","3856","4010","4597"},["divitia"]={"987","3170"},["insusurro"]={"440"},["persuadendus"]={"2088"},["quincunx"]={"3482","3483"},["funebris"]={"753","755","756"},["sicut"]={"4603"},["immunitas"]={"3893","4038"},["offensio"]={"2889","2893","2894","3733"},["dominor"]={"2868","3848"},["bivium"]={"212"},["reduco"]={"1127","1550","1663","4650"},["luxuria"]={"3249"},["renovatus"]={"3486"},["bene"]={"780","804","909","1069","1100","1156","1213","1633","1659","1691","1726","2251","2389","2625","2968","2969","2998","3011","3094","3095","3100","3171","3221","3267","3347","3408","3420","3612","4227","4466","4825"},["pando"]={"4682"},["depictus"]={"1333"},["desidia"]={"1287"},["investigandus"]={"1406"},["iter"]={"218","219","220","222","1255","4305","4306","4318"},["peroro"]={"2095"},["novo"]={"3057","3788"},["impulsus"]={"2806"},["colloco"]={"967","1241","1611","2650","2712","2900","2902","3189","3192","3360","3439","4343","4351","4453"},["superstes"]={"621"},["centuria"]={"3919","3920","3921"},["pars"]={"118","149","188","284","286","287","486","1787","1832","1833","2028","2030","2370","2671","2936","2937","3737","3739","3740","3741","3742","3743","3745","3746","3751","3752","3755","3759","3994"},["memoriter"]={"1545"},["versor"]={"501","778","945","946","947","957","997","1417","1419","1602","1603","1604","1623","1638","1769","1770","1841","2554","3503","3510","3590","4758"},["usus"]={"1002","1005","1284","1579","1581","1582","1583","1584","1585","1586","1588","1589","1592","2287","2293","3286","3287","3289","3399","3947","4202","4222"},["tantus"]={"133","775","1541"},["impositus"]={"158"},["infero"]={"78","467","918","956","1020","1216","1531","2872","2896","3301","4284","4285","4405","4482","4485","4575"},["adscribo"]={"3340"},["laetitia"]={"2492","2493","2494","2499","2500","2501","2502","2503","2504"},["peregre"]={"227","228"},["effusus"]={"128","264","2501","3240","4556"},["absolutio"]={"1356"},["perficio"]={"1354","4292"},["denique"]={"4743"},["septimus"]={"3953"},["assigno"]={"3897","4119"},["anatocismus"]={"3487","3490"},["humanitas"]={"1656","1657","1661","1679","2667","2668","2669","2670","2952"},["expeditus"]={"2061","2099","2115","4203"},["indictus"]={"4044","4077"},["gens"]={"174","1658","1899","4613","4655"},["cresco"]={"107","2221","2572","3555","3727","3728"},["felix"]={"805","3099"},["rumpo"]={"3373","3877","4632"},["ornandus"]={"2185"},["simulatio"]={"2916"},["pecus"]={"4557"},["introeo"]={"239"},["sed"]={"2234","2235","4744","4783","4784","4786","4793","4818","4846"},["diffluo"]={"64","1286","1302","3247","3248"},["fictus"]={"1333"},["gladius"]={"453","4254","4255","4256","4257","4258","4259","4506","4507","4508","4509","4510"},["amicitia"]={"1105","1106","1108","1111","1112","1113","1114","1115","1116","1117","1118","2355","2425","4634"},["perpensus"]={"1496"},["sevoco"]={"538","1299"},["curro"]={"2054"},["effluo"]={"1569"},["influo"]={"443"},["plausus"]={"2021"},["ratus"]={"108","3699","3700"},["miles"]={"2583","4195","4201","4203","4207","4458"},["facetia"]={"2260"},["excultus"]={"1655"},["libertas"]={"3868","3869","3873","3875","3885","3886"},["impono"]={"762","800","2435","3866","3894","4669"},["serpo"]={"1167"},["paro"]={"796","943","1136","1512","2901","3352","4191","4263"},["discrepo"]={"1864"},["nocturnus"]={"415"},["in"]={"14","31","32","92","109","125","147","160","161","163","171","172","175","200","212","220","239","244","245","250","253","257","259","260","265","281","282","284","285","286","287","291","294","295","296","303","304","319","320","326","355","362","363","364","417","418","440","443","452","454","462","471","472","473","476","477","478","479","484","486","488","491","492","506","507","509","510","512","547","550","565","568","620","645","647","665","676","698","702","703","704","705","735","746","751","759","760","762","763","772","773","774","775","777","778","787","789","816","824","829","836","838","840","847","851","853","855","856","858","859","896","907","913","915","924","937","941","942","945","946","947","948","950","953","954","956","957","958","966","967","984","992","997","998","999","1005","1012","1028","1031","1034","1038","1042","1053","1071","1104","1114","1116","1125","1127","1128","1132","1140","1149","1155","1159","1161","1176","1178","1179","1180","1181","1182","1189","1198","1221","1238","1239","1240","1241","1242","1247","1261","1272","1278","1283","1285","1298","1336","1339","1343","1345","1346","1347","1350","1366","1373","1379","1380","1397","1417","1419","1423","1437","1438","1439","1443","1480","1493","1494","1495","1499","1509","1510","1513","1532","1549","1550","1559","1561","1566","1568","1574","1576","1582","1584","1601","1602","1603","1604","1606","1607","1608","1609","1610","1611","1623","1638","1641","1653","1663","1664","1669","1670","1680","1686","1689","1690","1694","1711","1724","1725","1729","1731","1732","1736","1737","1742","1763","1768","1769","1770","1788","1796","1832","1833","1835","1839","1841","1842","1843","1844","1845","1847","1848","1860","1912","1921","1944","1947","1952","1985","2010","2011","2012","2014","2032","2062","2090","2091","2101","2155","2157","2161","2165","2174","2175","2186","2190","2191","2216","2254","2265","2269","2299","2302","2348","2356","2370","2371","2384","2386","2388","2393","2416","2428","2429","2430","2431","2432","2438","2440","2448","2453","2456","2474","2476","2487","2496","2515","2526","2543","2544","2546","2554","2555","2564","2565","2626","2631","2632","2649","2650","2659","2673","2674","2675","2677","2681","2688","2689","2712","2720","2725","2727","2747","2748","2749","2750","2753","2761","2762","2764","2766","2767","2768","2769","2771","2774","2776","2789","2790","2791","2793","2804","2818","2830","2842","2843","2889","2891","2892","2902","2903","2904","2913","2928","2930","2934","2938","2944","2949","2951","2992","3005","3007","3013","3038","3039","3050","3053","3054","3073","3074","3137","3151","3156","3157","3169","3177","3178","3179","3187","3188","3192","3239","3249","3264","3268","3280","3291","3292","3294","3296","3300","3302","3304","3308","3323","3355","3360","3361","3388","3389","3395","3397","3407","3412","3431","3432","3439","3455","3456","3457","3492","3503","3504","3505","3507","3509","3510","3527","3530","3537","3544","3545","3546","3558","3576","3581","3585","3590","3594","3608","3609","3610","3611","3615","3619","3621","3623","3627","3657","3696","3698","3704","3709","3715","3722","3744","3751","3757","3759","3774","3816","3820","3828","3832","3833","3834","3840","3844","3845","3848","3860","3865","3870","3886","3902","3909","3919","3924","3925","3930","3955","3957","3962","3979","3983","3998","4015","4017","4023","4041","4045","4046","4047","4051","4056","4062","4064","4089","4110","4111","4118","4122","4128","4135","4136","4147","4148","4149","4152","4160","4174","4190","4202","4204","4222","4239","4246","4256","4258","4260","4261","4264","4283","4287","4294","4318","4320","4340","4343","4351","4360","4361","4362","4368","4386","4415","4416","4428","4429","4445","4447","4448","4449","4474","4482","4484","4485","4488","4501","4510","4515","4521","4542","4553","4554","4560","4609","4622","4634","4638","4639","4640","4644","4645","4648","4651","4652","4653","4666","4669","4670","4680","4701","4711","4714","4716","4729","4730","4735","4753","4757","4758","4764","4765","4766","4775","4792","4801","4802"},["depono"]={"1123","1430","1472","1554","2523","2550","2641","3846","3939","4244"},["exquisitissimus"]={"3254"},["murus"]={"297","4395","4396","4402"},["tenuis"]={"2105","3225","3426"},["risus"]={"638","640","641","642","643","644","645"},["opportunus"]={"154"},["prosa"]={"2128"},["educo"]={"1659","4255","4445"},["auditus"]={"2213"},["imprudens"]={"1528","4333"},["vetustas"]={"1112","1904","2391","2551"},["neque"]={"445","4835","4839","4840"},["ramus"]={"27"},["accelero"]={"4313"},["disputans"]={"2154"},["discordia"]={"3836"},["perductus"]={"964"},["clarus"]={"1197","1700","2205","3945"},["oppeto"]={"730"},["creandus"]={"3675"},["coagmento"]={"1804"},["comprehensus"]={"1360"},["moderatus"]={"2989","2990"},["futurus"]={"363","366","367","368","427","3622"},["auctumnalis"]={"389"},["sanus"]={"525","1322","2966"},["occupo"]={"2553","3077","3438","3849","4336","4337"},["ingens"]={"4198","4577"},["circumfero"]={"485"},["magniloquentia"]={"2113"},["contero"]={"320"},["orbis"]={"9","95","115","116","118","119","177","4520","4521"},["premo"]={"627","634","779","994","2511","2568","2763","3863","3895","4374","4534"},["tento"]={"667","893","2481","4319"},["mobilitas"]={"3021"},["voluptas"]={"1290","1291","1292","1293","1294","1296","1297","1298","1299","1300","1301"},["oblivio"]={"1560","1567","1568","1573","1574","1575","1576","1577","3835","3836"},["sumo"]={"329","478","736","794","1712","1720","1813","1838","2432","2592","2596","3203","3205","3441","3862","4134","4155","4240"},["vestitus"]={"28","3198"},["litus"]={"4701","4706","4719"},["atrocitas"]={"2781"},["sub"]={"31","94","528","529","928","1794","2150","2151","2156","3871","4079","4341","4430","4646"},["prosterno"]={"302","517","4535"},["dos"]={"3359"},["praeterquam"]={"4800"},["mediocriter"]={"1623","1631","1635"},["inopia"]={"995"},["expers"]={"1647","1656","2284","2669","2958"},["proprius"]={"2375","3020"},["servitus"]={"3863","3864","3865","3866","3867","3870","3872","3878","3880","3882"},["convoco"]={"3280","3670","3984","4183","4380"},["comitia"]={"3674","3675"},["sextus"]={"385"},["evolvo"]={"1884","2411"},["posteritas"]={"1562"},["illatus"]={"2899","4586"},["quies"]={"703"},["demolior"]={"3144"},["impar"]={"4519"},["sarcio"]={"1024"},["egressio"]={"2184"},["lavo"]={"55"},["circumfluo"]={"990"},["iactatio"]={"3781"},["omnino"]={"2336","2529"},["pactus"]={"4630"},["opinans"]={"1400"},["citatus"]={"61","4307"},["cordus"]={"2690"},["brevi"]={"2157","4746","4747","4748"},["dedo"]={"1287","1294","1605","2831","2853","4426"},["abreptus"]={"2806"},["furia"]={"2976","2978"},["consularis"]={"3956"},["divulgo"]={"1180"},["maritimus"]={"72","1924","4660","4662"},["falsus"]={"1386","1413","1414","1784","2635","4097"},["virilis"]={"546","551","586","3203"},["sponsor"]={"2742"},["optio"]={"1435","1436"},["mensis"]={"4410"},["planus"]={"39"},["quis"]={"2240","2423","4064","4153"},["intercessio"]={"3981"},["ridiculus"]={"2267","2268"},["condico"]={"3263"},["despicio"]={"768"},["subeo"]={"914","951","1160","1215","1231","1337","2766","3150","4143","4393","4621"},["fortis"]={"2576"},["argentarius"]={"3452","3453"},["labefacto"]={"2722","3050","3798"},["conturbo"]={"2490"},["affligo"]={"919","937","2582"},["tormentum"]={"2905","4060","4061","4063","4400"},["vagus"]={"112"},["redimo"]={"3520","3887","3970","4625"},["occupatio"]={"1594"},["fluctus"]={"58","59","3761"},["minitor"]={"2905","2906"},["deleo"]={"86","1235","1560","1575","2752","3049","3836","4034","4580","4581"},["describo"]={"1927","2179","3573"},["spiro"]={"2453"},["multi"]={"1246","1628","3207"},["conquiesco"]={"1608"},["usitatus"]={"2326"},["provectus"]={"590","591","2193"},["puritas"]={"2124"},["frango"]={"130","452","2582","2588","2721","2737","4617","4632"},["meridianus"]={"415"},["firma"]={"661","663"},["tempestas"]={"126","129","137","4681","4703","4704"},["coorior"]={"126"},["ales"]={"3133"},["fides"]={"971","1908","1982","1983","1984","1985","2707","2708","2709","2710","2711","2716","2718","2719","2721","2722","2725","2726","2727","2728","2729","2730","2731","2732","2733","2734","2735","2736","2737","2740","2741","3497","3501","4428","4429"},["mundus"]={"0","3","4","5","3779"},["anima"]={"560","562","716","718"},["pol"]={"2024"},["inveteratus"]={"1389","2776"},["amplius"]={"382","383"},["commotio"]={"2483"},["nuptia"]={"3351","3352"},["vos"]={"503","4752"},["vinculo"]={"1111"},["superbia"]={"2591"},["torqueo"]={"2657"},["socordia"]={"1288"},["deduco"]={"1372","1658","2723","3160","3468","3902","4351","4665"},["transfigo"]={"4259"},["mens"]={"488","538","1321","1324","1335","1339","1345","1494","1527","1561","2453","2490","2611","2615","2969","2976","3077"},["et"]={"3","7","8","38","70","72","75","99","108","110","136","148","183","288","383","414","421","487","504","633","637","673","786","823","833","888","907","927","1049","1084","1172","1228","1246","1247","1253","1264","1265","1285","1287","1288","1289","1315","1351","1354","1356","1358","1413","1428","1486","1551","1628","1644","1652","1656","1657","1682","1718","1745","1757","1762","1767","1768","1772","1774","1776","1777","1781","1786","1788","1790","1795","1797","1801","1861","1917","1980","1981","1998","2061","2079","2099","2115","2123","2134","2224","2225","2261","2262","2273","2289","2291","2360","2371","2445","2464","2466","2511","2558","2577","2588","2589","2644","2687","2688","2724","2813","2834","2858","2897","2905","2922","2948","2978","3008","3016","3021","3043","3073","3106","3109","3161","3197","3213","3329","3347","3418","3454","3465","3495","3570","3572","3609","3611","3642","3644","3779","3815","3931","3945","4025","4064","4239","4262","4389","4431","4446","4528","4545","4546","4586","4646","4679","4753","4810","4836","4837"},["desperatio"]={"2617","2618"},["multus"]={"407","3312","4751","4753"},["constanter"]={"2601"},["procurro"]={"160","161"},["prospicio"]={"367","976","1007","3622","4214"},["absolutus"]={"1351","1352","1936"},["insidia"]={"2900","2901","2902","2903","2904"},["fusior"]={"2167"},["confirmatus"]={"1389"},["locupletior"]={"2278"},["eruditio"]={"1647"},["trientarius"]={"3481"},["spero"]={"1691","2624","2625"},["nihilum"]={"3423"},["nubo"]={"3356"},["fusus"]={"2106","4562"},["princeps"]={"2071","2072","3584","3585","3617","3656","3766"},["sic"]={"766","781","1462","1465","2153","2369","3148"},["absolute"]={"2194"},["offundo"]={"1323"},["quadripartitus"]={"388"},["ingeniosus"]={"1311"},["quoad"]={"569"},["intimus"]={"14","1120"},["species"]={"704","706","1359","1360","1639","1788","2910","2911","2912","2913","2915"},["vestigium"]={"278","279","280"},["constituo"]={"800","1227","1795","2981","2987","3190","3424","3526","3571","3706","3858","3904","4135","4152","4440","4449","4711"},["metior"]={"2985"},["terror"]={"2552","2563","2564","2565"},["severus"]={"1660","3006","3177"},["ventus"]={"75","89","122","123","124","125","146","4687"},["forma"]={"1358","1359","2320","3568","4653"},["meus"]={"539","545","693","772","789","1010","1119","1381","1383","2522","2541","3007","3012","3148","3339","3396","3397","3403","4112"},["cohibeo"]={"652","2795","2859","2862"},["iuro"]={"3061","3709"},["adimo"]={"692","881","2636"},["enuntiatio"]={"2317"},["oppono"]={"1836"},["renovo"]={"1547","4470"},["sterno"]={"190","255"},["insperans"]={"1400"},["infamo"]={"1217"},["valeo"]={"672","848","1035","1131","1133","1135","1313","1324","1539","1687","2065","2069","2345","2365","2368","3345","3346","3724","4662"},["ulciscor"]={"2799","2800","2801","4130"},["improbus"]={"3765"},["iacto"]={"58","673","929","2908","3447"},["herba"]={"22","3544","3545"},["dissideo"]={"1859","1872","2772"},["excido"]={"1569","1570","2344"},["cingo"]={"4389","4517"},["dilucidus"]={"3703"},["doctrina"]={"798","1579","1581","1627","1634","1635","1636","1637","1639","1678","1751","1776"},["ripa"]={"63","64"},["caerimonia"]={"3059"},["conspectus"]={"508","509","510","511","512","513","2155","2157","2158"},["fragor"]={"137"},["primus"]={"1617","1677","2030","3669"},["perscribo"]={"1881"},["captatio"]={"2396"},["optimas"]={"3763","3764","3765"},["consequens"]={"1826"},["error"]={"208","1417","1418","1419","1421","1422","1423","1424","1425","1427","1428","1429","1430","1431"},["suscipio"]={"549","951","1122","1252","1266","2766","2774","2842","3056","3101","3776","4075"},["fingendus"]={"1997"},["dissimulo"]={"2918"},["symphoniacus"]={"1989"},["mediocris"]={"1474","2206"},["haesito"]={"2201"},["errans"]={"112","207"},["compos"]={"1320","2609","3103"},["similis"]={"1411","2381","4758"},["captivus"]={"4624","4625","4626"},["custodio"]={"1546"},["fingo"]={"521","1049","1326","1365","2154","2349"},["quorsum"]={"806","4824"},["transitio"]={"3647"},["eius"]={"1560","1561","2344","2753"},["rogo"]={"1085","3684","3990","4180"},["status"]={"2605","2606","3660"},["littera"]={"568","1594","1595","1598","1599","1600","1601","1602","1603","1604","1605","1606","1607","1608","1609","1610","1611","1613","1614","1615","1617","1618","1619","1620","1621","1622","1623","1632","1641","1647","1651","1652","1653","1654","1665","1672","1677","1680","1739","1884","2372","2392","2397","2398","2399","2400","2401","2402","2403","2459","2464","2465","2466","2467","2472","2473","2474","2478","2952"},["arbor"]={"22","26","3551","3552"},["libo"]={"3115"},["moderor"]={"271","2993"},["imber"]={"62","127","128"},["propello"]={"4693"},["augeo"]={"906","1223","1645","2189","2580","3600"},["potio"]={"633","3213"},["libero"]={"3517","4408","4409"},["petitio"]={"4087"},["maturo"]={"310","4313"},["perpetuus"]={"364","2078","3244","3485","4022","4757"},["poeta"]={"1960","1962","1963"},["telum"]={"4247","4251","4252"},["contineo"]={"20","21","33","167","420","562","644","654","852","1398","1660","1769","2426","2795","2858","2862","3813","4239","4366","4651"},["lumen"]={"497","499","1323","1621","2131","3532"},["seditiosus"]={"3785"},["promitto"]={"455","3260","3262"},["dicendus"]={"2055","2056","2057","2058","2059","2060","2061","2062","2066","2068","2069","2089","2093","2094","2099","2104","2105","2107","2131","2182","2189","2312","2320","4004","4073","4776"},["peto"]={"292","1488","1709","1713","1813","3123","3321","3736","3913","4132","4195","4425","4555"},["subicio"]={"78","2150","2156","3372","4642","4643"},["subdo"]={"261"},["frustra"]={"1253"},["initio"]={"3035"},["crebritas"]={"2135"},["aestas"]={"393"},["dominus"]={"2016","4062"},["divinus"]={"1347","3022","3032","3033","3041","3105","3107","3806"},["lito"]={"4080"},["crux"]={"2905","4160","4161"},["clueo"]={"738","747","2481","2560","2722","2888","2892","3413","3471","3972"},["inflatus"]={"1966"},["prospectus"]={"34"},["sequens"]={"374"},["gestio"]={"2500"},["intellego"]={"2346","2362","2363","4804","4805","4807"},["obsigno"]={"2468","3369"},["interpretor"]={"708","2303"},["equus"]={"215","254","255","256","257","258","259","260","261","262","263","265","268","269","270","271","272","273","3566","4178","4371","4476"},["conflo"]={"955","1231","2766","2770","3506","4271"},["facesso"]={"1274"},["sacramentum"]={"4179","4180"},["germania"]={"149"},["imitor"]={"1951"},["admirabilis"]={"2701"},["propius"]={"179","306","3042"},["aestus"]={"70","71","72","73","74","136","673","4721"},["constitutio"]={"663"},["infitior"]={"4762"},["novissimus"]={"4299","4329","4330","4331","4332"},["salus"]={"734","957","976","3341","3601","3610"},["orior"]={"69","103","2394","4278"},["eum"]={"729","787","3148","3302"},["satisfacio"]={"1089","1097","2655","2881","2934"},["deiectus"]={"3667"},["fuga"]={"3240","4542","4548","4551","4552","4553","4554","4555","4556","4559","4560","4566","4573"},["dego"]={"567","568","998","3567"},["amoenitas"]={"43"},["syria"]={"3907"},["disiunctus"]={"183"},["commodum"]={"1008"},["pondus"]={"8"},["plebs"]={"3645","3646","3647","3648","3792","3813"},["demoveo"]={"2605","3181","3659"},["a"]={"20","35","150","184","236","464","538","539","553","555","576","577","901","1050","1094","1142","1158","1250","1299","1368","1388","1404","1405","1408","1410","1413","1473","1506","1514","1635","1658","1709","1710","1713","1749","1783","1784","1792","1824","1854","1872","1905","1942","1990","2192","2231","2290","2352","2353","2394","2460","2478","2560","2723","2751","2756","2820","2822","2823","3007","3028","3083","3117","3171","3311","3381","3393","3394","3592","3593","3701","3755","3791","3879","3886","3890","3922","3979","4003","4064","4079","4115","4116","4125","4322","4425","4495","4516","4635"},["equitatus"]={"4518","4539"},["porticus"]={"3970"},["deverto"]={"3268"},["quin"]={"324","653","654","1533"},["contumeliosus"]={"2883","2885"},["morte"]={"721","722","4154"},["adulterinus"]={"3430"},["collis"]={"35","150"},["complexus"]={"2427"},["nonnullus"]={"4795"},["contaminatus"]={"2833"},["scribendus"]={"1911","2104","2217","2218","2406","2407","2456"},["postulans"]={"1094"},["effero"]={"15","743","902","903","1146","1149","1179","1180","2503","2594","2787","3152","3153"},["sors"]={"2538","3907"},["orcus"]={"3025"},["vix"]={"643","653","654","2611","4769"},["quadrans"]={"3480"},["aedificandus"]={"3521","3970"},["incultus"]={"41"},["servo"]={"959","1556","1916","1917","2614","2718","2732","2933","2979","3066","3132","3212","3390","4323"},["irritus"]={"807","2640","3373","3699"},["trivium"]={"212"},["usque"]={"174","3258"},["conduco"]={"3520","3521","3887","3970","4189"},["confuto"]={"1816"},["puto"]={"808","1379","2352","3463"},["descisco"]={"1405","2822"},["alienatus"]={"1321"},["coniungo"]={"4281","4358"},["calculus"]={"3461"},["certamen"]={"2053","3741","4447","4477","4478"},["prenso"]={"3916"},["u"]={"2369"},["nuntio"]={"1184","3333"},["deicio"]={"296","297","298","494","1371","2606","2607","2639","3181","3660","3842","3879","4531","4702"},["evado"]={"806"},["suppono"]={"3372"},["contraho"]={"460","1105","3413","3415","3505","4121","4189","4684"},["depingo"]={"1329","2146"},["inquisitio"]={"1407"},["demeto"]={"3548"},["comicus"]={"1963"},["hebesco"]={"1285"},["refero"]={"277","1006","1059","1063","1065","2424","2438","2813","2986","3038","3039","3455","3459","3594","3607","3715","3816","3988","4045","4089","4538","4598"},["quasi"]={"1323","2153","2161","3073","4766"},["exardesco"]={"2694","2786","4278"},["vado"]={"66"},["luxus"]={"1289"},["exsilium"]={"3820","3828"},["deperditus"]={"2420"},["incutio"]={"2552","3052"},["blanditia"]={"1297"},["sinus"]={"13","163","2496","2689"},["consequentia"]={"1822"},["complexo"]={"900"},["corruptus"]={"2291","3003","3004"},["paeninsula"]={"161"},["appeto"]={"391","1113","3855"},["antiquior"]={"2692"},["probo"]={"1157","1158","1707","1811","1826"},["publico"]={"3818"},["necessarius"]={"813","3140","3226","3228"},["suadeo"]={"3682"},["aucupium"]={"2396"},["familiariter"]={"1110","3284"},["colloquium"]={"429","3321","3322"},["astrum"]={"110"},["ne"]={"1765","2337","3691","3692","3954","4064","4740","4741","4744","4750","4751","4752","4753"},["tarditas"]={"1318"},["allatus"]={"824","1184","1185","2464"},["morti"]={"734"},["perculsus"]={"2558","2589"},["dicio"]={"4637","4646","4647","4648"},["acutus"]={"1819","2206"},["tolero"]={"395","628","996","3236"},["quieto"]={"2537"},["demonstro"]={"1808"},["vincio"]={"2130"},["circumfundo"]={"314"},["occasus"]={"104"},["is"]={"4749"},["infixus"]={"114","1729","2517"},["paene"]={"2151","2505"},["implico"]={"1421","4275"},["contumelia"]={"2882","2884"},["cado"]={"123","303","528","792","806","808","847","1161","1495","1842","1848","1995","2025","2129","2393","2584","2585","2640","2747","2749","3397","4084","4593","4764"},["ruina"]={"3141","3143","4397","4398"},["defungor"]={"921"},["laedo"]={"2721"},["venalis"]={"3419"},["observo"]={"1228"},["eruditus"]={"1626","1627","1650"},["intersero"]={"819"},["portus"]={"1736","4678","4681","4718","4719"},["transfero"]={"1284","1973","2299","2301","2304","2307","2308","3306","4118","4234","4294","4765"},["subsido"]={"2904"},["erigo"]={"442","2587","2630","2977","3525"},["disiunctissimus"]={"225"},["quidem"]={"1382","1383","1765","2328","2337","4784","4785","4787","4820","4834","4837","4838"},["obtingo"]={"3907"},["luculentus"]={"1701"},["alius"]={"326","825","1309","1396","1691","2920"},["coniunctum"]={"1111","1112","1798","1799","2283","3286"},["dominatus"]={"3762","3763","3769","3883"},["oblitero"]={"1571","1572"},["sal"]={"97","2266"},["divus"]={"94"},["accurate"]={"2436"},["deficio"]={"105","542","2585","2820","3498","3791"},["permisceo"]={"3806"},["egressus"]={"613"},["partiendus"]={"1790"},["rogatio"]={"3680"},["capesso"]={"3589","4174","4552"},["oratio"]={"443","756","2073","2074","2075","2077","2078","2079","2080","2092","2098","2104","2106","2108","2109","2110","2115","2116","2117","2118","2119","2120","2121","2122","2123","2124","2125","2126","2127","2128","2129","2130","2134","2138","2142","2170","2186","2187","2195","2197","2203","2234","2236","2266","2281","2284","2319","2431","2449","4771"},["liberaliter"]={"1659"},["mitigo"]={"432"},["derogo"]={"2710","3497"},["comitium"]={"3676","3677"},["lego"]={"2441","2445","2450","3375","3961","3983","4186","4685"},["nobilitatus"]={"3631","3767"},["stirpes"]={"20","21"},["iniuria"]={"935","2803","2872","2873","2874","2875","2876","2877","2878","2879","2880","2881","4014","4839","4840"},["meto"]={"3540"},["propono"]={"502","503","1078","1508","1719","2175","2237","2241","2633","3419","3696","3697","4443","4619"},["exeo"]={"240","713","1180","2393","3154","3516","3824","4681","4715","4716"},["clemens"]={"1835"},["iracundia"]={"2369","2784","2786","2787","2795","2797"},["obductus"]={"4590"},["exsulatus"]={"3829"},["veteranus"]={"4201"},["possessio"]={"3178","3179","3180","3181","3182","3184","3814"},["aedifico"]={"4","4663"},["cicatrix"]={"4588","4590"},["coniector"]={"709"},["ab"]={"35","146","168","178","324","387","463","494","554","558","578","793","795","817","828","944","1037","1042","1095","1153","1213","1284","1342","1375","1488","1577","1657","1665","1666","1813","1859","1904","1950","2194","2213","2253","2301","2351","2355","2772","2797","2799","2802","2880","2940","2941","2946","2955","3012","3028","3123","3258","3305","3382","3383","3437","3441","3470","3471","3726","3747","3757","3882","4132","4133","4245","4266","4600","4797"},["dissentio"]={"1375","1859","3757"},["compleo"]={"616","4185"},["socius"]={"3281","3282","3744","4633"},["utor"]={"3574","4736","4754","4759"},["perstringo"]={"2160"},["venia"]={"4780"},["dignitas"]={"1136","1139","1140","1141","1142","3653","3654","3655","3656","3657","3658","3659","3661"},["excusatio"]={"688"},["subsum"]={"394"},["singulus"]={"379","417","3558"},["debeo"]={"1057","3435","3493","3494","4807","4835"},["praetereo"]={"316","371","1452","2176"},["gaudium"]={"657","2492","2497","2498","2499","2503","2505"},["fatigo"]={"1086"},["effervesco"]={"2786"},["vicis"]={"2508"},["prior"]={"372"},["invidia"]={"2760","2761","2763","2764","2765","2768","2769","2770","2771","2775","3728","3732","3735","3736"},["facilis"]={"2019","2061","3278"},["affinis"]={"4117"},["egestas"]={"995","997","998","999"},["amplector"]={"1600","2678"},["solemnis"]={"3108"},["iungo"]={"1105","3272","3344","3529","4188","4358"},["porta"]={"241","3167","4363","4414"},["sollicito"]={"2531","2567","3792"},["admiratio"]={"2695","2696","2697","2698","2699","2700"},["lacero"]={"2886","3252"},["obtrecto"]={"1208"},["artificium"]={"1777","1935"},["iste"]={"1699"},["bonae"]={"1593","1692"},["omissus"]={"4507"},["provideo"]={"366","4213","4215"},["exanimo"]={"563","2556"},["medicina"]={"1697"},["flo"]={"146"},["caedes"]={"2907","4568","4577"},["centesimus"]={"617"},["magnificentia"]={"2048"},["auditio"]={"1172"},["impello"]={"818","2804","4530"},["iucundus"]={"1259","2270","2680"},["communis"]={"1004","1325","2197"},["codex"]={"3454"},["odium"]={"2764","2766","2767","2768","2771","2773","2774","2776","2778","2779"},["melior"]={"770","772","773","2625","2632","3098"},["arbitrium"]={"865","866","867","868","1049","1944","3764"},["siccitas"]={"2118"},["aspernor"]={"1093","1225"},["custodia"]={"4147","4344","4362","4719"},["impingo"]={"451"},["specimen"]={"1359"},["etiam"]={"365","1085","4789"},["separo"]={"4064"},["rudis"]={"1647","2062","4223"},["maleficium"]={"1066","1067","1068","2974"},["silva"]={"28"},["acerbus"]={"2513"},["recreo"]={"685","1303","2561"},["talis"]={"729"},["odor"]={"3106","3543","3810"},["securis"]={"3110","4159"},["aedificium"]={"82","3523"},["patefacio"]={"195","437"},["percrebresco"]={"1180"},["iniungo"]={"3866"},["sapiens"]={"846","847","2362"},["identidem"]={"365"},["cognosco"]={"2445","4039"},["finis"]={"169","170","728","729","799","800","801","803","2094","2987","4291"},["ferus"]={"4513"},["dodrans"]={"3385"},["sortior"]={"3906"},["circumvenio"]={"4364","4516"},["internecio"]={"4581","4655"},["facilitas"]={"3278"},["exsul"]={"3832"},["tamquam"]={"7","3148"},["accedens"]={"72"},["subduco"]={"3460","4666"},["bis"]={"1933","3951"},["occasio"]={"869","870","871","872","873","876","877","878","879","880"},["memini"]={"1578"},["disertus"]={"2063","2086"},["debitor"]={"3493"},["infimus"]={"31","35","771","1090","3640","3642","3651"},["surgo"]={"701"},["averto"]={"3096","3899","4316"},["impedio"]={"224"},["corripio"]={"84","667","2392"},["demissus"]={"2589"},["tranquillo"]={"2537"},["fames"]={"627","628","630","631","632","633","4387"},["dissensio"]={"1868","3758"},["inclino"]={"898"},["expeditio"]={"4287"},["insequens"]={"374"},["aeger"]={"664","675","2919"},["levitas"]={"3021"},["adhuc"]={"3545","4079"},["perditus"]={"776","912","2421","2999","3003"},["noster"]={"337","338","339","340","623","1559","1898","3389"},["amo"]={"2682","2683"},["praecipiendus"]={"1728"},["sacrum"]={"3034","3035"},["corona"]={"2022","3871","4430"},["paeniteo"]={"2541","2542"},["scio"]={"1449","1450","1453","1454","1587","1651","2296","2297"},["trado"]={"473","690","1294","1563","1605","1669","1670","1727","1754","1758","1777","1886","1938","2057","2717","2725","3001","3857","4233","4424"},["repente"]={"128"},["deprehendo"]={"2471","4046","4047","4731"},["excutio"]={"641","3878"},["ornatus"]={"2083","2121"},["explodo"]={"2026"},["perpetuitas"]={"1786","2141"},["digero"]={"2222","2401"},["praeditus"]={"526","1141","1312","1583","1686","1688","2811","2959"},["intellegens"]={"1942","1943","1948"},["interitus"]={"944"},["reficio"]={"1303","4667"},["philosophus"]={"1698","1741","1743","1785"},["duco"]={"50","199","325","470","554","560","561","747","794","1142","1143","1154","1535","1609","1813","2351","3354","3355","4282","4308","4354","4609"},["emendate"]={"2315"},["nutus"]={"8","1048","1049"},["culter"]={"4260"},["ambio"]={"3914"},["ieiunium"]={"3212"},["conveniendus"]={"3320","3321"},["sidus"]={"111","114","1929","1930"},["assuefactus"]={"3387"},["semper"]={"1561"},["praedico"]={"1150","1151","4777"},["immolo"]={"3110","3113"},["patrimonium"]={"3250"},["repraesento"]={"1554"},["integer"]={"525","863","864","4023","4050","4526","4528"},["improbo"]={"3136"},["collum"]={"158"},["an"]={"1436","1847","2246","3116"},["eludo"]={"2931"},["contestor"]={"3093"},["coniectus"]={"4251","4252"},["decerto"]={"4472"},["ancora"]={"4677","4708","4709","4710","4712","4713","4714"},["arma"]={"1521","3876","4166","4167","4183","4188","4240","4241","4244","4248","4249","4285","4424","4444","4446","4558"},["inter"]={"148","481","1459","1479","1797","1801","1865","1870","2071","2140","2144","2466","2651","2948","3222","3261","3289","3342","3344","3414","3795","3908","4103"},["calor"]={"99","130"},["mordeo"]={"2973"},["foedus"]={"4631","4632"},["equester"]={"3635","3641","4462","4463"},["freni"]={"269","1685"},["navigium"]={"4734"},["dubitatio"]={"1440","1441","1442","1446"},["redoleo"]={"2126","2127"},["iuventus"]={"4166"},["pater"]={"340","552","2477","3381"},["polluo"]={"3109"},["metallum"]={"3446","3898"},["gratis"]={"3423"},["stadium"]={"2054"},["levis"]={"3017","4200"},["repudio"]={"1093","4621"},["enitor"]={"1263","1265"},["amicissimus"]={"1119"},["censorius"]={"553","3971"},["exalbesco"]={"2557"},["erudio"]={"1666","1680"},["splendor"]={"1232"},["secundum"]={"3656","4464"},["tergum"]={"4549","4550"},["abundans"]={"2136","2323"},["mendum"]={"2454"},["invito"]={"3259","3276"},["dominatio"]={"3768","3851","3883","3886"},["naufragium"]={"4698","4705"},["compenso"]={"1025"},["adamo"]={"1601","2681"},["gymnicus"]={"2052","2053"},["tempero"]={"653","3572"},["repeto"]={"1026","1548","1709","1713","1904","2194","2353","2802","4132","4266"},["exspecto"]={"2658"},["no"]={"538","3220","3992","4255","4497"},["erectus"]={"2577"},["iniquitas"]={"775","932"},["dolor"]={"432","983","2509","2510","2511","2512","2513","2514","2515","2516","2517","2518","2519","2520","2521","2522","2523","2524","2525"},["pro"]={"80","545","546","731","732","733","734","785","786","960","1059","1060","1068","1073","1265","1457","1807","1854","1856","2306","2742","2801","2881","2926","3058","3113","3161","3683","3957","4057","4058","4070","4130","4363"},["annotinus"]={"4674"},["attribuo"]={"4119"},["exprimo"]={"1953","2138","2304","2305","2397"},["unda"]={"59"},["alpes"]={"32"},["libros"]={"3130"},["percurro"]={"2446"},["raptim"]={"4308"},["reus"]={"4089","4091"},["concitatio"]={"3781"},["manifesto"]={"4047"},["familia"]={"1746","2015","2044"},["patricius"]={"3770"},["abstergeo"]={"2549"},["intendo"]={"216","486","1343","4078"},["tempus"]={"183","316","317","318","319","320","321","322","323","324","325","326","329","331","332","333","334","335","336","337","338","341","342","344","349","350","351","352","353","354","355","356","357","358","359","361","362","369","388","389","392","415","416","568","601","775","785","786","1250","1283","1610","1897","1899","1900","1902","1904","1915","1916","1917","1918","1919","1920","1921","2076"},["irruptio"]={"4416"},["vituperatio"]={"1160","1161"},["replico"]={"1900"},["laetissimus"]={"3542"},["alieno"]={"1050"},["repetunda"]={"4098"},["casus"]={"367","887","927","928","929","930","2604","3622"},["fidis"]={"1981"},["consaluto"]={"3342"},["moenia"]={"4393"},["omitto"]={"878","2559","4772","4796"},["silentium"]={"412","2176"},["cognitus"]={"1579","1588","1646","4077"},["falsum"]={"1413","2642","2926"},["passim"]={"290"},["locus"]={"43","114","151","152","153","183","837","872","1771","1815","2035","4310","4382","4781","4782","4791"},["gerens"]={"3407","3408"},["palus"]={"4157"},["ira"]={"2783","2785","2788","2790","2791","2792","2793","2796"},["impietas"]={"3075"},["tego"]={"1377"},["auctor"]={"1715","1883","2404"},["demoror"]={"4752"},["ascribo"]={"1116","3627"},["praevideo"]={"366"},["pactio"]={"4629"},["sepultura"]={"744","757"},["emano"]={"1180"},["transeo"]={"66","316","2982","4234"},["continuo"]={"3928","3929","4314"},["liberalis"]={"1593","1940","3245"},["ego"]={"654","692","742","818","985","986","1012","1094","1158","1394","1433","1434","1452","1514","1567","1592","1854","1856","2531","2541","2542","2619","2620","2623","2643","3383","4829"},["plaga"]={"740","4584"},["permotio"]={"2483"},["proficiscor"]={"172","206","228","308","309","310","795","828","1783","1784","1792","3828","3909","3957","4287"},["exsisto"]={"2243","3028"},["gerendus"]={"3615","3625","4220","4296"},["linum"]={"2469"},["proscribo"]={"3814"},["fluo"]={"290","832","1751","3809"},["planum"]={"1810"},["ager"]={"52","65","3192","3533","3534","3537","3546","3896","3897","4368"},["politus"]={"2079"},["impetus"]={"3015","4484","4486","4487"},["redeo"]={"219","1128","1549","1664","2012","2232","2233","2234","2343","2613","2943","2963","3196","3834","3898","4502"},["assentator"]={"437"},["novus"]={"1782","3633","3780","3785","3787"},["vitium"]={"2281","2665","2811","2830","2831","2832","2833","2834","2835","2837"},["tenus"]={"46"},["millies"]={"4767"},["decimum"]={"609","611","613"},["figura"]={"1927"},["praecipio"]={"1328","1726","2389","3002","4601"},["impero"]={"2858","2861","4171","4628"},["maiestas"]={"4100"},["hora"]={"433","434","435"},["insculptus"]={"3073"},["decurro"]={"283","4261"},["hospitium"]={"3270","3271","3272","3273","3274"},["as"]={"1880","1883","3385"},["lectus"]={"669","701"},["respiro"]={"2560"},["colum"]={"3478"},["frequento"]={"1674","3146"},["incumbo"]={"1242","3608","4283"},["reflo"]={"4687"},["dum"]={"327","543","569"},["desudo"]={"1247","1694"},["subiectio"]={"2151"},["silex"]={"190"},["cur"]={"815"},["sollicitus"]={"2528","2531"},["praeclare"]={"780","1069"},["fascis"]={"3964"},["frux"]={"15","16","2964"},["molestus"]={"2507","2780"},["incresco"]={"130"},["delectatio"]={"2452"},["recondo"]={"1638","4256"},["consequor"]={"311","1011","1192","1201","1393","1642","1690","3725","4563"},["debilitatus"]={"2534","2558"},["tus"]={"3106"},["definiendus"]={"1790","1793"},["torpeo"]={"134"},["triarii"]={"4502"},["iam"]={"386","619","1745","4603"},["reputo"]={"1492"},["universus"]={"1788"},["patior"]={"2877","3869"},["adventus"]={"244"},["intermitto"]={"324","1249","1250","4315","4467"},["excursio"]={"4368","4404"},["nuncupo"]={"3101"},["undo"]={"2741"},["congressus"]={"3295","3323"},["marmor"]={"1999"},["expletus"]={"1358"},["immaturus"]={"719"},["collocatus"]={"3657"},["obstruo"]={"198","3167","3532","4412"},["delicatus"]={"3214","3246"},["translatus"]={"2309","2376"},["cuniculus"]={"4399"},["parens"]={"2823","3639"},["vindico"]={"944","1577","3886"},["irrogo"]={"4145"},["repto"]={"3471"},["diverbium"]={"2036"},["mentio"]={"1187","1188","1189","1190"},["intercludo"]={"197","564","2212","4217","4218"},["commendo"]={"1200","1562","1563"},["incolumis"]={"4432"},["edictum"]={"3697"},["flamma"]={"84"},["exstinguo"]={"721","1575","2487","2779"},["laudo"]={"1155"},["repetendus"]={"817"},["falso"]={"1385"},["neco"]={"87","631"},["effundo"]={"63","646","647","732","2515","2789","2790","3249","3250"},["romanus"]={"1653","1710","1875","1876","1878","1879","1881","1913","1973","4634","4654"},["diffundo"]={"27","315"},["indicium"]={"4817"},["pertineo"]={"174","845","846","2747","3227"},["adventicius"]={"537"},["purus"]={"2123","2291","3203"},["ternus"]={"3474"},["splendidissimus"]={"3635"},["districtus"]={"1270"},["o"]={"2782","4179"},["mundanus"]={"3779"},["propter"]={"548"},["acumen"]={"1317"},["succurro"]={"1338"},["familiarissimus"]={"1120"},["diuturnitas"]={"2551"},["fundamentum"]={"3524"},["eligo"]={"1712","3983"},["cum"]={"137","166","333","334","385","431","649","650","780","791","923","1025","1105","1108","1109","1111","1121","1122","1127","1128","1164","1174","1414","1425","1478","1492","1493","1671","1798","1846","1851","1858","1859","2283","2340","2465","2525","3270","3272","3279","3283","3286","3287","3288","3294","3299","3300","3309","3317","3328","3344","3357","3365","3413","3414","3415","3463","3490","3668","3672","3747","3749","3797","3843","4013","4014","4029","4064","4188","4230","4247","4276","4280","4304","4431","4490","4491","4496","4504","4592","4614","4616","4629","4631","4780","4797"},["defero"]={"295","1080","1102","3669","3838","3857","3935","4088","4233","4381","4689","4702","4704"},["resto"]={"1448"},["exstirpo"]={"2670","2834","2871"},["inconditus"]={"1970","2107"},["refreno"]={"2863"},["intermissus"]={"361","375","1616"},["procul"]={"178","3097"},["mano"]={"520","827","832","1165"},["mons"]={"28","29","31","33","159","283","299","4339","4340","4341"},["subsisto"]={"4334"},["persolvo"]={"1077","2733","3102","4139","4207"},["converto"]={"487","488","1048","2267","2299","2300","2301","2308","2766","4316","4317"},["praeeo"]={"3087"},["imperitus"]={"1590"},["regio"]={"11","281","1922","1924","3267","4310"},["supplementum"]={"4186"},["adulescens"]={"599","1691","1692"},["hic"]={"2","174","337","338","370","384","548","623","761","765","782","806","810","832","865","986","1337","1412","1809","1897","2254","2256","2302","2308","2331","2347","2357","2358","2359","2393","2425","2444","2474","3315","3496","4135","4618","4773","4774","4775","4781","4782","4784","4785","4787","4788","4791","4824"},["praeceps"]={"295","937","938","2793","2855","4556","4559"},["obicio"]={"4253"},["testamentum"]={"3368","3369","3370","3371","3372","3373","3374","3376"},["conqueror"]={"1164"},["vigilia"]={"4345","4361","4364"},["currens"]={"2115"},["translatio"]={"2310","2377","2380"},["attendo"]={"1307","1308"},["desero"]={"2821","2937","2939","3534","3535","4471"},["magnificus"]={"1347"},["humanitus"]={"790"},["numerosus"]={"4198"},["nummarius"]={"3450","3503"},["materies"]={"2226"},["sufficio"]={"3924"},["aequabiliter"]={"2116"},["adiungo"]={"1581","2321","2709","3281"},["legitimus"]={"3927"},["praes"]={"2757"},["labrum"]={"1617"},["extremus"]={"188"},["apud"]={"1033","1034","1035","1037","1133","1134","1135","1221","1856","1889","2032","2090","2154","2338","2347","2447","2610","2762","2888","3027","3148","3149","3187","3269","3726","4067","4088","4455","4456"},["occidio"]={"4582"},["pateo"]={"2367","3275","4809"},["locutio"]={"2327"},["emetior"]={"218"},["involutus"]={"1793"},["gestus"]={"1709","1876","1913","4228"},["creditus"]={"3443"},["insisto"]={"279"},["praematurus"]={"719"},["expolitus"]={"1655"},["umquam"]={"1560"},["turba"]={"3963"},["intro"]={"239"},["festum"]={"3116","3117"},["parco"]={"1248","3241"},["aqua"]={"44","45","46","47","48","49","50","51","53","54","56","636","3815"},["histrio"]={"2015","2026","2027"},["intercedo"]={"422","1108","1109","2948","3270","3289","3695"},["simulo"]={"2917","2919"},["contumacia"]={"2598"},["aversus"]={"1042","1404","2955","4318","4494","4516","4588"},["omnis"]={"286","486","568","840","917","930","1148","1261","1263","1344","1459","1610","1611","1627","1629","1655","1656","1657","1771","1801","1860","1899","1952","2549","2604","2667","2668","2669","2670","2829","2936","3049","3145","3230","3608","3609","3610","3643","3803","3836","3921","4034","4183","4190","4283","4594"},["dilato"]={"4451"},["gemmo"]={"24"},["provoco"]={"3980","4435"},["iucunditas"]={"536","2271"},["obtero"]={"515"},["unde"]={"1828","2234","2235","2236","3237"},["altior"]={"1347"},["obliquo"]={"283"},["milito"]={"1680","4222"},["vector"]={"4673"},["supero"]={"32","47","162","4574","4686"},["divisus"]={"3743"},["flagro"]={"85","1206","2693","2763","2847","4279"},["gelu"]={"134"},["vertex"]={"117"},["tendo"]={"217","293","1347","2901","3088"},["desiderium"]={"2693","2694"},["gratus"]={"1045","1056","1552","1553","1557"},["cras"]={"427"},["excerpo"]={"2437"},["haustus"]={"636"},["obliviosus"]={"1540"},["reconcilio"]={"1126","1129"},["gelidus"]={"636"},["adhibeo"]={"1260","1480","1684","1685","2275","2674","2895","2979","2992","3086","3213","3264","4052"},["aufero"]={"481","1081","2253","2636"},["proximus"]={"91"},["cunctus"]={"3921"},["appropinquo"]={"305"},["indignitas"]={"2781"},["perennis"]={"54"},["ambiguus"]={"2326"},["profundo"]={"646","732","733","3250"},["vergo"]={"147","149"},["obscuro"]={"105","1210","1560","1572","2397"},["molior"]={"943","1477","2838","3501","3788","4272"},["stirpitus"]={"1429"},["aptissimus"]={"1800"},["tot"]={"1384"},["conventus"]={"4021"},["ignominia"]={"1229","1230","1234","3972"},["vivus"]={"53"},["cognitio"]={"1647","3072"},["oculus"]={"93","445","484","485","486","487","490","491","492","493","494","495","496","497","498","500","501","502","503","505","506","507","508","528","531","532","693","1340","2149","2150","2152"},["redundo"]={"520","829","950","1012","1013"},["corroboratus"]={"586","588"},["obscurus"]={"3639","4791"},["flumen"]={"49","61","62","63","64","65","66","67","68","2117","2333","3527","3529","3530"},["denego"]={"1091"},["lacesso"]={"2874","4290","4435"},["digitus"]={"459"},["munitio"]={"4407"},["contra"]={"1874","2945","3603","3713","3789","3790","3797","4036"},["capio"]={"691","793","1011","1018","1290","1395","1470","1503","1567","1720","2494","2510","2573","2663","3145","3205","3954","4240","4336","4371","4417","4552","4569","4731"},["tuba"]={"4376"},["contendo"]={"1261","1262","1264","3668","4318","4462","4694"},["succedo"]={"804","3925","3926","4528"},["testis"]={"4048","4049","4050","4051","4052","4053","4054","4055","4056","4059","4816"},["gubernaculum"]={"3581","3583","4691"},["agito"]={"75","270","537","1494","2976","2978"},["clamo"]={"2214"},["benefactus"]={"1066","1067"},["notio"]={"1348","1350","2359","2360","3074"},["revertor"]={"2232","2235","2236","2963"},["progredior"]={"307","1689","1781","2984","4790"},["aberro"]={"2231","2234"},["quomodo"]={"2181","2385"},["templum"]={"3036"},["monstro"]={"207"},["supplicatio"]={"3118","3119","3120"},["summa"]={"597","995","1137","1198","2162","2617","2659","3467","3655","3838","4231","4232","4233","4749"},["distentus"]={"1270"},["virga"]={"4158"},["recognosco"]={"4193"},["scrupulus"]={"1447","1448"},["insinuo"]={"3292"},["recuso"]={"960","1094"},["diligenter"]={"1236","1308","1496","2434","2436","3466"},["luceo"]={"402","403"},["munus"]={"2042","2815","3624","3933","3934","3936","3937","3943","3946"},["quodam"]={"1965","1966","2444","3010"},["similitudo"]={"1714"},["crucio"]={"634","2511","2657","4063"},["abiecto"]={"2589"},["strictus"]={"4510"},["reseco"]={"4794"},["pondero"]={"2985"},["morsus"]={"2514"},["strages"]={"4578"},["civitas"]={"1363","1364","1365","1899","3569","3573","3584","3614","3626","3627","3628","3629","3650","3764","3775","3821","3822","3823","3867","3890","4171","4628"},["crimen"]={"1163","4093","4120"},["vis"]={"75","203","230","544","545","646","661","727","750","850","890","1099","1223","1262","1263","1265","1521","2138","2599","2672","2885","2895","2896","2897","2898","2899","3678","4102","4216","4262","4319","4446","4503"},["inde"]={"4809"},["sustento"]={"628","996"},["tranquillitas"]={"4679"},["incendium"]={"85","86"},["contemplatio"]={"1769"},["summissus"]={"2208"},["planior"]={"4755"},["impeditus"]={"4203"},["quietus"]={"690","703","4367"},["sicarius"]={"4103"},["commotus"]={"2488","2489"},["profluens"]={"53"},["sollicitudo"]={"2526","2527","2531"},["mos"]={"370","1043","1047","1662","1767","1768","3000","3003","3004","3005","3007","3016","3278","3388","3389","3398"},["declarans"]={"2366"},["meridies"]={"147"},["recipio"]={"1114","2574","2727","2964","3151","3627","4418","4429","4540","4573"},["patefactus"]={"4397"},["aestimo"]={"2985"},["interiectus"]={"182","375"},["census"]={"3966","3973"},["arripio"]={"880"},["narratio"]={"3313"},["bibo"]={"736","3218","3219"},["victoria"]={"339","4597","4598","4600","4601","4602","4603","4604","4605","4606","4608"},["negotiator"]={"3406"},["decido"]={"303"},["demersus"]={"3511"},["insto"]={"4277","4564"},["specto"]={"147","148","1347","1508","1519","1520","1521","2329","3623"},["persuasus"]={"1460"},["lex"]={"3572","3574","3686","3692","3699","3702","3703","3707","3708","3711"},["copiosior"]={"2166","2167","2278"},["for"]={"2293","3008"},["perfero"]={"2467","3685","3686","4140"},["legens"]={"2450","2451"},["integritas"]={"2124","2292"},["tunc"]={"622"},["nuntius"]={"3363"},["pernicies"]={"941","943"},["profectus"]={"1749"},["proditus"]={"1885"},["conscientia"]={"2968","2970","2973","2974","2975","2977"},["proscriptus"]={"3816","3817"},["latinus"]={"2290","2292","2293","2299","2302","2303"},["oro"]={"1084","1087","4068"},["stipendium"]={"4207","4208","4209"},["castrum"]={"4202","4243","4357","4361","4366","4367"},["misceo"]={"3804"},["excolo"]={"1648"},["modus"]={"1992","1993","2979","2981","2982","2983","2984","2992","2996","3242"},["hodie"]={"427"},["imitandus"]={"1719"},["luo"]={"4141","4142"},["nomenclator"]={"3917"},["lang=la"]={"229","230","242","250","251","252","265","278","279","291","298","302","311","312","313","439","441","452","454","462","463","466","470","474","476","477","479","481","484","491","498","499","506","508","509","511","516","517","518","542","550","603","620","677","695","744","746","748","749","750","752","762","774","777","794","799","834","859","860","866","873","874","882","902","937","942","944","950","954","957","959","962","970","971","974","982","983","984","993","994","1007","1008","1009","1019","1022","1028","1029","1030","1031","1032","1033","1034","1035","1036","1037","1038","1039","1041","1042","1044","1046","1047","1048","1049","1050","1052","1053","1054","1071","1076","1082","1084","1085","1086","1093","1097","1102","1113","1114","1115","1116","1125","1126","1127","1129","1133","1134","1135","1138","1139","1145","1146","1147","1148","1149","1150","1151","1155","1176","1186","1187","1189","1190","1199","1200","1207","1208","1209","1210","1217","1221","1223","1224","1226","1228","1229","1233","1339","1341","1342","1350","1360","1372","1373","1374","1395","1423","1447","1480","1486","1537","1547","1548","1549","1550","1552","1553","1554","1555","1556","1557","1567","1568","1570","1572","1642","1645","1661","1662","1663","1667","1668","1670","1680","1706","1716","1717","1719","1721","1724","1732","1747","1748","1874","1974","1975","1976","1982","2010","2028","2145","2146","2147","2154","2177","2178","2179","2193","2204","2265","2330","2338","2388","2413","2422","2453","2459","2461","2482","2485","2486","2490","2492","2504","2535","2536","2545","2553","2556","2564","2565","2567","2579","2581","2587","2593","2605","2630","2631","2632","2645","2646","2647","2656","2659","2661","2662","2665","2666","2674","2675","2676","2677","2678","2681","2682","2683","2686","2687","2688","2689","2693","2698","2702","2703","2708","2711","2714","2716","2722","2723","2725","2726","2727","2728","2743","2746","2747","2748","2756","2762","2766","2767","2768","2769","2771","2774","2775","2776","2778","2789","2790","2791","2797","2799","2800","2801","2802","2804","2807","2825","2830","2843","2846","2847","2848","2849","2850","2867","2873","2874","2880","2882","2885","2886","2887","2888","2889","2902","2903","2910","2911","2915","2916","2927","2928","2931","2949","2950","2951","2953","2954","2965","2974","2978","2981","3007","3020","3028","3038","3039","3040","3062","3063","3149","3151","3155","3160","3178","3179","3180","3181","3182","3183","3184","3187","3259","3262","3264","3267","3268","3269","3271","3273","3276","3282","3285","3290","3291","3292","3293","3316","3323","3324","3334","3376","3377","3460","3464","3467","3469","3470","3498","3532","3623","3626","3627","3655","3658","3659","3660","3726","3736","3745","3746","3748","3797","3814","3816","3817","3818","3820","3821","3822","3823","3824","3827","3833","3840","3848","3858","3860","3861","3865","3870","3871","3902","3914","3924","3925","3936","3949","3950","3962","3972","3974","3998","4015","4023","4041","4046","4047","4051","4052","4054","4055","4056","4064","4067","4071","4088","4089","4090","4094","4095","4096","4097","4098","4099","4100","4101","4102","4103","4111","4118","4124","4127","4128","4129","4130","4131","4135","4136","4138","4140","4141","4144","4147","4148","4149","4150","4151","4152","4154","4159","4160","4161","4163","4219","4220","4233","4234","4243","4259","4260","4290","4428","4429","4432","4478","4567","4569","4572","4609","4633","4643","4645","4646","4647","4648","4650","4651","4704"},["dico"]={"429","440","1174","1175","1378","1401","1402","1617","1874","1886","2076","2082","2083","2084","2085","2086","2087","2088","2112","2167","2203","2256","2259","2261","2265","2274","2342","2355","2356","2369","2371","2385","2416","2443","2444","2607","2682","2925","2926","3333","3337","3364","3683","3959","3961","3991","4007","4016","4057","4058","4068","4069","4070","4105","4179","4620","4749","4761","4763","4766","4767","4768","4769","4771","4772","4773","4774","4775","4778","4779","4780","4786"},["venio"]={"1339","1905","2249","3054","3383","3942","4249","4511"},["misericordia"]={"2660","2661","2662","2663","2664"},["video"]={"2","327","339","385","431","504","505","519","619","693","704","705","831","915","1382","1889","2158","2447","2624","3142","3621","3954","3995","4835"},["expositus"]={"935"},["sica"]={"4260"},["collapsurus"]={"3142"},["ieiuno"]={"2120"},["latitudo"]={"175"},["domesticus"]={"1914","3168","4269"},["perpolio"]={"2434"},["exheredo"]={"3381"},["plus"]={"383","422","1237","1380","2166","3621","4739","4744","4783"},["edico"]={"3986","4030"},["semen"]={"7","3538"},["haurio"]={"60","831","916","1293","2547"},["incredibilis"]={"4770"},["valetudo"]={"661","662","664","687","688","4176"},["audiendus"]={"527","3329"},["commuto"]={"898","4624","4689"},["concipio"]={"79","1231","1327","1350","1361","2627","2842","3101"},["confero"]={"291","321","1001","1005","1031","1053","1115","1238","1344","1611","1670","1733","1911","1928","1971","2056","2406","2725","2949","3299","3330","3588","3609","3611","4118","4324","4491","4512","4554"},["iugum"]={"3872","3878","3879","3881","3882"},["incautus"]={"4333"},["insero"]={"2187"},["imperatum"]={"1104"},["posco"]={"2242"},["reddo"]={"724","1055","1068","2209","2303","2306","2462","2478","2748","3102","3469","4008","4073","4267","4626"},["incurro"]={"941","948","2767","2889","4515"},["exploratus"]={"1458","4602","4603"},["incendo"]={"82","2703","2805","4419"},["affecto"]={"593"},["statio"]={"4360","4363"},["decretum"]={"1741"},["despero"]={"2616"},["heres"]={"3376","3378","3385","3386"},["serius"]={"424"},["poena"]={"2799","2800","2802","4127","4131","4132","4133","4135","4137","4138","4139","4140","4141","4143"},["num"]={"415"},["arcesso"]={"2264","4187"},["securus"]={"2537"},["vendo"]={"3871"},["pax"]={"4614","4619","4620","4621","4622","4623","4779"},["diripio"]={"4420"},["spolio"]={"3861"},["certior"]={"1186"},["radicitus"]={"3081"},["consigno"]={"2402"},["sedem"]={"3188","3189","3190"},["eques"]={"3961","4454","4532"},["vehementer"]={"670","1085","1420"},["ea"]={"18","19","20","21","149","575","767","856","1527","3712","3996"},["tribunus"]={"3978","3979"},["reporto"]={"4600"},["vel"]={"2551"},["nonne"]={"4823"},["actus"]={"2005"},["rego"]={"2859","3168","3579","3764"},["cultura"]={"1649"},["sacrosanctus"]={"3978"},["aulus"]={"3684"},["capessendus"]={"3623"},["obiectum"]={"934"},["tumulus"]={"36"},["ter"]={"658","742","1448","2024","2331","2619","2689","2782"},["saluto"]={"2330"},["pictus"]={"1998"},["mendosus"]={"2455","2457"},["favor"]={"890","1030","3716","3717"},["verius"]={"4756"},["stomachus"]={"2798"},["pronuntio"]={"1969"},["omen"]={"1099","3096","3136","3137","3138","3139"},["elevo"]={"2535"},["montuosus"]={"38"},["facinus"]={"2782","2840","4122"},["signum"]={"4322","4441","4442","4503"},["uberior"]={"2167","2278"},["donatus"]={"4211"},["ingenuus"]={"1593","1659"},["antiquo"]={"3687"},["oppidum"]={"156","158","159","3526","4382","4383","4384","4385","4386","4387","4388","4389","4400","4409","4415","4416","4417","4418","4419","4420","4421","4422","4660"},["seges"]={"3541"},["deprimo"]={"4727"},["subtiliter"]={"1819","1831"},["acerbitas"]={"2789"},["prodo"]={"1562","1722","1888","2736"},["mereo"]={"1062","1069","1070"},["divido"]={"168","1788"},["sudor"]={"1246"},["volubilitas"]={"2280"},["expio"]={"2845","3112"},["deus"]={"4","5","3022","3029","3030","3031","3036","3037","3038","3039","3042","3070","3071","3073","3076","3083","3084","3085","3086","3092","3093","3095","3096","3098","3111"},["sepulcrum"]={"751","759","760"},["melicus"]={"2035"},["respublica"]={"3946"},["exitium"]={"939","943","944"},["astrologus"]={"1930"},["supplex"]={"1087"},["accuso"]={"4094","4096","4097","4099","4100","4101","4102","4103"},["grammaticus"]={"2313","2314"},["modicus"]={"2601","2980","2994"},["salubritas"]={"97"},["susceptus"]={"3012"},["fallo"]={"1432","1433","1434","2645","2732"},["italia"]={"3500"},["deterreo"]={"1371","1473","1506"},["heroicus"]={"1901","1902","1904"},["cachinnus"]={"639"},["mathematicus"]={"1926"},["placo"]={"1125","3111"},["iusiurandum"]={"3060","3066","3068"},["promissum"]={"2738"},["summoveo"]={"3963","4532"},["potestas"]={"739","859","875","881","3318","3852","3941","3962","4427","4428","4433","4434","4638","4642","4645","4648"},["praeoccupo"]={"4338"},["praecipuus"]={"4038"},["teres"]={"444"},["profusus"]={"3240"},["diversus"]={"287"},["auctus"]={"62"},["cedo"]={"331","936","3184","4012"},["deturbo"]={"2605","2639"},["dormio"]={"692","694","698"},["resigno"]={"2469","3370"},["praesens"]={"362","973","1155","2599","3427"},["sinceritas"]={"2124"},["incipio"]={"793","4273"},["convalesco"]={"684"},["nequam"]={"3176"},["calceus"]={"3197"},["conexus"]={"2142"},["multitudo"]={"314","3051","3192","3679","3769","3812","3895","4517"},["imperium"]={"169","177","3177","3762","3769","3775","3838","3840","3841","3843","3844","3845","3846","3847","3849","3874","3930","3931","3944","4229","4230","4231","4232","4233","4234","4235","4642","4643","4646","4647","4649"},["vetus"]={"1884","1891","1892","1893","1894","2383","3289","4201"},["renuntio"]={"1117","3274","3950"},["auditor"]={"1755"},["vilior"]={"3556"},["proclivis"]={"2837","2955"},["debilito"]={"2582"},["senatorius"]={"3634","3728"},["victima"]={"3110","3113"},["iudex"]={"4026","4079","4104"},["expleo"]={"632","2654","2773","2794","2866","3937"},["adduco"]={"266","777","801","886","954","1341","1373","1467","1568","1574","1843","1844","2617","2626","2631","2659","2662","2748","2769","2965","3504","3942","4321","4655"},["incognitus"]={"4044"},["vexillum"]={"4443"},["supplico"]={"3085"},["derivo"]={"49"},["virtus"]={"1219","1713","1975","2363","2364","2812","2813","2814","2815","2816","2819","2825","2968","4457"},["atque"]={"365","369","1085","1263","1407","1582","1655","2110","2680","3007","3613","4050","4370","4375","4428","4603","4784","4785","4789","4811"},["pius"]={"4268"},["romam"]={"243","244","246","308","309","574","1185"},["caterva"]={"2015","2033"},["insideo"]={"1559","1729","2753"},["praecurro"]={"312"},["saeculum"]={"369","1899"},["intercido"]={"2419"},["inops"]={"56","996","1489","3236"},["tenuissimus"]={"2755"},["geometria"]={"1925"},["nudo"]={"4359","4402"},["contrarius"]={"284","1832"},["imperator"]={"3926"},["gurges"]={"60"},["triumpho"]={"4607","4609"},["compono"]={"523","1849","1956","2222","2409","4080","4293"},["pristinus"]={"774","2816","2817","3394","3395","3576"},["fertilis"]={"3534"},["capitalis"]={"2772","4094"},["evoco"]={"3028","4181"},["rusticatio"]={"234"},["precor"]={"3083","3084","3100"},["hercules"]={"212"},["defixus"]={"1346"},["funus"]={"743","747","748","749","754"},["ubi"]={"402"},["unguiculus"]={"577"},["facile"]={"2115","4804"},["excrucio"]={"2975"},["pono"]={"1079","1227","1241","1438","1706","1847","2149","2155","2157","2175","2238","2239","2240","2241","2433","2650","2712","2818","2902","3204","3208","3492","4244","4345","4348"},["mortifer"]={"738","740","4584","4585"},["vulnus"]={"4583","4585","4586","4587","4590","4591","4606"},["inferior"]={"625","4073","4574","4596"},["subtilis"]={"1636","1948","2119"},["saepius"]={"365","2023"},["secus"]={"783"},["potentia"]={"3725"},["comprehensio"]={"2319"},["e"]={"19","185","285","290","374","437","475","480","508","552","685","700","701","741","831","1569","1668","1955","1999","2299","2305","2330","3005","3182","3446","3543","3603","3649","3652","3669","3817","3822","3824","3975","4248","4255","4438","4570","4571","4572"},["vir"]={"346","348","349","1311","1312","1624","1625","1626","1627","1868","3017","3665","4224"},["arto"]={"1593","1597","1652","1679","3782"},["decem"]={"610","612","615","4146"},["desum"]={"318","879","974","1089","2218","2252","2347","2942","3591","3601"},["existimatio"]={"1214","1220","3730"},["confido"]={"2713"},["exquirendus"]={"1921"},["iv"]={"500","3232"},["devincio"]={"1054","2841","3290"},["abicio"]={"517","1347","1472","1554","2523","2559","2641","2667","4558"},["crebro"]={"2282"},["erga"]={"1029","1071"},["septem"]={"1750"},["modestia"]={"4236"},["ignarus"]={"1451"},["narro"]={"1908","1918","2153","2181","4825","4826"},["faciendus"]={"3968"},["biduus"]={"424"},["lepos"]={"2269"},["finio"]={"629","4291"},["manus"]={"465","466","467","468","469","470","471","473","476","477","478","481","727","859","2432","2435","2897","3088","3916","4383","4490","4511","4514","4729","4846"},["peropportunus"]={"910"},["frigo"]={"1490"},["deflecto"]={"204","1405","2231","2822","3394"},["febris"]={"673"},["immortalitas"]={"1201","1563","1807"},["principium"]={"6","1784"},["conglutino"]={"1804"},["vacatio"]={"4177"},["satio"]={"2866"},["dives"]={"993"},["ex"]={"45","48","49","69","73","170","219","236","237","238","258","299","300","332","474","508","558","579","675","684","694","712","713","825","826","827","829","830","832","840","841","854","857","858","897","904","959","993","1002","1011","1012","1030","1073","1098","1174","1290","1303","1395","1396","1447","1468","1535","1544","1558","1569","1712","1720","1801","1813","1818","1827","1828","2076","2127","2133","2203","2301","2302","2339","2344","2351","2437","2494","2506","2510","2547","2548","2561","2670","2683","2685","2752","2771","2817","2985","3048","3061","3385","3386","3403","3405","3446","3484","3491","3516","3658","3727","3728","3736","3758","3821","3823","3886","3898","4013","4025","4403","4404","4476","4560","4591","4607","4608","4630","4678","4681","4704","4715","4733","4807","4808"},["mico"]={"139"},["neuter"]={"2373","3750","3751","3752"},["verior"]={"1412"},["dictatura"]={"3810","3960"},["kalenda"]={"2475"},["amplus"]={"3947"},["villa"]={"157","3268"},["adversus"]={"912"},["avoco"]={"2946"},["ineptus"]={"2276"},["armatura"]={"4200"},["conclamo"]={"88","3875","3876","4377","4604"},["ingravescens"]={"585"},["inquinatus"]={"2125","2836"},["vasum"]={"4377","4378"},["traduco"]={"568","3646"},["perturbatio"]={"2871","3805"},["remex"]={"4672"},["traditus"]={"1885"},["prosequor"]={"229","230","749","750","1032","1099","1223","1552","1553","2678","2885","2950","4561"},["ambitus"]={"2319","4101"},["neglectus"]={"1598","1738"},["elatus"]={"2590"},["leniter"]={"35"},["facultas"]={"874","881","882","2059","3170"},["obduresco"]={"2522"},["profugus"]={"3194"},["ultimus"]={"187","225"},["termino"]={"2393"},["recessus"]={"70"},["carpo"]={"4331"},["attingo"]={"164","459","1617","2159","2160","2161","2162","4396"},["fortissimus"]={"4224"},["ingratus"]={"1056","3550"},["factus"]={"587"},["mercennarius"]={"4212"},["elegans"]={"444","1636","1948"},["inhaereo"]={"2754","4565"},["descendo"]={"258","972","1515","1516","1732","3026","4446","4447","4448"},["notitia"]={"1793"},["despondeo"]={"3349","3350"},["mando"]={"1543","1563","1730","2402","3905","3935","4551","4559"},["obrutus"]={"1270","2811","2833","3511"},["graecus"]={"1622","1623","1710","2278","2295","2299","2303","2388","2389"},["reprimo"]={"2593","2795","3812","3884","4566"},["fruor"]={"566","981","1280","1292"},["clarissimus"]={"348","1621"},["disputatio"]={"1829"},["deditus"]={"1528","2835","3210","3216"},["vester"]={"503"},["possum"]={"874","1467","1514","1691","2172","3185","4064","4166","4167","4306","4763","4765","4769","4777","4804","4807"},["transitus"]={"2161","4766"},["onerarius"]={"4658"},["vivendus"]={"909","1695"},["fortuna"]={"771","889","890","891","892","893","894","895","896","897","898","899","900","901","902","911","923","926","931","933","934","935","936","991","2541","3182","3183","3190","3651"},["bibliotheca"]={"2440"},["lassitudo"]={"694"},["diiudico"]={"1413","1850"},["exercitatus"]={"2062","3619","4204"},["comptus"]={"458"},["particeps"]={"2958"},["sapienter"]={"2601","2994","3011"},["probabilis"]={"1399"},["acerrimus"]={"1943"},["interpres"]={"709","2311"},["flosculus"]={"2334"},["grex"]={"2015","2016","3564","3565"},["reprehensio"]={"884","885","1161"},["cumulo"]={"906","1055","1148","2844"},["tactus"]={"1966"},["oraculum"]={"3122","3123","3125","3127"},["adumbro"]={"1362","2137","2138"},["par"]={"180","1063","1064","2170","3464"},["antiquitas"]={"1895","1904","2126","3630"},["obsto"]={"1007"},["toga"]={"3203"},["interpono"]={"819","1533","2188","2730","2735","4274"},["humi"]={"301","302"},["mercatura"]={"3411"},["sementis"]={"3539","3540"},["concino"]={"1864"},["nascor"]={"827"},["flatus"]={"890"},["urgeo"]={"925","1814","4534"},["testimonium"]={"4057","4058"},["minuo"]={"1138","2646","3243"},["imploro"]={"970","2664","2728"},["funditus"]={"2834","3080","3802"},["controversia"]={"1841","1842","1843","1844","1845","1846","1848","1849","1850","1853"},["monumentum"]={"1619","1709","1884","1894","3523"},["totus"]={"3","315","1049","1294","1605","1606","1780","2682","2717","2853","3500","3611"},["machinor"]={"942"},["vespertinus"]={"415"},["gero"]={"1043","1047","1121","1269","2595","2597","3135","3171","3579","3754","3933","3960","3967","4225","4280","4466","4506","4507","4509"},["optatus"]={"1096"},["praeceptum"]={"1727","1743","1758","1769","1774","1779","1941","2057","2313","3000","3001"},["concito"]={"262","265","640","1205","1965","2661","2771","3792","3793","4695"},["appareo"]={"4810"},["numen"]={"3022"},["commemoro"]={"1706"},["investigatio"]={"1407","1928"},["libido"]={"2369","2852","2853","2863","2867","2868","2869"},["porrigo"]={"173","465","3343"},["periodus"]={"2319"},["persto"]={"1366","1509"},["conclusio"]={"1820"},["dissolutus"]={"1804"},["offendo"]={"251","2887","2888","2890","2891","2892"},["insumo"]={"3239","3432"},["nescio"]={"887","2423","2424"},["nilus"]={"299"}} return hw_auden_latin_lemmas_no_collision_to_ix_phrase tfthwhbicp9xgnd0uyoj3is9dalevml Module:data tables/metadata 828 38985 178495 2026-10-27T05:43:59Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local metadata = { ["shard_location_base"]={"Module:data tables/dataM"}, ["shards"]={1000}, ["tables"] = {"freezer", "la_RMA_index_to_phrases", "grc_RWoodhouse_lemma_to_infinitives", "la_NLW_headwords_to_path", "grc_RLBG_lemma_to_index", "la_RMA_lemmas_no_collision_to_ix_phrase", "grc_RCunliffe_lemma_to_index", "grc_RWoodhouse_lemma_to_headwords"} } return metadata' 178495 Scribunto text/plain local metadata = { ["shard_location_base"]={"Module:data tables/dataM"}, ["shards"]={1000}, ["tables"] = {"freezer", "la_RMA_index_to_phrases", "grc_RWoodhouse_lemma_to_infinitives", "la_NLW_headwords_to_path", "grc_RLBG_lemma_to_index", "la_RMA_lemmas_no_collision_to_ix_phrase", "grc_RCunliffe_lemma_to_index", "grc_RWoodhouse_lemma_to_headwords"} } return metadata e4qri2318dx0vlki3oij9mvet6gchu2 Module:data tables/dataM526 828 38986 178496 2026-10-27T05:45:03Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { } local grc_RWoodhouse_lemma_to_infinitives = { ["διασύρω"]={"διασύρειν","διασῦραι"},["δισπυτο"]={"δισπυταρε","δισπυταρι","δισπυτασσε","δισπυταϝισσε"},["εχσπιρο"]={"εχσπιραρε","εχσπιρασσε"},["μυωπίζω"]={"μυωπίζειν","μυωπίζεσθαι"},["περποτο"]={"περποταρε","περποτα...' 178496 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { } local grc_RWoodhouse_lemma_to_infinitives = { ["διασύρω"]={"διασύρειν","διασῦραι"},["δισπυτο"]={"δισπυταρε","δισπυταρι","δισπυτασσε","δισπυταϝισσε"},["εχσπιρο"]={"εχσπιραρε","εχσπιρασσε"},["μυωπίζω"]={"μυωπίζειν","μυωπίζεσθαι"},["περποτο"]={"περποταρε","περποτασσε"},["ρεσιστο"]={"ρεσιστερε","ρεσιστι"},["φορτίζω"]={"φορτίζεσθαι"},["ἐναποτίνω"]={"ἐναποτεῖσαι"},["ἐπαληθεύω"]={"ἐπαληθεύειν","ἐπαληθεῦσαι","ἐπηλήθευσεν"},["ὁμοφρονέω"]={"ὁμοφρονεῖν"},["περιστρέφω"]={"περιεστράφθαι","περιστρέφεσθαι","περιστρέψαι"},["καταψεύδομαι"]={"καταψεύδεσθαι","καταψεύσασθαι","κατεψεῦσθαι"}} local la_NLW_headwords_to_path = { ["circumcursator"]={"2/009910"},["coalo"]={"2/013082"},["conputrefactus"]={"0/006532"},["conseruamentum"]={"0/012540"},["consolidatiuus"]={"1/014049"},["dapax"]={"3/003391"},["fallo"]={"1/000545"},["foraminolentus"]={"1/005161"},["inago"]={"0/006900"},["interfectorius"]={"1/011489"},["metasomatismos"]={"2/011690"},["muscilaginosus"]={"0/018624"},["necio"]={"2/020130"},["philotheologus"]={"0/013920"},["prospocieticos"]={"2/002946"},["pseudantidotum"]={"3/008231"},["scholasticulus"]={"2/003582"},["semitriangulum"]={"2/019910"},["siela"]={"1/021081"},["subreptiuncula"]={"3/003655"},["supercoetaneus"]={"0/012016"},["superoptabilis"]={"1/006373"},["theologisticus"]={"2/005974"},["theophilologus"]={"2/014554"},["transitiuncula"]={"2/014610"},["uexilliferatus"]={"2/012650"}} local grc_RLBG_lemma_to_index = { ["γλύπτης"]={"14324"},["διφρεύς"]={"17805"},["δώρησις"]={"19317"},["ἔξαμον"]={"23940"},["ἐπενθρονίζομαι"]={"25292"},["κύπερις"]={"40213"},["μεγαλαυτοκράτωρ"]={"43602"},["παρακαμπανισμός"]={"53261"},["προηγός"]={"60680"},["ἀγροκόμος"]={"699"},["ἀναδουλόω"]={"3582"},["δυσευρέτως"]={"18690"},["δυσευρέτως"]={"18842"},["ἑκουσιάζω"]={"21116"},["ἐλαττονέω"]={"21712"},["ἐνδυνάμως"]={"23004"},["ἐντείχιος"]={"23608"},["ἐξαναβρύω"]={"23949"},["ἐξιλέωσις"]={"24428"},["ἐπιδόχμια"]={"25608"},["εὐδενδρόω"]={"27836"},["ἑωλοποσία"]={"29129"},["ἡμίτραγος"]={"29985"},["ἱερόχολος"]={"32038"},["ἰσόθρονος"]={"32538"},["οἰνόποσις"]={"48995"},["ὀρεΐγονος"]={"50532"},["παρυποφέρω"]={"54514"},["πραιτωρίως"]={"59465"},["ἀγγελόπρωτος"]={"267"},["ἀγγελοτρόπως"]={"273"},["ἀναχωμάτωσις"]={"4354"},["ἀπανθρωπικός"]={"6729"},["ἀπροσαύδητος"]={"8507"},["βδελυρεύομαι"]={"12143"},["διπλοκάρηνος"]={"17537"},["εὐαπόδραστος"]={"27748"},["καινοποίησις"]={"33264"},["κατατομητέον"]={"36026"},["κοσμολέτειρα"]={"38869"},["μακροκοντίας"]={"42857"},["μεταλλευτέον"]={"44715"},["παλινδρόμημα"]={"51946"},["πεντηκονταέξ"]={"55296"},["πολυμεριμνία"]={"58567"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["aetas"]={"337","338","339","341","345","346","568","575","578","580","581","582","584","585","586","588","590","591","593","596","600","601","605","607","611","619","620","623","625","1289","1609","1678","1679","1695","1896","1897","1899","1901","3012","3644","3956","4165","4167"},["saepe"]={"826","2282"},["apparatissimus"]={"2049"},["ianua"]={"3166"},["liber"]={"1740","2408","2409","2410","2411","2413","2414","2430","2432","2433","2434","2437","2439"},["reddo"]={"724","1055","1068","2209","2303","2306","2462","2478","2748","3102","3469","4008","4073","4267","4626"},["sedem"]={"3188","3189","3190"},["fallo"]={"1432","1433","1434","2645","2732"}} local grc_RCunliffe_lemma_to_index = { ["πατροκασίγνητος"]={"7470"},["περιστρέφω"]={"7660"},["μύνη"]={"6558"},["ὁμοφρονέω"]={"6971"},["νύξε"]={"6732"}} local grc_RWoodhouse_lemma_to_headwords = { ["Κέρκυρα"]={"corcyra"},["δονεῖν"]={"confound"},["κινεῖν"]={"agitate","arouse","broach","cause","convulse","disturb","evoke","excite","fan","flap","flutter","foment","inspire","interfere","kindle","meddle","misplace","molest","motion","move","occasion","play","poke","propagate","propel","provoke","raise","revive","rock","rouse","ruffle","shift","start","stimulate","stir","sway","swing","tamper with","thrill","trespass","ventilate","wake"},["κρωσσοί"]={"ewer"},["σκαφεύς"]={"digger"},["στρωμνή"]={"bed","bedding","couch"},["φανερός"]={"apparent","barefaced","clear","conspicuous","declared","discernible","distinct","evident","flagrant","manifest","naked","noticeable","observable","obvious","open","ostentatious","overt","palpable","patent","perceptible","plain","tangible","traceable","undoubted","unmistakable","visible"},["φροντίς"]={"anxiety","brooding","care","cogitation","concern","consideration","debate","deliberation","heed","interest","meditation","notion","pensiveness","reflection","regard","strain","thought","trouble","uneasiness","worry"},["φρυκτοί"]={"alarm"},["ἐπίκουροι"]={"mercenary"},["ἰλιγγιᾶν"]={"be dizzy, v.","giddy","reel","stagger","swim","totter"},["Ἰλλυρικός"]={"illyrian"},["ὑπούργημα"]={"benefaction","merit","service"},["Φθία"]={"phthia"},["ἀγωνοθετεῖν"]={"steward"},["ἐκφοβεῖσθαι"]={"afraid","dread","fear","tremble"},["ἐπαναπολεῖν"]={"reiterate","repeat","retrace"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} jid49igyo3tcq15g72z7i89gvs6ushh Module:data tables/dataM206 828 38987 178497 2026-10-27T05:47:29Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1049"]={"_totum se fingere et accommodare ad alicuius arbitrium et nutum_","to be at the beck and call of another; to be his creature."},["1058"]={"_gratiam alicui habere_","to feel gratitude (in one's heart)."},["1067"]={"_maleficia benefactis remunerari_","to return good for evil."},["1076"]={"_praemiis (amplissimis, maximis) aliquem afficere_[2]","to remunerate (handsomely)."},["1085"]={"_magno opere, ve...' 178497 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1049"]={"_totum se fingere et accommodare ad alicuius arbitrium et nutum_","to be at the beck and call of another; to be his creature."},["1058"]={"_gratiam alicui habere_","to feel gratitude (in one's heart)."},["1067"]={"_maleficia benefactis remunerari_","to return good for evil."},["1076"]={"_praemiis (amplissimis, maximis) aliquem afficere_[2]","to remunerate (handsomely)."},["1085"]={"_magno opere, vehementer, etiam atque etiam rogare aliquem_","to entreat earnestly; to make urgent requests."},["1094"]={"_nihil tibi a me postulanti recusabo_","I will refuse you nothing."},["1139"]={"_auctoritati, dignitati alicuius illudere_","to insult a person's dignity."},["1148"]={"_omni laude cumulare aliquem_","to overwhelm with eulogy."},["1157"]={"_res mihi probatur_","a thing meets with my approval."},["1166"]={"_rumor, fama viget_","a rumour is prevalent."},["1175"]={"_vulgo dicitur, pervulgatum est_","every one says."},["1184"]={"_nuntio allato_ or _accepto_","on receiving the news."},["1193"]={"_gloriae, laudi esse_","to confer distinction on a person; to redound to his credit."},["1229"]={"_aliquem ignominia afficere, notare_","to inflict an indignity upon, insult a person."},["1238"]={"_operam alicui rei tribuere, in aliquid conferre_","to expend great labour on a thing."},["1247"]={"_desudare et elaborare in aliqua re_ (De Senect. 11. 38)","to exert oneself very considerably in a matter."},["1256"]={"_patiens laboris_","capable of exertion."},["1265"]={"_pro viribus eniti et laborare, ut_","to strain every nerve, do one's utmost in a matter."},["1274"]={"_negotium alicui facessere_ (Fam. 3. 10. 1)","to give a person trouble, inconvenience him."},["1283"]={"_otiosum tempus consumere in aliqua re_","to spend one's leisure hours on an object."},["1292"]={"_voluptatibus frui_","to take one's fill of enjoyment."},["1319"]={"_ingenii infirmitas_ or _imbecillitas_","weakmindedness."},["1328"]={"_animo, cogitatione aliquid praecipere_ (Off 1. 23. 81)","to form a conception of a thing beforehand."},["1337"]={"_haec cogitatio subit animum_","an idea strikes me."},["1346"]={"_in cogitatione defixum esse_","to be deep in thought."},["1355"]={"_ad perfectionem, (ad summum) pervenire_","to attain perfection."},["1364"]={"_illa civitas Platonis commenticia_","Plato's ideal republic."},["1373"]={"_aliquem ad suam sententiam perducere_ or _in suam sententiam adducere_","to win a man over to one's own way of thinking."},["1382"]={"_ut mihi quidem videtur_","according to my opinion."},["1391"]={"_opinionum commenta_ (N. D. 2. 2. 5)","chimeras."},["1409"]={"_proxime ad verum accedere_","to be very near the truth."},["1418"]={"_magno errore teneri_","to be in gross error, seriously misled."},["1427"]={"_errorem tollere_","to banish an error, do away with a false impression."},["1436"]={"_optionem alicui dare, utrum...an_","to offer a person the alternative of... or..."},["1445"]={"_sine dubio_ (not _sine ullo dubio_)","without doubt, beyond all doubt."},["1454"]={"_quod sciam_","as far as I know."},["1463"]={"_persuade tibi_","convince yourself of this; rest assured on this point."},["1472"]={"_consilium abicere_ or _deponere_","to let a plan fall through."},["1481"]={"_consilium habere (de aliqua re)_","to deliberate together (of a number of people)."},["1490"]={"_omnia consilia frigent_ (Verr. 2. 25)","advice is useless in this case; the situation is very embarrassing."},["1508"]={"_magna sibi proponere_ or _magna spectare_","to have a high object in view; to be ambitious."},["1517"]={"_consilium est_ c. Inf. or _ut_","my intention is..."},["1526"]={"_quid hoc rei est?_","what is the meaning of this?"},["1535"]={"_diem ex die ducere, differre_","to put off from one day to another."},["1544"]={"_ex memoria_ (opp. _de scripto_)","from memory; by heart."},["1553"]={"_nomen alicuius grato animo prosequi_","to think of a person with a grateful sense of his goodness."},["1562"]={"_nomen suum posteritati aliqua re commendare, propagare, prodere_","to win renown amongst posterity by some act."},["1571"]={"_obliterari_[4] (Liv. 26. 41)","to be forgotten, pass into oblivion."},["1580"]={"_ad artem, ad rationem revocare aliquid_ (De Or. 2. 11. 44)","to reduce a thing to its theoretical principles; to apply theory to a thing."},["1607"]={"_in litteris elaborare_ (De Sen. 8. 26)","to apply oneself very closely to literary, scientific work."},["1616"]={"_intermissa studia revocare_","to resume one's studies."},["1625"]={"_vir doctissimus_","a great scholar."},["1634"]={"_doctrina abundare_ (De Or. 3. 16. 59)","to be a man of great learning."},["1643"]={"_scientia comprehendere aliquid_","to acquire knowledge of a subject."},["1652"]={"_litterae interiores et reconditae, artes reconditae_","profound scientific education."},["1661"]={"_aliquem ad humanitatem informare_ or _instituere_","to teach a person refinement."},["1670"]={"_operam dare_ or simply _se dare alicui, se tradere in disciplinam alicuius, se conferre, se applicare ad aliquem_","to become a pupil, disciple of some one."},["1706"]={"_aliquem (aliquid) exempli causa_[2] _ponere, proferre, nominare, commemorare_","to cite a person or a thing as an example."},["1715"]={"_auctore aliquo uti ad aliquid_","to have as authority for a thing."},["1724"]={"_exemplum in aliquo_ or _in aliquem statuere_","to inflict an exemplary punishment on some one."},["1733"]={"_se conferre ad philosophiam, ad philosophiae_ or _sapientiae studium_ (Fam. 4. 3. 4)","to devote oneself to philosophy."},["1742"]={"_quae in philosophia tractantur_","philosophical subjects."},["1751"]={"_Pythagorae doctrina longe lateque fluxit_ (Tusc. 4. 1. 2)","Pythagoras' principles were widely propagated."},["1760"]={"_disserendi subtilitas_ (De Or. 1. 1. 68)","dialectical nicety."},["1805"]={"_argumentum_[1] _firmum, magnum_","a strong, striking proof."},["1814"]={"_argumentum premere_ (not _urgere_)","to persist in an argument, press a point."},["1823"]={"_conclusiuncula fallax_ or _captio_","a fallacious argument; sophism."},["1832"]={"_in utramque partem, in contrarias partes disputare_ (De Or. 1. 34)","to discuss both sides of a question."},["1841"]={"_in controversia (contentione) esse, versari_","to be at variance with."},["1850"]={"_controversiam diiudicare_","to decide a debated question."},["1904"]={"_repetere ab ultima (extrema, prisca) antiquitate (vetustate), ab heroicis temporibus_","to go back to the remote ages."},["1913"]={"_memoriam rerum gestarum (rerum Romanarum) tenere_","to be well versed in Roman history."},["1922"]={"_terrarum_ or _regionum descriptio (geographia)_","geography."},["1931"]={"_arithmetica_[7] (_-orum_)","arithmetic."},["1940"]={"_artium (liberalium) studium_, or simply _studium_","a taste for the fine arts."},["2039"]={"_ludos apparare_","to institute games."},["2048"]={"_magnificentia ludorum_","sumptuous public games."},["2057"]={"_dicendi_[1] _praecepta tradere_","to teach rhetoric."},["2066"]={"_dicendi arte florere_","to be very eloquent."},["2075"]={"_oratio meditata_ (Plin. 26. 3. 7)","a prepared speech."},["2084"]={"_libere dicere_ (Verr. 2. 72. 176)","to speak frankly, independently."},["2093"]={"_initium dicendi facere_","to begin to speak."},["2129"]={"_oratio numerose cadit_","his style has a well-balanced cadence."},["2138"]={"_exprimere aliquid verbis_ or _oratione_ (_vid._ sect. VI. 3, note _adumbrare..._)","to express clearly, make a lifelike representation of a thing."},["2147"]={"_de ingenio moribusque alicuius exponere_","to make a character-sketch of a person."},["2156"]={"_sub unum aspectum subicere aliquid_","to give a general idea of a thing."},["2165"]={"_multum, nimium esse (in aliqua re)_ (De Or. 2. 4. 17)","to go deeply into a matter, discuss it fully."},["2174"]={"_in medium proferre aliquid_","to bring a subject forward into discussion."},["2183"]={"_rhetorice, tragice ornare aliquid_ (Brut. 11. 43)","to add rhetorical, dramatic embellishments to a subject."},["2192"]={"_digredi (a proposito)_ (De Or. 2. 77. 311)","to digress, deviate."},["2219"]={"_non habeo, non est quod scribam_","I have nothing to write about."},["2228"]={"_res proposita_","a theme, subject proposed for discussion."},["2237"]={"_mihi propositum est_ c. Inf. (or _mihi proposui, ut_)","the task I have put before myself is..."},["2246"]={"_magna quaestio est_ (followed by an indirect question)","it is a difficult point, disputed question."},["2255"]={"_ioco uti_ (Off. 1. 29. 103)","to make a joke."},["2264"]={"_arcessitum dictum_ (De Or. 2. 63. 256)","a far-fetched joke."},["2273"]={"_ioca et seria agere_","to be now jesting, now in earnest."},["2282"]={"_saepe (crebro, multa) peccavit, erravit, lapsus est_","he has made several mistakes."},["2291"]={"_consuetudo vitiosa et corrupta_ (opp. _pura et incorrupta_) _sermonis_","incorrect usage."},["2309"]={"_liber (scriptoris) conversus, translatus_","the work when translated; translation (concrete)."},["2318"]={"_compositio, structura verborum_","the structure of the sentence."},["2327"]={"_locutio_ (Brut. 74. 258)","a phrase."},["2336"]={"_nullum (omnino) verbum facere_","to not say a word."},["2345"]={"_verbo parum valere_ (Tusc. 3. 5. 11)","to unable to find a suitable expression."},["2354"]={"_nomina enodare_ or _verborum origines quaerere, indagare_","to give the etymological explanation of words."},["2363"]={"_quae intellegitur virtus_","what do we mean by 'virtue'?"},["2372"]={"_verba ac litteras_ or _scriptum (legis) sequi_ (opp. _sententia_ the spirit)","to hold by the letter (of the law)."},["2381"]={"_simili uti_","to employ a comparison, simile."},["2390"]={"_vetamur vetere proverbio_","an old proverb tells us not to..."},["2408"]={"_librum scribere, conscribere_","to write a book."},["2417"]={"_est liber de..._","there exists a book on..."},["2426"]={"_libro continetur aliquid_","the book contains something... (not _continet aliquid_)."},["2435"]={"_extrema manus accēdit operi_ (active _extremam manum imponere operi_)","to put the finishing touch to a work."},["2444"]={"_Cicero loco quodam haec dicit_","Cicero says this somewhere."},["2453"]={"_alicuius mens in scriptis spirat_","a man's soul breathes through his writings."},["2462"]={"_epistulam reddere alicui_ (Att. 5. 21. 4)","to deliver a letter to some one (used of the messenger)."},["2471"]={"_epistulam deprehendere_","to take forcible possession of a letter."},["2480"]={"_ita_[1] _animo affectum esse_","to be so disposed."},["2507"]={"_aegre, graviter, moleste fero aliquid_ (or with Acc. c. Inf. or _quod_)","I am pained, vexed, sorry."},["2516"]={"_dolori indulgere_","to give way to grief."},["2525"]={"_cum magno meo dolore_","to my sorrow."},["2534"]={"_aegritudine afflictum, debilitatum esse, iacēre_","to be bowed down, prostrated by grief."},["2543"]={"_in luctu esse_ (Sest. 14. 32)","to suffer affliction."},["2552"]={"_timorem, terrorem alicui inicere_, more strongly _incutere_","to inspire fear, terror."},["2561"]={"_ex metu se recreare, se colligere_","to recover from one's fright."},["2570"]={"_bono animo esse_","to be brave, courageous."},["2606"]={"_de statu suo_ or _mentis deici_ (Att. 16. 15)","to lose one's composure; to be disconcerted."},["2615"]={"_mente consistere_","to be calm, self-possessed."},["2624"]={"_sperare videor_","I flatter myself with the hope..."},["2633"]={"_spem proponere alicui_","to lead some one to expect..."},["2642"]={"_inani, falsa spe duci, induci_","to be misled by a vain hope."},["2651"]={"_inter spem metumque suspensum animi esse_","to hover between hope and fear."},["2660"]={"_misericordiam alicui commovere_","to excite some one's pity."},["2705"]={"_ardorem animi restinguere_","to damp, chill enthusiasm."},["2714"]={"_fiduciam (alicuius rei) habere_","to have great confidence in a thing."},["2723"]={"_de fide deducere_ or _a fide abducere aliquem_","to undermine a person's loyalty."},["2732"]={"_fidem servare_ (opp. _fallere_)","to keep one's word (not _tenere_)."},["2741"]={"_aliquid fidem habet_ (_vid._ also _fides_ under sect. VII., History)","a thing finds credence, is credible."},["2750"]={"_in suspicionem alicui venire_","to be suspected by some one."},["2804"]={"_impellere aliquem in furorem_","to make some one furious."},["2813"]={"_omnia consilia et facta ad virtutem referre_[1] (Phil. 10. 10. 20)","to make virtue the standard in every thought and act."},["2822"]={"_a maiorum virtute desciscere, degenerare, deflectere_","to deteriorate."},["2831"]={"_animum vitiis dedere_","to abandon oneself to vice."},["2840"]={"_facinus facere, committere_","to do a criminal deed."},["2903"]={"_aliquem in insidias elicere, inducere_","to draw some one into an ambush."},["2912"]={"_speciem prae se ferre_[1]","to give the impression of...; have the outward aspect of..."},["2921"]={"_per dolum_ (B. G. 4. 13)","by craft."},["2930"]={"_in ludibrium verti_ (Tac. Ann. 12. 26)","to become an object of ridicule; to be laughed at."},["3029"]={"_deos sancte, pie venerari_","to be an earnest worshipper of the gods."},["3038"]={"_aliquem in deorum numerum referre, reponere_","to deify a person."},["3047"]={"_audientium animos religione perfundere_ (Liv. 10. 388)","to fill the souls of one's audience with devotion."},["3056"]={"_religionem externam suscipere_","to embrace a strange religion."},["3065"]={"_iureiurando teneri_ (Off. 3. 27. 100)","to be bound by oath."},["3074"]={"_natura in omnium animis notionem dei impressit_ (N. D. 1. 16. 43)","Nature has implanted in all men the idea of a God."},["3083"]={"_precari aliquid a deo_","to pray to God."},["3092"]={"_testari deos_ (Sull. 31. 86)","to call the gods to witness."},["3119"]={"_supplicationem quindecim dierum decernere_ (Phil. 14. 14. 37)","to decree a public thanksgiving for fifteen days."},["3128"]={"_vox Pythia (Pythica)_ (Liv. 1. 56)","an oracle given by the Delphian Apollo (Apollo Pythius)."},["3137"]={"_accipere, vertere aliquid in omen_","to interpret something as an omen."},["3146"]={"_domum frequentare_ (Sall. Cat. 14. 7)","to be a regular visitor at a house."},["3155"]={"_foras mittere aliquem_","to turn some one out of the house."},["3164"]={"_ostium, fores aperire, claudere_","to open, shut the door."},["3173"]={"_rem familiarem neglegere_","to neglect, mismanage one's household matters."},["3182"]={"_exturbare aliquem omnibus fortunis, e possessionibus_","to drive a person out of house and home."},["3191"]={"_considere alicubi_ (Att. 5. 14. 1)","to take up one's abode in a place, settle down somewhere."},["3209"]={"_corpus curare (cibo, vino, somno)_","to refresh oneself, minister to one's bodily wants."},["3218"]={"_alicui bibere dare_[1]","to give some one to drink."},["3227"]={"_quae ad victum pertinent_","the necessaries of life."},["3236"]={"_vitam (inopem) tolerare_ (B. G. 7. 77)","to endure a life of privation."},["3245"]={"_sumptus liberales_ (Off. 2. 12. 42)","munificence."},["3254"]={"_mensas exquisitissimis epulis instruere_ (Tusc. 5. 21. 62)","to load the tables with the most exquisite viands."},["3263"]={"_condicere alicui (ad cenam)_","to invite oneself to some one's house for dinner."},["3272"]={"_hospitium cum aliquo facere, (con-)iungere_","to become a friend and guest of a person."},["3281"]={"_socium se adiungere alicui_","to attach oneself to a person's society."},["3290"]={"_devincire aliquem consuetudine_","to attach a person to oneself."},["3308"]={"_sermonem producere in multam noctem_ (Rep. 6. 10. 10)","to prolong a conversation far into the night."},["3317"]={"_congredi cum aliquo_","to meet a person by arrangement, interview him."},["3326"]={"_tribus verbis te volo_","a word with you."},["3335"]={"_quid agis?_[1]","how are you?"},["3344"]={"_dextram iungere cum aliquo, dextras inter se iungere_","to shake hands with a person."},["3353"]={"_condicio (uxoria)_ (Phil. 2. 38. 99)","a match."},["3362"]={"_filiam alicui nuptum dare_","to give one's daughter in marriage to some-one."},["3371"]={"_testamentum rescindere_","to declare a will to be null and void."},["3380"]={"_exheres paternorum bonorum_ (De Or. 1. 38. 175)","disinherited."},["3407"]={"_homines negotii_ (always in sing.) _gerentes_","business-men."},["3416"]={"_quaestum facere_ (Fam. 15. 14)","to make money."},["3425"]={"_pecunia magna_,[1] _grandis (multum pecuniae)_","much money."},["3434"]={"_pecuniam solvere_","to pay money."},["3443"]={"_pecuniam creditam solvere_","to repay a loan."},["3452"]={"_argentariam facere_ (Verr. 5. 59. 155)","to be a banker."},["3461"]={"_ad calculos vocare aliquid_ (Amic. 16. 58)","to go through accounts, make a valuation of a thing."},["3470"]={"_rationem alicuius rei reposcere aliquem_ or _ab aliquo_","to demand an account, an audit of a matter."},["3506"]={"_grande, magnum_ (opp. _exiguum_) _aes alienum conflare_","to incur debts on a large scale."},["3515"]={"_nomina exigere_ (Verr. 3. 10. 28)","to demand payment of, recover debts."},["3524"]={"_fundamenta iacere, agere_","to lay the foundations."},["3533"]={"_agrum colere_ (Leg. Agr. 2. 25. 67)","to till the ground."},["3542"]={"_laetissimi flores_ (Verr. 4. 48. 107)","a glorious expanse of flowers."},["3551"]={"_arbores serere_ (De Sen. 7. 24)","to plant trees."},["3560"]={"_hac annona_ (Plaut. Trin. 2. 4. 83)","when corn is as dear as it is."},["3605"]={"_commoda publica_ or _rei publicae rationes_","the interests of the state."},["3614"]={"_rector civitatis_ (De Or. 1. 48. 211)","the head of the state."},["3623"]={"_alicuius in re publica_ or _capessendae rei publicae consilia eo spectant, ut..._","a man's policy is aiming at, directed towards..."},["3632"]={"_nobilitatis fautorem, studiosum esse_","to be a friend of the aristocracy."},["3641"]={"_equestri loco natus_ or _ortus_","a knight by birth."},["3650"]={"_faex populi, plebis, civitatis_","the dregs of the people."},["3704"]={"_in lege scriptum est_, or simply _est_","the law says..."},["3713"]={"_aliquid contra legem est_","a thing is illegal."},["3722"]={"_ventum popularem quendam (in aliqua re) quaerere_","to strive to gain popular favour by certain means."},["3731"]={"_multum communi hominum opinioni tribuere_","to be always considering what people think."},["3740"]={"_partium studiosum esse_","to be a strong partisan."},["3803"]={"_omnes leges confundere_","to upset the whole constitution."},["3812"]={"_concitatam multitudinem reprimere_","to allay the excitement of the mob."},["3821"]={"_ex urbe (civitate) expellere, pellere aliquem_","to banish a person, send him into exile."},["3830"]={"_solum vertere, mutare_ (Caecin. 34. 100)","to leave one's country (only used of exiles)."},["3902"]={"_coloniam deducere in aliquem locum_ (_vid._ sect. XII. 1, note _Notice too..._)","to found a colony somewhere."},["3911"]={"_provinciam administrare, obtinere_","to manage, govern a province."},["3920"]={"_centuriam, tribum ferre_ (Planc. 49)","to gain the vote of a century or tribe."},["4019"]={"_iudicium exercere_ (_vid._ sect. V. 7, note _The first..._)","to administer justice; to judge (used of criminal cases before the praetor)."},["4028"]={"_aequa iuris descriptio_ (Off. 2. 4. 15)","a sound judicial system."},["4037"]={"_optimo iure_","with full right."},["4046"]={"_deprehendere aliquem (in aliqua re)_","to catch a person, find him out."},["4055"]={"_aliquem testem producere_","to produce as a witness."},["4064"]={"_aliquem a ceteris separare et in arcam conicere ne quis cum eo colloqui possit_ (Mil. 22. 60)","to isolate a witness."},["4073"]={"_causam inferiorem dicendo reddere superiorem_ (λόγον κρείττω ποιειν) (Brut. 8. 30)","to gain a weak case by clever pleading."},["4082"]={"_causā_ or _iudicio vincere_","to win a case."},["4091"]={"_aliquis reus fit_ (Fam. 13. 54)","some one is accused."},["4109"]={"_lege Plautia damnari_ (Sall. Cat. 31. 4)","to be condemned under the Lex Plautia."},["4118"]={"_culpam in aliquem conferre, transferre, conicere_","to put the blame on another."},["4127"]={"_poena afficere aliquem_ (Off. 2. 5. 18)","to punish some one."},["4136"]={"_graviter consulere in aliquem_ (Liv. 8. 13)","to deal severely with a person."},["4145"]={"_multam irrogare alicui_ (Cic. Dom. 17. 45)","to impose a fine (used of the prosecutor or the _tribunus plebis_ proposing a fine to be ratified by the people)."},["4154"]={"_morte multare aliquem_ (Catil. 1. 11. 28)","to punish any one with death."},["4163"]={"_impunitum aliquem dimittere_","to let a person go scot-free."},["4172"]={"_nomen (nomina) dare, profiteri_","to enlist oneself."},["4181"]={"_evocare undique copias_","to call up troops from all sides."},["4190"]={"_cogere omnes copias in unum locum_","to concentrate all the troops at one point."},["4208"]={"_stipendia facere, merere_","to serve."},["4217"]={"_intercludere commeatum_","to cut off the supplies, intercept them."},["4226"]={"_res fortiter feliciterque gesta_","a success; a glorious feat of arms."},["4235"]={"_imperium alicui abrogare_ (Off.3. 10)","to depose a person from his command."},["4244"]={"_arma ponere_ (not _deponere_)","to pile arms (cf. sect. XII. 3, note _vestem deponere..._)."},["4253"]={"_se obicere telis_","to expose oneself to missiles."},["4262"]={"_vi et armis_","by force of arms."},["4271"]={"_bellum conflare_ (Fam. 5. 2. 8)","to kindle a war."},["4280"]={"_bellum gerere cum aliquo_","to make war on a person."},["4307"]={"_citatum agmen rapere_","to lead the army with forced marches."},["4316"]={"_iter flectere, convertere, avertere_","to deviate, change the direction."},["4325"]={"_raris ordinibus_","in open order."},["4334"]={"_subsistere, consistere_","to halt."},["4343"]={"_praesidium collocare in urbe_","to garrison a town."},["4352"]={"_castra munire_","to make a fortified, entrenched camp."},["4361"]={"_vigilias agere in castris_ (Verr. 4. 43)","to mount guard in the camp."},["4370"]={"_ferre atque agere_[1] _praedam_","to carry off booty."},["4406"]={"_subsidium alicui summittere_","to send relief to some one."},["4415"]={"_in oppidum irrumpere_","to break into the town."},["4424"]={"_arma tradere_","to surrender weapons."},["4433"]={"_potestatem, copiam pugnandi hostibus facere_","to offer battle to the enemy."},["4442"]={"_signum proelii dare_","to give the signal to engage."},["4451"]={"_aciem explicare_ or _dilatare_","to extend the line of battle, deploy the battalions."},["4460"]={"_proelium inire_ (Liv. 2. 14)","to engage."},["4505"]={"_collato pede_ (Liv. 6. 12)","hand to hand."},["4514"]={"_manu fortis_","personally brave."},["4523"]={"_phalangem facere_ (B. G. 1. 24)","to form a phalanx."},["4532"]={"_summovere_ or _reicere hostium equites_","to repel the attack of the enemy's cavalry."},["4541"]={"_loco excedere_","to abandon one's position."},["4550"]={"_terga dare hosti_","to run away from the enemy."},["4604"]={"_victoriam conclamare_ (B. G. 5. 37)","to raise a shout of victory."},["4613"]={"_ius gentium violare_","to violate the law of nations."},["4622"]={"_pax convenit in eam condicionem, ut..._","peace is concluded on condition that..."},["4631"]={"_foedus facere (cum aliquo), icere, ferire_","to conclude a treaty, an alliance."},["4640"]={"_populum in deditionem accipere_","to accept the submission of a people."},["4703"]={"_tempestate abripi_","to be driven out of one's course; to drift."},["4712"]={"_ad ancoram consistere_","to ride at anchor."},["4721"]={"_aestu incitato_","at high tide."},["4730"]={"_in navem (hostium) transcendere_","to throw grappling irons on board; to board."},["4802"]={"_hoc in aperto est_","it is clear, evident."},["4811"]={"_exstat atque eminet_","it is quite manifest."},["4820"]={"_est istuc quidem aliquid_","there is something in what you say; you are more or less right."}} local grc_RWoodhouse_lemma_to_infinitives = { ["αϝερτο"]={"αυερτερε","αυερτι","αϝερτερε","αϝερτι","αϝερτισσε"},["ἀναβαίνω"]={"ἀμβαίνειν","ἀναβαίνειν","ἀναβαίνεσθαι","ἀναβεβηκέναι","ἀναβήσεσθαι","ἀναβῆναι"},["ἀναγκάζω"]={"ἀνάγκαν","ἀναγκάζειν","ἀναγκάζεσθαι","ἀναγκάξειν","ἀναγκάσαι","ἀναγκασθήσεσθαι","ἀναγκασθῆναι","ἠνάγκακεν","ἠναγκάκειν","ἠναγκάσθαι"},["ἀνομοιόω"]={"ἀνομοιοῦσθαι"},["εἰσβάλλω"]={"ἐσβάλλειν","ἐσβαλεῖν","ἐσβεβληκέναι","εἰσβάλλειν","εἰσβαλεῖν"},["κατατρύχω"]={"κατατρύχεσθαι"},["περικόπτω"]={"περικόπτειν","περικοπῆναι","προσπερικόπτειν"},["συβστιτυο"]={"συβστιτυερε","συβστιτυισσε"}} local la_NLW_headwords_to_path = { ["altiloquium"]={"3/009371"},["antiquarius"]={"1/001653"},["assentatrix"]={"3/018031"},["astoropaeus"]={"0/017712"},["circumpulso"]={"2/010634"},["ciuiloquium"]={"3/012415"},["commentulum"]={"2/005450"},["coniunctrix"]={"2/006710"},["conscriptor"]={"2/003446"},["contestator"]={"2/012490"},["contrauerto"]={"1/005881"},["cupidinosus"]={"2/020870"},["disputatura"]={"2/003278"},["fastuositas"]={"0/007596"},["foenusculum"]={"0/005004"},["frigusculum"]={"0/008252"},["frivolarius"]={"2/014562"},["honestitudo"]={"2/015214"},["interuentio"]={"0/000760"},["malepositus"]={"0/016884"},["migratorius"]={"0/015356"},["ministerium"]={"3/001539"},["myrothecium"]={"2/000890"},["octimestris"]={"0/001792"},["partimentum"]={"3/018955"},["perfortiter"]={"0/017624"},["persubtilis"]={"0/010524"},["philorticus"]={"2/021250"},["pietisticus"]={"2/016966"},["plectropeus"]={"0/010892"},["plurifarius"]={"1/003561"},["polemologus"]={"0/004556"},["polychordum"]={"0/014440"},["pontiuegium"]={"0/015160"},["portiuncula"]={"1/002817"},["postillaris"]={"1/009429"},["punctulatim"]={"3/010075"},["pyrobolaris"]={"0/018616"},["ridiculosus"]={"0/001660"},["rigorositas"]={"1/007913"},["sanguifluus"]={"1/007881"},["scopeterius"]={"0/012532"},["semiauersus"]={"2/019894"},["semitestudo"]={"3/021227"},["sigmatismus"]={"1/012745"},["somnambulus"]={"2/005810"},["succussatio"]={"3/009083"},["tipographus"]={"1/001429"},["transcoloro"]={"3/008339"},["tritestiger"]={"0/020644"},["triumphatio"]={"3/010047"},["turbulatiue"]={"2/018942"},["uitulolatra"]={"0/019208"},["uniternitas"]={"3/007659"}} local grc_RLBG_lemma_to_index = { ["ἀνεπιμόμφως"]={"4737"},["ἀντιπομπεύω"]={"6084"},["ἀξύγκλυστος"]={"6598"},["ἀπροσόμιλος"]={"8540"},["ἀρσενοτόκος"]={"9203"},["γνωμολόγημα"]={"14434"},["δολοπλόκημα"]={"17974"},["ἐγκατοπτεύω"]={"19664"},["ἐμπερόνησις"]={"22237"},["ἐμπλαστικός"]={"22268"},["ἐντραύλησις"]={"23682"},["εὐεφόδευτος"]={"27958"},["εὐκτηριώτης"]={"28202"},["εὐφραντικός"]={"28833"},["κακολογικός"]={"33457"},["κοινολεκτέω"]={"38007"},["κολοβοποιέω"]={"38181"},["κομπολόγημα"]={"38387"},["κοσμοθεάμων"]={"38848"},["μανικόδετον"]={"43124"},["μεταλούομαι"]={"44728"},["ἀγαθοδαιμονία"]={"140"},["ἀρρωστηματικός"]={"9193"},["γρίβας"]={"14690"},["γωνιόω"]={"14877"},["διαδηματοφόρος"]={"15860"},["δουκόω"]={"18145"},["ἐννεαπηχυαῖος"]={"23342"},["κνυζόω"]={"37909"},["μισοπονηρίτζης"]={"45648"},["μυλεύω"]={"46577"},["νοερόω"]={"47831"},["περιστιλβόομαι"]={"56282"},["πούχνη"]={"59395"},["προσαπογεύομαι"]={"61719"},["ἀμυγδάλη"]={"3221"},["ἀναβλάζω"]={"3467"},["ἀναλγητί"]={"3810"},["ἀνατάδην"]={"4231"},["ἀπλίκεμα"]={"7247"},["αὐογαρία"]={"10467"},["δασύοφρυς"]={"15099"},["ἐκζεννύω"]={"20717"},["ἔμπλοκος"]={"22295"},["ἐντύβιον"]={"23700"},["ἐξόμνυμα"]={"24539"},["ἐπάγαμαι"]={"24819"},["εὐέργεια"]={"27948"},["εὐκραδία"]={"28181"},["ζωπύρησις"]={"29549"},["ἡδομένως"]={"29602"},["ἰεράνεος"]={"31868"},["καταφύσσω"]={"36136"},["κρατυσμός"]={"39417"},["Κρονικῶς"]={"39652"},["μυρορρόας"]={"46877"},["ὁλάγαθος"]={"49168"},["ὀργάομαι"]={"50484"},["πεπλαστουργημένως"]={"55371"},["περικόπτω"]={"55843"},["περισυνός"]={"56321"},["πλατυσμός"]={"57374"},["πολλαχοῖ"]={"58169"},["πρόπυργον"]={"61483"},["προσαθρόω"]={"61539"},["πρόσκεψις"]={"62605"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["vicissitudo"]={"413","926"},["perpetuitas"]={"1786","2141"},["iusiurandum"]={"3060","3066","3068"}} local grc_RCunliffe_lemma_to_index = { ["νότιος"]={"6721"},["ἀναβαίνω"]={"699"},["πύρνον"]={"8281"},["κνυζόω"]={"5671"},["πρότμησις"]={"8174"},["φλοιός"]={"9469"},["κατατρύχω"]={"5348"}} local grc_RWoodhouse_lemma_to_headwords = { ["διαλέγεσθαι"]={"chat","commune with","confer","converse","descant","discourse","discuss","interview","speak","speech","talk"},["κατοιμώζειν"]={"bewail","groan","lament","moan","mourn","sigh","wail"},["ὁμοιοῦσθαι"]={"answer","approximate","equal","identify","like","match","resemble","take"},["Κύθηρα"]={"cythera"},["νότιος"]={"southern"},["παραφθέγγεσθαι"]={"casually","passing"},["φλοιός"]={"bark","rind"},["ψύχειν"]={"benumb","chill","cool","fan","freshen"},["ἑτέρᾳ"]={"another","otherwise"},["εὔτολμος"]={"bold","brave","courageous","doughty"},["μαστροπός"]={"pander","pimp","procurer","procuress"},["περαιοῦν"]={"cross","send"},["περυσινός"]={"last","year"},["πρόσθετος"]={"false"},["τελωνεῖν"]={"tax-collector","toll-collector"},["ψυχαγωγός"]={"conjurer","ghostly","necromancer"},["ἀγροικία"]={"awkwardness","bluntness","boorishness","churlishness","clownishness","coarseness","discourtesy","grossness","impoliteness","inattention","incivility","lowness","roughness","rudeness","rusticity","unmannerliness","vulgarity"},["ἀνίεσθαι"]={"effete","spring"},["ἀντιλαβή"]={"grip","handle","hold","lever"},["ἀποδημία"]={"abroad","absence","emigration","journey","peregrination","travel","trip"},["ἁρμάμαξα"]={"carriage","tilt-waggon"},["Ἀμούλιος"]={"amulius"},["ὠφέλιμος"]={"advantageous","advisable","beneficial","expedient","good","helpful","profitable","serviceable","useful"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} 1jvh7rsxtnvv2lgxp306mjltcyuq7zv 178510 178497 2026-10-27T06:10:07Z GinawaSaHapon 3989 178510 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1049"]={"_totum se fingere et accommodare ad alicuius arbitrium et nutum_","to be at the beck and call of another; to be his creature."},["1058"]={"_gratiam alicui habere_","to feel gratitude (in one's heart)."},["1067"]={"_maleficia benefactis remunerari_","to return good for evil."},["1076"]={"_praemiis (amplissimis, maximis) aliquem afficere_[2]","to remunerate (handsomely)."},["1085"]={"_magno opere, vehementer, etiam atque etiam rogare aliquem_","to entreat earnestly; to make urgent requests."},["1094"]={"_nihil tibi a me postulanti recusabo_","I will refuse you nothing."},["1139"]={"_auctoritati, dignitati alicuius illudere_","to insult a person's dignity."},["1148"]={"_omni laude cumulare aliquem_","to overwhelm with eulogy."},["1157"]={"_res mihi probatur_","a thing meets with my approval."},["1166"]={"_rumor, fama viget_","a rumour is prevalent."},["1175"]={"_vulgo dicitur, pervulgatum est_","every one says."},["1184"]={"_nuntio allato_ or _accepto_","on receiving the news."},["1193"]={"_gloriae, laudi esse_","to confer distinction on a person; to redound to his credit."},["1229"]={"_aliquem ignominia afficere, notare_","to inflict an indignity upon, insult a person."},["1238"]={"_operam alicui rei tribuere, in aliquid conferre_","to expend great labour on a thing."},["1247"]={"_desudare et elaborare in aliqua re_ (De Senect. 11. 38)","to exert oneself very considerably in a matter."},["1256"]={"_patiens laboris_","capable of exertion."},["1265"]={"_pro viribus eniti et laborare, ut_","to strain every nerve, do one's utmost in a matter."},["1274"]={"_negotium alicui facessere_ (Fam. 3. 10. 1)","to give a person trouble, inconvenience him."},["1283"]={"_otiosum tempus consumere in aliqua re_","to spend one's leisure hours on an object."},["1292"]={"_voluptatibus frui_","to take one's fill of enjoyment."},["1319"]={"_ingenii infirmitas_ or _imbecillitas_","weakmindedness."},["1328"]={"_animo, cogitatione aliquid praecipere_ (Off 1. 23. 81)","to form a conception of a thing beforehand."},["1337"]={"_haec cogitatio subit animum_","an idea strikes me."},["1346"]={"_in cogitatione defixum esse_","to be deep in thought."},["1355"]={"_ad perfectionem, (ad summum) pervenire_","to attain perfection."},["1364"]={"_illa civitas Platonis commenticia_","Plato's ideal republic."},["1373"]={"_aliquem ad suam sententiam perducere_ or _in suam sententiam adducere_","to win a man over to one's own way of thinking."},["1382"]={"_ut mihi quidem videtur_","according to my opinion."},["1391"]={"_opinionum commenta_ (N. D. 2. 2. 5)","chimeras."},["1409"]={"_proxime ad verum accedere_","to be very near the truth."},["1418"]={"_magno errore teneri_","to be in gross error, seriously misled."},["1427"]={"_errorem tollere_","to banish an error, do away with a false impression."},["1436"]={"_optionem alicui dare, utrum...an_","to offer a person the alternative of... or..."},["1445"]={"_sine dubio_ (not _sine ullo dubio_)","without doubt, beyond all doubt."},["1454"]={"_quod sciam_","as far as I know."},["1463"]={"_persuade tibi_","convince yourself of this; rest assured on this point."},["1472"]={"_consilium abicere_ or _deponere_","to let a plan fall through."},["1481"]={"_consilium habere (de aliqua re)_","to deliberate together (of a number of people)."},["1490"]={"_omnia consilia frigent_ (Verr. 2. 25)","advice is useless in this case; the situation is very embarrassing."},["1508"]={"_magna sibi proponere_ or _magna spectare_","to have a high object in view; to be ambitious."},["1517"]={"_consilium est_ c. Inf. or _ut_","my intention is..."},["1526"]={"_quid hoc rei est?_","what is the meaning of this?"},["1535"]={"_diem ex die ducere, differre_","to put off from one day to another."},["1544"]={"_ex memoria_ (opp. _de scripto_)","from memory; by heart."},["1553"]={"_nomen alicuius grato animo prosequi_","to think of a person with a grateful sense of his goodness."},["1562"]={"_nomen suum posteritati aliqua re commendare, propagare, prodere_","to win renown amongst posterity by some act."},["1571"]={"_obliterari_[4] (Liv. 26. 41)","to be forgotten, pass into oblivion."},["1580"]={"_ad artem, ad rationem revocare aliquid_ (De Or. 2. 11. 44)","to reduce a thing to its theoretical principles; to apply theory to a thing."},["1607"]={"_in litteris elaborare_ (De Sen. 8. 26)","to apply oneself very closely to literary, scientific work."},["1616"]={"_intermissa studia revocare_","to resume one's studies."},["1625"]={"_vir doctissimus_","a great scholar."},["1634"]={"_doctrina abundare_ (De Or. 3. 16. 59)","to be a man of great learning."},["1643"]={"_scientia comprehendere aliquid_","to acquire knowledge of a subject."},["1652"]={"_litterae interiores et reconditae, artes reconditae_","profound scientific education."},["1661"]={"_aliquem ad humanitatem informare_ or _instituere_","to teach a person refinement."},["1670"]={"_operam dare_ or simply _se dare alicui, se tradere in disciplinam alicuius, se conferre, se applicare ad aliquem_","to become a pupil, disciple of some one."},["1706"]={"_aliquem (aliquid) exempli causa_[2] _ponere, proferre, nominare, commemorare_","to cite a person or a thing as an example."},["1715"]={"_auctore aliquo uti ad aliquid_","to have as authority for a thing."},["1724"]={"_exemplum in aliquo_ or _in aliquem statuere_","to inflict an exemplary punishment on some one."},["1733"]={"_se conferre ad philosophiam, ad philosophiae_ or _sapientiae studium_ (Fam. 4. 3. 4)","to devote oneself to philosophy."},["1742"]={"_quae in philosophia tractantur_","philosophical subjects."},["1751"]={"_Pythagorae doctrina longe lateque fluxit_ (Tusc. 4. 1. 2)","Pythagoras' principles were widely propagated."},["1760"]={"_disserendi subtilitas_ (De Or. 1. 1. 68)","dialectical nicety."},["1805"]={"_argumentum_[1] _firmum, magnum_","a strong, striking proof."},["1814"]={"_argumentum premere_ (not _urgere_)","to persist in an argument, press a point."},["1823"]={"_conclusiuncula fallax_ or _captio_","a fallacious argument; sophism."},["1832"]={"_in utramque partem, in contrarias partes disputare_ (De Or. 1. 34)","to discuss both sides of a question."},["1841"]={"_in controversia (contentione) esse, versari_","to be at variance with."},["1850"]={"_controversiam diiudicare_","to decide a debated question."},["1904"]={"_repetere ab ultima (extrema, prisca) antiquitate (vetustate), ab heroicis temporibus_","to go back to the remote ages."},["1913"]={"_memoriam rerum gestarum (rerum Romanarum) tenere_","to be well versed in Roman history."},["1922"]={"_terrarum_ or _regionum descriptio (geographia)_","geography."},["1931"]={"_arithmetica_[7] (_-orum_)","arithmetic."},["1940"]={"_artium (liberalium) studium_, or simply _studium_","a taste for the fine arts."},["2039"]={"_ludos apparare_","to institute games."},["2048"]={"_magnificentia ludorum_","sumptuous public games."},["2057"]={"_dicendi_[1] _praecepta tradere_","to teach rhetoric."},["2066"]={"_dicendi arte florere_","to be very eloquent."},["2075"]={"_oratio meditata_ (Plin. 26. 3. 7)","a prepared speech."},["2084"]={"_libere dicere_ (Verr. 2. 72. 176)","to speak frankly, independently."},["2093"]={"_initium dicendi facere_","to begin to speak."},["2129"]={"_oratio numerose cadit_","his style has a well-balanced cadence."},["2138"]={"_exprimere aliquid verbis_ or _oratione_ (_vid._ sect. VI. 3, note _adumbrare..._)","to express clearly, make a lifelike representation of a thing."},["2147"]={"_de ingenio moribusque alicuius exponere_","to make a character-sketch of a person."},["2156"]={"_sub unum aspectum subicere aliquid_","to give a general idea of a thing."},["2165"]={"_multum, nimium esse (in aliqua re)_ (De Or. 2. 4. 17)","to go deeply into a matter, discuss it fully."},["2174"]={"_in medium proferre aliquid_","to bring a subject forward into discussion."},["2183"]={"_rhetorice, tragice ornare aliquid_ (Brut. 11. 43)","to add rhetorical, dramatic embellishments to a subject."},["2192"]={"_digredi (a proposito)_ (De Or. 2. 77. 311)","to digress, deviate."},["2219"]={"_non habeo, non est quod scribam_","I have nothing to write about."},["2228"]={"_res proposita_","a theme, subject proposed for discussion."},["2237"]={"_mihi propositum est_ c. Inf. (or _mihi proposui, ut_)","the task I have put before myself is..."},["2246"]={"_magna quaestio est_ (followed by an indirect question)","it is a difficult point, disputed question."},["2255"]={"_ioco uti_ (Off. 1. 29. 103)","to make a joke."},["2264"]={"_arcessitum dictum_ (De Or. 2. 63. 256)","a far-fetched joke."},["2273"]={"_ioca et seria agere_","to be now jesting, now in earnest."},["2282"]={"_saepe (crebro, multa) peccavit, erravit, lapsus est_","he has made several mistakes."},["2291"]={"_consuetudo vitiosa et corrupta_ (opp. _pura et incorrupta_) _sermonis_","incorrect usage."},["2309"]={"_liber (scriptoris) conversus, translatus_","the work when translated; translation (concrete)."},["2318"]={"_compositio, structura verborum_","the structure of the sentence."},["2327"]={"_locutio_ (Brut. 74. 258)","a phrase."},["2336"]={"_nullum (omnino) verbum facere_","to not say a word."},["2345"]={"_verbo parum valere_ (Tusc. 3. 5. 11)","to unable to find a suitable expression."},["2354"]={"_nomina enodare_ or _verborum origines quaerere, indagare_","to give the etymological explanation of words."},["2363"]={"_quae intellegitur virtus_","what do we mean by 'virtue'?"},["2372"]={"_verba ac litteras_ or _scriptum (legis) sequi_ (opp. _sententia_ the spirit)","to hold by the letter (of the law)."},["2381"]={"_simili uti_","to employ a comparison, simile."},["2390"]={"_vetamur vetere proverbio_","an old proverb tells us not to..."},["2408"]={"_librum scribere, conscribere_","magsulat ng aklat"},["2417"]={"_est liber de..._","there exists a book on..."},["2426"]={"_libro continetur aliquid_","the book contains something... (not _continet aliquid_)."},["2435"]={"_extrema manus accēdit operi_ (active _extremam manum imponere operi_)","to put the finishing touch to a work."},["2444"]={"_Cicero loco quodam haec dicit_","Cicero says this somewhere."},["2453"]={"_alicuius mens in scriptis spirat_","a man's soul breathes through his writings."},["2462"]={"_epistulam reddere alicui_ (Att. 5. 21. 4)","to deliver a letter to some one (used of the messenger)."},["2471"]={"_epistulam deprehendere_","to take forcible possession of a letter."},["2480"]={"_ita_[1] _animo affectum esse_","to be so disposed."},["2507"]={"_aegre, graviter, moleste fero aliquid_ (or with Acc. c. Inf. or _quod_)","I am pained, vexed, sorry."},["2516"]={"_dolori indulgere_","to give way to grief."},["2525"]={"_cum magno meo dolore_","to my sorrow."},["2534"]={"_aegritudine afflictum, debilitatum esse, iacēre_","to be bowed down, prostrated by grief."},["2543"]={"_in luctu esse_ (Sest. 14. 32)","to suffer affliction."},["2552"]={"_timorem, terrorem alicui inicere_, more strongly _incutere_","to inspire fear, terror."},["2561"]={"_ex metu se recreare, se colligere_","to recover from one's fright."},["2570"]={"_bono animo esse_","to be brave, courageous."},["2606"]={"_de statu suo_ or _mentis deici_ (Att. 16. 15)","to lose one's composure; to be disconcerted."},["2615"]={"_mente consistere_","to be calm, self-possessed."},["2624"]={"_sperare videor_","I flatter myself with the hope..."},["2633"]={"_spem proponere alicui_","to lead some one to expect..."},["2642"]={"_inani, falsa spe duci, induci_","to be misled by a vain hope."},["2651"]={"_inter spem metumque suspensum animi esse_","to hover between hope and fear."},["2660"]={"_misericordiam alicui commovere_","to excite some one's pity."},["2705"]={"_ardorem animi restinguere_","to damp, chill enthusiasm."},["2714"]={"_fiduciam (alicuius rei) habere_","to have great confidence in a thing."},["2723"]={"_de fide deducere_ or _a fide abducere aliquem_","to undermine a person's loyalty."},["2732"]={"_fidem servare_ (opp. _fallere_)","to keep one's word (not _tenere_)."},["2741"]={"_aliquid fidem habet_ (_vid._ also _fides_ under sect. VII., History)","a thing finds credence, is credible."},["2750"]={"_in suspicionem alicui venire_","to be suspected by some one."},["2804"]={"_impellere aliquem in furorem_","to make some one furious."},["2813"]={"_omnia consilia et facta ad virtutem referre_[1] (Phil. 10. 10. 20)","to make virtue the standard in every thought and act."},["2822"]={"_a maiorum virtute desciscere, degenerare, deflectere_","to deteriorate."},["2831"]={"_animum vitiis dedere_","to abandon oneself to vice."},["2840"]={"_facinus facere, committere_","to do a criminal deed."},["2903"]={"_aliquem in insidias elicere, inducere_","to draw some one into an ambush."},["2912"]={"_speciem prae se ferre_[1]","to give the impression of...; have the outward aspect of..."},["2921"]={"_per dolum_ (B. G. 4. 13)","by craft."},["2930"]={"_in ludibrium verti_ (Tac. Ann. 12. 26)","to become an object of ridicule; to be laughed at."},["3029"]={"_deos sancte, pie venerari_","to be an earnest worshipper of the gods."},["3038"]={"_aliquem in deorum numerum referre, reponere_","to deify a person."},["3047"]={"_audientium animos religione perfundere_ (Liv. 10. 388)","to fill the souls of one's audience with devotion."},["3056"]={"_religionem externam suscipere_","to embrace a strange religion."},["3065"]={"_iureiurando teneri_ (Off. 3. 27. 100)","to be bound by oath."},["3074"]={"_natura in omnium animis notionem dei impressit_ (N. D. 1. 16. 43)","Nature has implanted in all men the idea of a God."},["3083"]={"_precari aliquid a deo_","to pray to God."},["3092"]={"_testari deos_ (Sull. 31. 86)","to call the gods to witness."},["3119"]={"_supplicationem quindecim dierum decernere_ (Phil. 14. 14. 37)","to decree a public thanksgiving for fifteen days."},["3128"]={"_vox Pythia (Pythica)_ (Liv. 1. 56)","an oracle given by the Delphian Apollo (Apollo Pythius)."},["3137"]={"_accipere, vertere aliquid in omen_","to interpret something as an omen."},["3146"]={"_domum frequentare_ (Sall. Cat. 14. 7)","to be a regular visitor at a house."},["3155"]={"_foras mittere aliquem_","to turn some one out of the house."},["3164"]={"_ostium, fores aperire, claudere_","to open, shut the door."},["3173"]={"_rem familiarem neglegere_","to neglect, mismanage one's household matters."},["3182"]={"_exturbare aliquem omnibus fortunis, e possessionibus_","to drive a person out of house and home."},["3191"]={"_considere alicubi_ (Att. 5. 14. 1)","to take up one's abode in a place, settle down somewhere."},["3209"]={"_corpus curare (cibo, vino, somno)_","to refresh oneself, minister to one's bodily wants."},["3218"]={"_alicui bibere dare_[1]","to give some one to drink."},["3227"]={"_quae ad victum pertinent_","the necessaries of life."},["3236"]={"_vitam (inopem) tolerare_ (B. G. 7. 77)","to endure a life of privation."},["3245"]={"_sumptus liberales_ (Off. 2. 12. 42)","munificence."},["3254"]={"_mensas exquisitissimis epulis instruere_ (Tusc. 5. 21. 62)","to load the tables with the most exquisite viands."},["3263"]={"_condicere alicui (ad cenam)_","to invite oneself to some one's house for dinner."},["3272"]={"_hospitium cum aliquo facere, (con-)iungere_","to become a friend and guest of a person."},["3281"]={"_socium se adiungere alicui_","to attach oneself to a person's society."},["3290"]={"_devincire aliquem consuetudine_","to attach a person to oneself."},["3308"]={"_sermonem producere in multam noctem_ (Rep. 6. 10. 10)","to prolong a conversation far into the night."},["3317"]={"_congredi cum aliquo_","to meet a person by arrangement, interview him."},["3326"]={"_tribus verbis te volo_","a word with you."},["3335"]={"_quid agis?_[1]","how are you?"},["3344"]={"_dextram iungere cum aliquo, dextras inter se iungere_","to shake hands with a person."},["3353"]={"_condicio (uxoria)_ (Phil. 2. 38. 99)","a match."},["3362"]={"_filiam alicui nuptum dare_","to give one's daughter in marriage to some-one."},["3371"]={"_testamentum rescindere_","to declare a will to be null and void."},["3380"]={"_exheres paternorum bonorum_ (De Or. 1. 38. 175)","disinherited."},["3407"]={"_homines negotii_ (always in sing.) _gerentes_","business-men."},["3416"]={"_quaestum facere_ (Fam. 15. 14)","to make money."},["3425"]={"_pecunia magna_,[1] _grandis (multum pecuniae)_","much money."},["3434"]={"_pecuniam solvere_","to pay money."},["3443"]={"_pecuniam creditam solvere_","to repay a loan."},["3452"]={"_argentariam facere_ (Verr. 5. 59. 155)","to be a banker."},["3461"]={"_ad calculos vocare aliquid_ (Amic. 16. 58)","to go through accounts, make a valuation of a thing."},["3470"]={"_rationem alicuius rei reposcere aliquem_ or _ab aliquo_","to demand an account, an audit of a matter."},["3506"]={"_grande, magnum_ (opp. _exiguum_) _aes alienum conflare_","to incur debts on a large scale."},["3515"]={"_nomina exigere_ (Verr. 3. 10. 28)","to demand payment of, recover debts."},["3524"]={"_fundamenta iacere, agere_","to lay the foundations."},["3533"]={"_agrum colere_ (Leg. Agr. 2. 25. 67)","to till the ground."},["3542"]={"_laetissimi flores_ (Verr. 4. 48. 107)","a glorious expanse of flowers."},["3551"]={"_arbores serere_ (De Sen. 7. 24)","to plant trees."},["3560"]={"_hac annona_ (Plaut. Trin. 2. 4. 83)","when corn is as dear as it is."},["3605"]={"_commoda publica_ or _rei publicae rationes_","the interests of the state."},["3614"]={"_rector civitatis_ (De Or. 1. 48. 211)","the head of the state."},["3623"]={"_alicuius in re publica_ or _capessendae rei publicae consilia eo spectant, ut..._","a man's policy is aiming at, directed towards..."},["3632"]={"_nobilitatis fautorem, studiosum esse_","to be a friend of the aristocracy."},["3641"]={"_equestri loco natus_ or _ortus_","a knight by birth."},["3650"]={"_faex populi, plebis, civitatis_","the dregs of the people."},["3704"]={"_in lege scriptum est_, or simply _est_","the law says..."},["3713"]={"_aliquid contra legem est_","a thing is illegal."},["3722"]={"_ventum popularem quendam (in aliqua re) quaerere_","to strive to gain popular favour by certain means."},["3731"]={"_multum communi hominum opinioni tribuere_","to be always considering what people think."},["3740"]={"_partium studiosum esse_","to be a strong partisan."},["3803"]={"_omnes leges confundere_","to upset the whole constitution."},["3812"]={"_concitatam multitudinem reprimere_","to allay the excitement of the mob."},["3821"]={"_ex urbe (civitate) expellere, pellere aliquem_","to banish a person, send him into exile."},["3830"]={"_solum vertere, mutare_ (Caecin. 34. 100)","to leave one's country (only used of exiles)."},["3902"]={"_coloniam deducere in aliquem locum_ (_vid._ sect. XII. 1, note _Notice too..._)","to found a colony somewhere."},["3911"]={"_provinciam administrare, obtinere_","to manage, govern a province."},["3920"]={"_centuriam, tribum ferre_ (Planc. 49)","to gain the vote of a century or tribe."},["4019"]={"_iudicium exercere_ (_vid._ sect. V. 7, note _The first..._)","to administer justice; to judge (used of criminal cases before the praetor)."},["4028"]={"_aequa iuris descriptio_ (Off. 2. 4. 15)","a sound judicial system."},["4037"]={"_optimo iure_","with full right."},["4046"]={"_deprehendere aliquem (in aliqua re)_","to catch a person, find him out."},["4055"]={"_aliquem testem producere_","to produce as a witness."},["4064"]={"_aliquem a ceteris separare et in arcam conicere ne quis cum eo colloqui possit_ (Mil. 22. 60)","to isolate a witness."},["4073"]={"_causam inferiorem dicendo reddere superiorem_ (λόγον κρείττω ποιειν) (Brut. 8. 30)","to gain a weak case by clever pleading."},["4082"]={"_causā_ or _iudicio vincere_","to win a case."},["4091"]={"_aliquis reus fit_ (Fam. 13. 54)","some one is accused."},["4109"]={"_lege Plautia damnari_ (Sall. Cat. 31. 4)","to be condemned under the Lex Plautia."},["4118"]={"_culpam in aliquem conferre, transferre, conicere_","to put the blame on another."},["4127"]={"_poena afficere aliquem_ (Off. 2. 5. 18)","to punish some one."},["4136"]={"_graviter consulere in aliquem_ (Liv. 8. 13)","to deal severely with a person."},["4145"]={"_multam irrogare alicui_ (Cic. Dom. 17. 45)","to impose a fine (used of the prosecutor or the _tribunus plebis_ proposing a fine to be ratified by the people)."},["4154"]={"_morte multare aliquem_ (Catil. 1. 11. 28)","to punish any one with death."},["4163"]={"_impunitum aliquem dimittere_","to let a person go scot-free."},["4172"]={"_nomen (nomina) dare, profiteri_","to enlist oneself."},["4181"]={"_evocare undique copias_","to call up troops from all sides."},["4190"]={"_cogere omnes copias in unum locum_","to concentrate all the troops at one point."},["4208"]={"_stipendia facere, merere_","to serve."},["4217"]={"_intercludere commeatum_","to cut off the supplies, intercept them."},["4226"]={"_res fortiter feliciterque gesta_","a success; a glorious feat of arms."},["4235"]={"_imperium alicui abrogare_ (Off.3. 10)","to depose a person from his command."},["4244"]={"_arma ponere_ (not _deponere_)","to pile arms (cf. sect. XII. 3, note _vestem deponere..._)."},["4253"]={"_se obicere telis_","to expose oneself to missiles."},["4262"]={"_vi et armis_","by force of arms."},["4271"]={"_bellum conflare_ (Fam. 5. 2. 8)","to kindle a war."},["4280"]={"_bellum gerere cum aliquo_","to make war on a person."},["4307"]={"_citatum agmen rapere_","to lead the army with forced marches."},["4316"]={"_iter flectere, convertere, avertere_","to deviate, change the direction."},["4325"]={"_raris ordinibus_","in open order."},["4334"]={"_subsistere, consistere_","to halt."},["4343"]={"_praesidium collocare in urbe_","to garrison a town."},["4352"]={"_castra munire_","to make a fortified, entrenched camp."},["4361"]={"_vigilias agere in castris_ (Verr. 4. 43)","to mount guard in the camp."},["4370"]={"_ferre atque agere_[1] _praedam_","to carry off booty."},["4406"]={"_subsidium alicui summittere_","to send relief to some one."},["4415"]={"_in oppidum irrumpere_","to break into the town."},["4424"]={"_arma tradere_","to surrender weapons."},["4433"]={"_potestatem, copiam pugnandi hostibus facere_","to offer battle to the enemy."},["4442"]={"_signum proelii dare_","to give the signal to engage."},["4451"]={"_aciem explicare_ or _dilatare_","to extend the line of battle, deploy the battalions."},["4460"]={"_proelium inire_ (Liv. 2. 14)","to engage."},["4505"]={"_collato pede_ (Liv. 6. 12)","hand to hand."},["4514"]={"_manu fortis_","personally brave."},["4523"]={"_phalangem facere_ (B. G. 1. 24)","to form a phalanx."},["4532"]={"_summovere_ or _reicere hostium equites_","to repel the attack of the enemy's cavalry."},["4541"]={"_loco excedere_","to abandon one's position."},["4550"]={"_terga dare hosti_","to run away from the enemy."},["4604"]={"_victoriam conclamare_ (B. G. 5. 37)","to raise a shout of victory."},["4613"]={"_ius gentium violare_","to violate the law of nations."},["4622"]={"_pax convenit in eam condicionem, ut..._","peace is concluded on condition that..."},["4631"]={"_foedus facere (cum aliquo), icere, ferire_","to conclude a treaty, an alliance."},["4640"]={"_populum in deditionem accipere_","to accept the submission of a people."},["4703"]={"_tempestate abripi_","to be driven out of one's course; to drift."},["4712"]={"_ad ancoram consistere_","to ride at anchor."},["4721"]={"_aestu incitato_","at high tide."},["4730"]={"_in navem (hostium) transcendere_","to throw grappling irons on board; to board."},["4802"]={"_hoc in aperto est_","it is clear, evident."},["4811"]={"_exstat atque eminet_","it is quite manifest."},["4820"]={"_est istuc quidem aliquid_","there is something in what you say; you are more or less right."}} local grc_RWoodhouse_lemma_to_infinitives = { ["αϝερτο"]={"αυερτερε","αυερτι","αϝερτερε","αϝερτι","αϝερτισσε"},["ἀναβαίνω"]={"ἀμβαίνειν","ἀναβαίνειν","ἀναβαίνεσθαι","ἀναβεβηκέναι","ἀναβήσεσθαι","ἀναβῆναι"},["ἀναγκάζω"]={"ἀνάγκαν","ἀναγκάζειν","ἀναγκάζεσθαι","ἀναγκάξειν","ἀναγκάσαι","ἀναγκασθήσεσθαι","ἀναγκασθῆναι","ἠνάγκακεν","ἠναγκάκειν","ἠναγκάσθαι"},["ἀνομοιόω"]={"ἀνομοιοῦσθαι"},["εἰσβάλλω"]={"ἐσβάλλειν","ἐσβαλεῖν","ἐσβεβληκέναι","εἰσβάλλειν","εἰσβαλεῖν"},["κατατρύχω"]={"κατατρύχεσθαι"},["περικόπτω"]={"περικόπτειν","περικοπῆναι","προσπερικόπτειν"},["συβστιτυο"]={"συβστιτυερε","συβστιτυισσε"}} local la_NLW_headwords_to_path = { ["altiloquium"]={"3/009371"},["antiquarius"]={"1/001653"},["assentatrix"]={"3/018031"},["astoropaeus"]={"0/017712"},["circumpulso"]={"2/010634"},["ciuiloquium"]={"3/012415"},["commentulum"]={"2/005450"},["coniunctrix"]={"2/006710"},["conscriptor"]={"2/003446"},["contestator"]={"2/012490"},["contrauerto"]={"1/005881"},["cupidinosus"]={"2/020870"},["disputatura"]={"2/003278"},["fastuositas"]={"0/007596"},["foenusculum"]={"0/005004"},["frigusculum"]={"0/008252"},["frivolarius"]={"2/014562"},["honestitudo"]={"2/015214"},["interuentio"]={"0/000760"},["malepositus"]={"0/016884"},["migratorius"]={"0/015356"},["ministerium"]={"3/001539"},["myrothecium"]={"2/000890"},["octimestris"]={"0/001792"},["partimentum"]={"3/018955"},["perfortiter"]={"0/017624"},["persubtilis"]={"0/010524"},["philorticus"]={"2/021250"},["pietisticus"]={"2/016966"},["plectropeus"]={"0/010892"},["plurifarius"]={"1/003561"},["polemologus"]={"0/004556"},["polychordum"]={"0/014440"},["pontiuegium"]={"0/015160"},["portiuncula"]={"1/002817"},["postillaris"]={"1/009429"},["punctulatim"]={"3/010075"},["pyrobolaris"]={"0/018616"},["ridiculosus"]={"0/001660"},["rigorositas"]={"1/007913"},["sanguifluus"]={"1/007881"},["scopeterius"]={"0/012532"},["semiauersus"]={"2/019894"},["semitestudo"]={"3/021227"},["sigmatismus"]={"1/012745"},["somnambulus"]={"2/005810"},["succussatio"]={"3/009083"},["tipographus"]={"1/001429"},["transcoloro"]={"3/008339"},["tritestiger"]={"0/020644"},["triumphatio"]={"3/010047"},["turbulatiue"]={"2/018942"},["uitulolatra"]={"0/019208"},["uniternitas"]={"3/007659"}} local grc_RLBG_lemma_to_index = { ["ἀνεπιμόμφως"]={"4737"},["ἀντιπομπεύω"]={"6084"},["ἀξύγκλυστος"]={"6598"},["ἀπροσόμιλος"]={"8540"},["ἀρσενοτόκος"]={"9203"},["γνωμολόγημα"]={"14434"},["δολοπλόκημα"]={"17974"},["ἐγκατοπτεύω"]={"19664"},["ἐμπερόνησις"]={"22237"},["ἐμπλαστικός"]={"22268"},["ἐντραύλησις"]={"23682"},["εὐεφόδευτος"]={"27958"},["εὐκτηριώτης"]={"28202"},["εὐφραντικός"]={"28833"},["κακολογικός"]={"33457"},["κοινολεκτέω"]={"38007"},["κολοβοποιέω"]={"38181"},["κομπολόγημα"]={"38387"},["κοσμοθεάμων"]={"38848"},["μανικόδετον"]={"43124"},["μεταλούομαι"]={"44728"},["ἀγαθοδαιμονία"]={"140"},["ἀρρωστηματικός"]={"9193"},["γρίβας"]={"14690"},["γωνιόω"]={"14877"},["διαδηματοφόρος"]={"15860"},["δουκόω"]={"18145"},["ἐννεαπηχυαῖος"]={"23342"},["κνυζόω"]={"37909"},["μισοπονηρίτζης"]={"45648"},["μυλεύω"]={"46577"},["νοερόω"]={"47831"},["περιστιλβόομαι"]={"56282"},["πούχνη"]={"59395"},["προσαπογεύομαι"]={"61719"},["ἀμυγδάλη"]={"3221"},["ἀναβλάζω"]={"3467"},["ἀναλγητί"]={"3810"},["ἀνατάδην"]={"4231"},["ἀπλίκεμα"]={"7247"},["αὐογαρία"]={"10467"},["δασύοφρυς"]={"15099"},["ἐκζεννύω"]={"20717"},["ἔμπλοκος"]={"22295"},["ἐντύβιον"]={"23700"},["ἐξόμνυμα"]={"24539"},["ἐπάγαμαι"]={"24819"},["εὐέργεια"]={"27948"},["εὐκραδία"]={"28181"},["ζωπύρησις"]={"29549"},["ἡδομένως"]={"29602"},["ἰεράνεος"]={"31868"},["καταφύσσω"]={"36136"},["κρατυσμός"]={"39417"},["Κρονικῶς"]={"39652"},["μυρορρόας"]={"46877"},["ὁλάγαθος"]={"49168"},["ὀργάομαι"]={"50484"},["πεπλαστουργημένως"]={"55371"},["περικόπτω"]={"55843"},["περισυνός"]={"56321"},["πλατυσμός"]={"57374"},["πολλαχοῖ"]={"58169"},["πρόπυργον"]={"61483"},["προσαθρόω"]={"61539"},["πρόσκεψις"]={"62605"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["vicissitudo"]={"413","926"},["perpetuitas"]={"1786","2141"},["iusiurandum"]={"3060","3066","3068"}} local grc_RCunliffe_lemma_to_index = { ["νότιος"]={"6721"},["ἀναβαίνω"]={"699"},["πύρνον"]={"8281"},["κνυζόω"]={"5671"},["πρότμησις"]={"8174"},["φλοιός"]={"9469"},["κατατρύχω"]={"5348"}} local grc_RWoodhouse_lemma_to_headwords = { ["διαλέγεσθαι"]={"chat","commune with","confer","converse","descant","discourse","discuss","interview","speak","speech","talk"},["κατοιμώζειν"]={"bewail","groan","lament","moan","mourn","sigh","wail"},["ὁμοιοῦσθαι"]={"answer","approximate","equal","identify","like","match","resemble","take"},["Κύθηρα"]={"cythera"},["νότιος"]={"southern"},["παραφθέγγεσθαι"]={"casually","passing"},["φλοιός"]={"bark","rind"},["ψύχειν"]={"benumb","chill","cool","fan","freshen"},["ἑτέρᾳ"]={"another","otherwise"},["εὔτολμος"]={"bold","brave","courageous","doughty"},["μαστροπός"]={"pander","pimp","procurer","procuress"},["περαιοῦν"]={"cross","send"},["περυσινός"]={"last","year"},["πρόσθετος"]={"false"},["τελωνεῖν"]={"tax-collector","toll-collector"},["ψυχαγωγός"]={"conjurer","ghostly","necromancer"},["ἀγροικία"]={"awkwardness","bluntness","boorishness","churlishness","clownishness","coarseness","discourtesy","grossness","impoliteness","inattention","incivility","lowness","roughness","rudeness","rusticity","unmannerliness","vulgarity"},["ἀνίεσθαι"]={"effete","spring"},["ἀντιλαβή"]={"grip","handle","hold","lever"},["ἀποδημία"]={"abroad","absence","emigration","journey","peregrination","travel","trip"},["ἁρμάμαξα"]={"carriage","tilt-waggon"},["Ἀμούλιος"]={"amulius"},["ὠφέλιμος"]={"advantageous","advisable","beneficial","expedient","good","helpful","profitable","serviceable","useful"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} 3mw92cmqzwmp6jbk5j3ps4wqc34n1he Module:data tables/dataM199 828 38988 178498 2026-10-27T05:48:36Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1006"]={"_omnia ad suam utilitatem referre_","to consider one's own advantage in everything."},["1015"]={"_cui bono?_","who gets the advantage from this? who is the interested party?"},["1024"]={"_damnum_ or _detrimentum sarcire_ (not _reparare_)","to make good, repair a loss or injury."},["1033"]={"_gratiosum esse alicui_ or _apud aliquem_","to be popular with; to stand well with a person."},["1042"]={"_pr...' 178498 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1006"]={"_omnia ad suam utilitatem referre_","to consider one's own advantage in everything."},["1015"]={"_cui bono?_","who gets the advantage from this? who is the interested party?"},["1024"]={"_damnum_ or _detrimentum sarcire_ (not _reparare_)","to make good, repair a loss or injury."},["1033"]={"_gratiosum esse alicui_ or _apud aliquem_","to be popular with; to stand well with a person."},["1042"]={"_propenso animo, studio esse_ or _propensa voluntate esse in aliquem_ (opp. _averso animo esse ab aliquo_)","to look favourably upon; to support."},["1051"]={"_beneficium alicui dare, tribuere_","to do any one a service or kindness."},["1060"]={"_gratias alicui agere pro aliqua re_","to thank a person (in words)."},["1105"]={"_amicitiam cum aliquo jungere, facere, inire, contrahere_","to form a friendship with any one."},["1114"]={"_in amicitiam alicuius recipi_","to gain some one's friendship; to become intimate with."},["1123"]={"_inimicitias deponere_","to lay aside one's differences."},["1132"]={"_magna auctoritas est in aliquo_","to possess great authority; to be an influential person."},["1141"]={"_summa dignitate praeditum esse_","to be in a dignified position."},["1150"]={"_alicuius laudes praedicare_","to spread a person's praises."},["1204"]={"_laudem, gloriam quaerere_","to be guided by ambition."},["1213"]={"_bene, male audire (ab aliquo)_","to have a good or bad reputation, be spoken well, ill of."},["1222"]={"_honorem alicui habere, tribuere_","to honour, show respect for, a person."},["1231"]={"_infamiam concipere, subire, sibi conflare_","to incur ignominy."},["1240"]={"_multum operae ac laboris consumere in aliqua re_","to exert oneself very energetically in a matter."},["1303"]={"_animum relaxare, reficere, recreare_ or simply _se reficere, se recreare, refici, recreari (ex aliqua re)_","to recruit oneself, seek relaxation."},["1312"]={"_vir magno ingenio praeditus_","a man of ability."},["1321"]={"_mente captum esse, mente alienata esse_","to be out of one's mind."},["1330"]={"_ingenium, cogitatio_","imagination."},["1402"]={"_omnia ad veritatem_[1] _dicere_","to be truthful in all one's statements."},["1411"]={"_veri simile esse_","to be probable."},["1420"]={"_vehementer errare_","to be in gross error, seriously misled."},["1501"]={"_certum deliberatumque est_","I am firmly resolved."},["1510"]={"_in proposito susceptoque consilio permanere_","to persevere in one's resolve."},["1600"]={"_litteras amplecti_","to be an enthusiastic devotee of letters."},["2005"]={"_actus_","an act."},["2014"]={"_in scaenam aliquid inducere_","to bring a thing upon the stage."},["2023"]={"_saepius revocatur_ (Liv. 7. 2. 9)","he is encored several times."},["2032"]={"_in Sophoclis_ (not _Sophoclea_) _Aiace_ or _apud Sophoclem in Aiace_","in Sophocles' Ajax."},["2041"]={"_ludos instaurare_","to revive public games."},["2050"]={"_ludi Olympia_ (not _ludi Olympici_), _Pythia_","the Olympian, Pythian games."},["2104"]={"_genus dicendi (scribendi); oratio_[1]","style."},["2113"]={"_magniloquentia, granditas verborum_","pathos; passion."},["2122"]={"_elegantia orationis_","tasteful description."},["2131"]={"_lumina, flores dicendi_ (De Or. 3. 25. 96)","flowers of rhetoric; embellishments of style."},["2140"]={"_sententiae inter se nexae_","the connection."},["2203"]={"_de scripto orationem_[3] _habere, dicere_ (opp. _sine scripto, ex memoria_)","to read a speech."},["2212"]={"_vocem intercludere_ (Just. 11. 8. 4)","to prevent some one from speaking."},["2221"]={"_materia mihi crescit_","my subject grows as I write."},["2230"]={"_institutum_ or _id quod institui_","a theme, subject proposed for discussion."},["2302"]={"_ex Platonis Phaedone haec in latinum conversa sunt_","what follows has been translated into Latin from Plato's Phaedo."},["2311"]={"_interpres_","the translator."},["2320"]={"_constructio, structura verborum, forma dicendi_","the construction."},["2401"]={"_ad litteram_ or _litterarum ordine digerere_","to arrange in alphabetical order."},["2410"]={"_librum edere_ (Div. 1. 3. 6)","to publish a book."},["2500"]={"_laetitia gestire_ (Tusc. 4. 6. 13)","to be transported with joy."},["3004"]={"_tam perditis_ or _corruptis moribus_","amongst such moral depravity."},["3013"]={"_certas rationes in agendo_[1] _sequi_","to follow fixed principles of conduct."},["3022"]={"_numen (deorum) divinum_","the sovereign power of the gods."},["3031"]={"_cultus dei, deorum_ (N. D. 2. 3. 8)","worship of the gods; divine service."},["3040"]={"_aliquem divino honere colere_","to pay divine honours to some one."},["3103"]={"_voti damnari, compotem fieri_","to have to pay a vow; to obtain one's wish."},["3112"]={"_manes expiare_ (Pis. 7. 16)","to appease the manes, make sacrifice for departed souls."},["3121"]={"_lectisternium facere, habere_ (Liv. 22. 1. 18)","to hold a lectisternium."},["3130"]={"_libros Sibyllinos adire, consulere, inspicere_","to consult the Sibylline books."},["3202"]={"_paludatus, sagatus_","in a military cloak (_paludamentum_, of a general; _sagum_, of soldiers)."},["3211"]={"_cibo se abstinere_","to abstain from all nourishment."},["3220"]={"_propīno tibi hoc (poculum, salutem)_","I drink your health."},["3301"]={"_sermonem inferre de aliqua re_","to turn the conversation on to a certain subject."},["3310"]={"_hinc sermo ductus est_","the conversation began in this way."},["3400"]={"_ut fit, ita ut fit, ut fere fit_","as usually happens."},["4003"]={"_a senatu res ad populum reicitur_","a matter is referred (for decision) from the senate to the people."},["4012"]={"_de iure suo decedere_ or _cedere_","to waive one's right."},["4021"]={"_conventus agere_ (B. G. 1. 54)","to convene the assizes (used of a provincial governor)."},["4030"]={"_iustitium indicere, edicere_ (Phil. 5. 12)","to proclaim that the courts are closed, a cessation of legal business."},["4102"]={"_accusare aliquem de vi, de veneficiis_","to accuse a person of violence, poisoning."},["4111"]={"_culpa alicuius rei est in aliquo_","some one is to blame in a matter; it is some one's fault."},["4120"]={"_aliquid alicui crimini dare, vitio vertere_ (Verr. 5. 50)","to reproach, blame a person for..."},["4201"]={"_vetus miles, veteranus miles_","veterans; experienced troops."},["4210"]={"_militia functum, perfunctum esse_","to retire from service."},["4300"]={"_agmen claudere, cogere_","to bring up the rear."}} local grc_RWoodhouse_lemma_to_infinitives = { ["εφφλυο"]={"εφφλυερε","εφφλυχισσε"},["εχοσσο"]={"εχοσσαρε"},["οφφερο"]={"οβτυλισσε","οφφερρε","οφφερρι"},["πληθύω"]={"πληθύειν","πληθύεσθαι"},["προφλο"]={"προφλαρε"},["σξυλπο"]={"σξυλπι"},["ἐξαναλύω"]={"ἐξαναλῦσαι"},["εἰσανάγω"]={"εἰσανάγεσθαι","εἰσαναχθῆναι"},["προεῖδον"]={"προϊδέσθαι","προϊδεῖν","προιδέσθαι","προιδεῖν"},["ἀπαλλοτριόω"]={"ἀπαλλοτριῶσαι","ἀπαλλοτριωθῆναι","ἀπηλλοτριωκέναι"},["ἀποτυπόομαι"]={"ἀποτυποῦσθαι"},["ξομπρεηενδο"]={"ξομπραεηενδερε","ξομπρεηενδερε","ξομπρεηενδι","ξομπρενδερε","ξομπρενδι","ξονπρεηενδερε","ξονπρεηενδι","ξονπρεηενδισσε","ξονπρενδερε"}} local la_NLW_headwords_to_path = { ["alexiterius"]={"0/012444"},["ambtsassius"]={"3/012399"},["amplexatrix"]={"1/015457"},["ampullineus"]={"2/018474"},["antisenatus"]={"1/006909"},["ascensorius"]={"1/006749"},["assasinatus"]={"2/012398"},["auocatorius"]={"3/010043"},["barybromius"]={"1/009121"},["beguttarius"]={"3/019419"},["catarrhosus"]={"1/011309"},["chalcotypus"]={"1/001801"},["circumnitor"]={"0/005920"},["circumscuro"]={"0/015052"},["circumuasto"]={"3/008367"},["concrepitus"]={"0/018928"},["conrelinquo"]={"1/013589"},["consummatio"]={"2/000326"},["contorpesco"]={"3/011215"},["cunctisator"]={"1/017545"},["cypressifer"]={"0/018452"},["degluttator"]={"0/021464"},["erudimentum"]={"0/003308"},["exemplarius"]={"1/018353"},["flammiuomus"]={"1/000561"},["flatuositas"]={"3/012511"},["florinellus"]={"1/010445"},["foraminulum"]={"0/005160"},["hortilicius"]={"1/010777"},["interfugium"]={"3/006379"},["intronauigo"]={"0/020576"},["inuitabulum"]={"1/000769"},["inuolubilis"]={"1/020233"},["iracundulus"]={"1/016461"},["maliloquium"]={"2/012430"},["multicordis"]={"2/006810"},["nauigatiuus"]={"1/004617"},["necromantus"]={"3/002451"},["octilaterus"]={"0/021340"},["paruipensio"]={"2/006346"},["pennalismus"]={"1/006961"},["performiter"]={"2/018934"},["perpudendus"]={"1/003221"},["perquamraro"]={"0/019984"},["persentisco"]={"0/001020"},["phtharticus"]={"3/006647"},["porragineus"]={"1/019085"},["praefluuium"]={"2/015102"},["praerequiro"]={"0/008492"},["rebaptismus"]={"1/007801"},["reuolubilis"]={"2/001222"},["semicyathus"]={"3/004147"},["semiinsanus"]={"3/009491"},["semisanctus"]={"1/020869"},["sessiuncula"]={"0/010888"},["stabilitrix"]={"3/020991"},["stemmaticus"]={"2/015262"},["subimpudens"]={"1/009045"},["superambulo"]={"2/008930"},["superincubo"]={"1/001489"},["supermisceo"]={"0/020572"},["triumphifer"]={"0/007884"},["uegeticulus"]={"0/020104"}} local grc_RLBG_lemma_to_index = { ["βλωμός"]={"12611"},["βραχυχρονέομαι"]={"13209"},["ἐννενηκονταέξ"]={"23359"},["κατηκριβωμένως"]={"36470"},["κλιτός"]={"37784"},["κλύσις"]={"37833"},["κλύστη"]={"37836"},["λαθροφαγοποτέω"]={"40605"},["λούπης"]={"42253"},["μεταστοιχείωμα"]={"44862"},["μηρύζω"]={"45228"},["μυδεύω"]={"46502"},["ναϊκός"]={"47071"},["παραθοινατικός"]={"53206"},["προμεσουράνημα"]={"61154"},["προσαινίττομαι"]={"61544"},["προσαριθμητέον"]={"61782"},["προσεπιμίγνυμι"]={"62280"},["ἀδειπνία"]={"796"},["αἰθριάζω"]={"1482"},["ἀπανεμία"]={"6719"},["ἔγκοιτος"]={"19750"},["εὔμικτος"]={"28292"},["εὔψαλτον"]={"28893"},["εὐώδιμος"]={"28899"},["ἡμίθετος"]={"29860"},["ἰσοπαλία"]={"32599"},["κουσπάτωρ"]={"39203"},["ὀλεννύνω"]={"49210"},["πρόσεδρος"]={"61976"},["ἀδοσόληπτος"]={"1009"},["ἀκτινόβρυος"]={"2312"},["ἀλεκτωρικός"]={"2436"},["ἀλωπεκισμός"]={"2880"},["ἀμητρόπολις"]={"3094"},["ἀνδρειόφρων"]={"4387"},["ἀπειροτόκος"]={"6970"},["ἀπεξορισμός"]={"7052"},["ἀποκόσμησις"]={"7631"},["ἀποκτητικός"]={"7667"},["ἀποσυνοψίζω"]={"8206"},["ἀποτελματόω"]={"8261"},["ἀρρενοποιός"]={"9157"},["ἀρχιτελώνης"]={"9502"},["ἀσύνθλαστος"]={"10081"},["γονυκλάριον"]={"14524"},["δικαιολόγος"]={"17215"},["ἐκβόθρευσις"]={"20568"},["ἐξοίστρησις"]={"24518"},["ἐπελαστικός"]={"25247"},["ἐπεξεύρεσις"]={"25324"},["ἑταιρειώτης"]={"27531"},["θεοτοκάριον"]={"30917"},["ἰνστιτόριος"]={"32259"},["κογχυλίδιον"]={"37932"},["κομμοδάριος"]={"38308"},["λαχανοκομέω"]={"40967"},["λειποτάξιον"]={"41105"},["λοιδορητέον"]={"42169"},["μικροκαλύβη"]={"45380"},["ξανθοκάρυον"]={"48184"},["ξυλοκέραιον"]={"48504"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["comprobatus"]={"1909"},["subterfugio"]={"4175"},["interiectus"]={"182","375"},["clarissimus"]={"348","1621"}} local grc_RCunliffe_lemma_to_index = { ["εἰσανάγω"]={"2791"},["τύμβος"]={"9085"},["ῥωγαλέος"]={"8388"},["εἰνάετες"]={"2734"},["χρυσάμπυξ"]={"9689"},["ἐντεσιεργός"]={"3280"},["ἀνέδρακε"]={"825"},["ἐξαναλύω"]={"3320"},["ἔκτοσθεν"]={"2971"}} local grc_RWoodhouse_lemma_to_headwords = { ["Δράκων"]={"draco"},["Θάσιος"]={"thasos"},["μύρωμα"]={"ointment","unguent"},["τύμβος"]={"barrow","grave","mound","sepulchre","tomb"},["ὑπερπονεῖσθαι"]={"labour","toil","work"},["πρόσθεσις"]={"addition","appliance","application","employment"},["πρόσπαιος"]={"sudden","unexpected"},["στερεότης"]={"firmness","hardness","massiveness","rigidity","solidity","stiffness","stubbornness","thickness","toughness"},["ταραχώδως"]={"obstreperously","tumultuously","turbulently","uproariously"},["ἀνόμοιος"]={"different","dissimilar","heterogeneous","unlike"},["Ἐτέοκλος"]={"eteoclus"},["ὠμοπλάτη"]={"blade","shoulder-blade"},["κρεμαννύναι"]={"hang","suspend","swing"},["ἀγνωμονεῖν"]={"inconsiderately","unfeelingly"},["Ἡρακλεῖδαι"]={"heracles"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} q10o26llee7bbkb51qv9x6dbra9l4ik 178509 178498 2026-10-27T06:10:03Z GinawaSaHapon 3989 178509 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1006"]={"_omnia ad suam utilitatem referre_","to consider one's own advantage in everything."},["1015"]={"_cui bono?_","who gets the advantage from this? who is the interested party?"},["1024"]={"_damnum_ or _detrimentum sarcire_ (not _reparare_)","to make good, repair a loss or injury."},["1033"]={"_gratiosum esse alicui_ or _apud aliquem_","to be popular with; to stand well with a person."},["1042"]={"_propenso animo, studio esse_ or _propensa voluntate esse in aliquem_ (opp. _averso animo esse ab aliquo_)","to look favourably upon; to support."},["1051"]={"_beneficium alicui dare, tribuere_","to do any one a service or kindness."},["1060"]={"_gratias alicui agere pro aliqua re_","to thank a person (in words)."},["1105"]={"_amicitiam cum aliquo jungere, facere, inire, contrahere_","to form a friendship with any one."},["1114"]={"_in amicitiam alicuius recipi_","to gain some one's friendship; to become intimate with."},["1123"]={"_inimicitias deponere_","to lay aside one's differences."},["1132"]={"_magna auctoritas est in aliquo_","to possess great authority; to be an influential person."},["1141"]={"_summa dignitate praeditum esse_","to be in a dignified position."},["1150"]={"_alicuius laudes praedicare_","to spread a person's praises."},["1204"]={"_laudem, gloriam quaerere_","to be guided by ambition."},["1213"]={"_bene, male audire (ab aliquo)_","to have a good or bad reputation, be spoken well, ill of."},["1222"]={"_honorem alicui habere, tribuere_","to honour, show respect for, a person."},["1231"]={"_infamiam concipere, subire, sibi conflare_","to incur ignominy."},["1240"]={"_multum operae ac laboris consumere in aliqua re_","to exert oneself very energetically in a matter."},["1303"]={"_animum relaxare, reficere, recreare_ or simply _se reficere, se recreare, refici, recreari (ex aliqua re)_","to recruit oneself, seek relaxation."},["1312"]={"_vir magno ingenio praeditus_","a man of ability."},["1321"]={"_mente captum esse, mente alienata esse_","to be out of one's mind."},["1330"]={"_ingenium, cogitatio_","imagination."},["1402"]={"_omnia ad veritatem_[1] _dicere_","to be truthful in all one's statements."},["1411"]={"_veri simile esse_","to be probable."},["1420"]={"_vehementer errare_","to be in gross error, seriously misled."},["1501"]={"_certum deliberatumque est_","I am firmly resolved."},["1510"]={"_in proposito susceptoque consilio permanere_","to persevere in one's resolve."},["1600"]={"_litteras amplecti_","to be an enthusiastic devotee of letters."},["2005"]={"_actus_","an act."},["2014"]={"_in scaenam aliquid inducere_","to bring a thing upon the stage."},["2023"]={"_saepius revocatur_ (Liv. 7. 2. 9)","he is encored several times."},["2032"]={"_in Sophoclis_ (not _Sophoclea_) _Aiace_ or _apud Sophoclem in Aiace_","in Sophocles' Ajax."},["2041"]={"_ludos instaurare_","to revive public games."},["2050"]={"_ludi Olympia_ (not _ludi Olympici_), _Pythia_","the Olympian, Pythian games."},["2104"]={"_genus dicendi (scribendi); oratio_[1]","style."},["2113"]={"_magniloquentia, granditas verborum_","pathos; passion."},["2122"]={"_elegantia orationis_","tasteful description."},["2131"]={"_lumina, flores dicendi_ (De Or. 3. 25. 96)","flowers of rhetoric; embellishments of style."},["2140"]={"_sententiae inter se nexae_","the connection."},["2203"]={"_de scripto orationem_[3] _habere, dicere_ (opp. _sine scripto, ex memoria_)","to read a speech."},["2212"]={"_vocem intercludere_ (Just. 11. 8. 4)","to prevent some one from speaking."},["2221"]={"_materia mihi crescit_","my subject grows as I write."},["2230"]={"_institutum_ or _id quod institui_","a theme, subject proposed for discussion."},["2302"]={"_ex Platonis Phaedone haec in latinum conversa sunt_","what follows has been translated into Latin from Plato's Phaedo."},["2311"]={"_interpres_","the translator."},["2320"]={"_constructio, structura verborum, forma dicendi_","the construction."},["2401"]={"_ad litteram_ or _litterarum ordine digerere_","to arrange in alphabetical order."},["2410"]={"_librum edere_ (Div. 1. 3. 6)","maglathala ng aklat"},["2500"]={"_laetitia gestire_ (Tusc. 4. 6. 13)","to be transported with joy."},["3004"]={"_tam perditis_ or _corruptis moribus_","amongst such moral depravity."},["3013"]={"_certas rationes in agendo_[1] _sequi_","to follow fixed principles of conduct."},["3022"]={"_numen (deorum) divinum_","the sovereign power of the gods."},["3031"]={"_cultus dei, deorum_ (N. D. 2. 3. 8)","worship of the gods; divine service."},["3040"]={"_aliquem divino honere colere_","to pay divine honours to some one."},["3103"]={"_voti damnari, compotem fieri_","to have to pay a vow; to obtain one's wish."},["3112"]={"_manes expiare_ (Pis. 7. 16)","to appease the manes, make sacrifice for departed souls."},["3121"]={"_lectisternium facere, habere_ (Liv. 22. 1. 18)","to hold a lectisternium."},["3130"]={"_libros Sibyllinos adire, consulere, inspicere_","to consult the Sibylline books."},["3202"]={"_paludatus, sagatus_","in a military cloak (_paludamentum_, of a general; _sagum_, of soldiers)."},["3211"]={"_cibo se abstinere_","to abstain from all nourishment."},["3220"]={"_propīno tibi hoc (poculum, salutem)_","I drink your health."},["3301"]={"_sermonem inferre de aliqua re_","to turn the conversation on to a certain subject."},["3310"]={"_hinc sermo ductus est_","the conversation began in this way."},["3400"]={"_ut fit, ita ut fit, ut fere fit_","as usually happens."},["4003"]={"_a senatu res ad populum reicitur_","a matter is referred (for decision) from the senate to the people."},["4012"]={"_de iure suo decedere_ or _cedere_","to waive one's right."},["4021"]={"_conventus agere_ (B. G. 1. 54)","to convene the assizes (used of a provincial governor)."},["4030"]={"_iustitium indicere, edicere_ (Phil. 5. 12)","to proclaim that the courts are closed, a cessation of legal business."},["4102"]={"_accusare aliquem de vi, de veneficiis_","to accuse a person of violence, poisoning."},["4111"]={"_culpa alicuius rei est in aliquo_","some one is to blame in a matter; it is some one's fault."},["4120"]={"_aliquid alicui crimini dare, vitio vertere_ (Verr. 5. 50)","to reproach, blame a person for..."},["4201"]={"_vetus miles, veteranus miles_","veterans; experienced troops."},["4210"]={"_militia functum, perfunctum esse_","to retire from service."},["4300"]={"_agmen claudere, cogere_","to bring up the rear."}} local grc_RWoodhouse_lemma_to_infinitives = { ["εφφλυο"]={"εφφλυερε","εφφλυχισσε"},["εχοσσο"]={"εχοσσαρε"},["οφφερο"]={"οβτυλισσε","οφφερρε","οφφερρι"},["πληθύω"]={"πληθύειν","πληθύεσθαι"},["προφλο"]={"προφλαρε"},["σξυλπο"]={"σξυλπι"},["ἐξαναλύω"]={"ἐξαναλῦσαι"},["εἰσανάγω"]={"εἰσανάγεσθαι","εἰσαναχθῆναι"},["προεῖδον"]={"προϊδέσθαι","προϊδεῖν","προιδέσθαι","προιδεῖν"},["ἀπαλλοτριόω"]={"ἀπαλλοτριῶσαι","ἀπαλλοτριωθῆναι","ἀπηλλοτριωκέναι"},["ἀποτυπόομαι"]={"ἀποτυποῦσθαι"},["ξομπρεηενδο"]={"ξομπραεηενδερε","ξομπρεηενδερε","ξομπρεηενδι","ξομπρενδερε","ξομπρενδι","ξονπρεηενδερε","ξονπρεηενδι","ξονπρεηενδισσε","ξονπρενδερε"}} local la_NLW_headwords_to_path = { ["alexiterius"]={"0/012444"},["ambtsassius"]={"3/012399"},["amplexatrix"]={"1/015457"},["ampullineus"]={"2/018474"},["antisenatus"]={"1/006909"},["ascensorius"]={"1/006749"},["assasinatus"]={"2/012398"},["auocatorius"]={"3/010043"},["barybromius"]={"1/009121"},["beguttarius"]={"3/019419"},["catarrhosus"]={"1/011309"},["chalcotypus"]={"1/001801"},["circumnitor"]={"0/005920"},["circumscuro"]={"0/015052"},["circumuasto"]={"3/008367"},["concrepitus"]={"0/018928"},["conrelinquo"]={"1/013589"},["consummatio"]={"2/000326"},["contorpesco"]={"3/011215"},["cunctisator"]={"1/017545"},["cypressifer"]={"0/018452"},["degluttator"]={"0/021464"},["erudimentum"]={"0/003308"},["exemplarius"]={"1/018353"},["flammiuomus"]={"1/000561"},["flatuositas"]={"3/012511"},["florinellus"]={"1/010445"},["foraminulum"]={"0/005160"},["hortilicius"]={"1/010777"},["interfugium"]={"3/006379"},["intronauigo"]={"0/020576"},["inuitabulum"]={"1/000769"},["inuolubilis"]={"1/020233"},["iracundulus"]={"1/016461"},["maliloquium"]={"2/012430"},["multicordis"]={"2/006810"},["nauigatiuus"]={"1/004617"},["necromantus"]={"3/002451"},["octilaterus"]={"0/021340"},["paruipensio"]={"2/006346"},["pennalismus"]={"1/006961"},["performiter"]={"2/018934"},["perpudendus"]={"1/003221"},["perquamraro"]={"0/019984"},["persentisco"]={"0/001020"},["phtharticus"]={"3/006647"},["porragineus"]={"1/019085"},["praefluuium"]={"2/015102"},["praerequiro"]={"0/008492"},["rebaptismus"]={"1/007801"},["reuolubilis"]={"2/001222"},["semicyathus"]={"3/004147"},["semiinsanus"]={"3/009491"},["semisanctus"]={"1/020869"},["sessiuncula"]={"0/010888"},["stabilitrix"]={"3/020991"},["stemmaticus"]={"2/015262"},["subimpudens"]={"1/009045"},["superambulo"]={"2/008930"},["superincubo"]={"1/001489"},["supermisceo"]={"0/020572"},["triumphifer"]={"0/007884"},["uegeticulus"]={"0/020104"}} local grc_RLBG_lemma_to_index = { ["βλωμός"]={"12611"},["βραχυχρονέομαι"]={"13209"},["ἐννενηκονταέξ"]={"23359"},["κατηκριβωμένως"]={"36470"},["κλιτός"]={"37784"},["κλύσις"]={"37833"},["κλύστη"]={"37836"},["λαθροφαγοποτέω"]={"40605"},["λούπης"]={"42253"},["μεταστοιχείωμα"]={"44862"},["μηρύζω"]={"45228"},["μυδεύω"]={"46502"},["ναϊκός"]={"47071"},["παραθοινατικός"]={"53206"},["προμεσουράνημα"]={"61154"},["προσαινίττομαι"]={"61544"},["προσαριθμητέον"]={"61782"},["προσεπιμίγνυμι"]={"62280"},["ἀδειπνία"]={"796"},["αἰθριάζω"]={"1482"},["ἀπανεμία"]={"6719"},["ἔγκοιτος"]={"19750"},["εὔμικτος"]={"28292"},["εὔψαλτον"]={"28893"},["εὐώδιμος"]={"28899"},["ἡμίθετος"]={"29860"},["ἰσοπαλία"]={"32599"},["κουσπάτωρ"]={"39203"},["ὀλεννύνω"]={"49210"},["πρόσεδρος"]={"61976"},["ἀδοσόληπτος"]={"1009"},["ἀκτινόβρυος"]={"2312"},["ἀλεκτωρικός"]={"2436"},["ἀλωπεκισμός"]={"2880"},["ἀμητρόπολις"]={"3094"},["ἀνδρειόφρων"]={"4387"},["ἀπειροτόκος"]={"6970"},["ἀπεξορισμός"]={"7052"},["ἀποκόσμησις"]={"7631"},["ἀποκτητικός"]={"7667"},["ἀποσυνοψίζω"]={"8206"},["ἀποτελματόω"]={"8261"},["ἀρρενοποιός"]={"9157"},["ἀρχιτελώνης"]={"9502"},["ἀσύνθλαστος"]={"10081"},["γονυκλάριον"]={"14524"},["δικαιολόγος"]={"17215"},["ἐκβόθρευσις"]={"20568"},["ἐξοίστρησις"]={"24518"},["ἐπελαστικός"]={"25247"},["ἐπεξεύρεσις"]={"25324"},["ἑταιρειώτης"]={"27531"},["θεοτοκάριον"]={"30917"},["ἰνστιτόριος"]={"32259"},["κογχυλίδιον"]={"37932"},["κομμοδάριος"]={"38308"},["λαχανοκομέω"]={"40967"},["λειποτάξιον"]={"41105"},["λοιδορητέον"]={"42169"},["μικροκαλύβη"]={"45380"},["ξανθοκάρυον"]={"48184"},["ξυλοκέραιον"]={"48504"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["comprobatus"]={"1909"},["subterfugio"]={"4175"},["interiectus"]={"182","375"},["clarissimus"]={"348","1621"}} local grc_RCunliffe_lemma_to_index = { ["εἰσανάγω"]={"2791"},["τύμβος"]={"9085"},["ῥωγαλέος"]={"8388"},["εἰνάετες"]={"2734"},["χρυσάμπυξ"]={"9689"},["ἐντεσιεργός"]={"3280"},["ἀνέδρακε"]={"825"},["ἐξαναλύω"]={"3320"},["ἔκτοσθεν"]={"2971"}} local grc_RWoodhouse_lemma_to_headwords = { ["Δράκων"]={"draco"},["Θάσιος"]={"thasos"},["μύρωμα"]={"ointment","unguent"},["τύμβος"]={"barrow","grave","mound","sepulchre","tomb"},["ὑπερπονεῖσθαι"]={"labour","toil","work"},["πρόσθεσις"]={"addition","appliance","application","employment"},["πρόσπαιος"]={"sudden","unexpected"},["στερεότης"]={"firmness","hardness","massiveness","rigidity","solidity","stiffness","stubbornness","thickness","toughness"},["ταραχώδως"]={"obstreperously","tumultuously","turbulently","uproariously"},["ἀνόμοιος"]={"different","dissimilar","heterogeneous","unlike"},["Ἐτέοκλος"]={"eteoclus"},["ὠμοπλάτη"]={"blade","shoulder-blade"},["κρεμαννύναι"]={"hang","suspend","swing"},["ἀγνωμονεῖν"]={"inconsiderately","unfeelingly"},["Ἡρακλεῖδαι"]={"heracles"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} gvkl6uf9l6rylkrcov8x2zub36icliq Module:data tables/dataM207 828 38989 178499 2026-10-27T05:49:22Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1059"]={"_gratiam alicui referre (meritam, debitam) pro aliqua re_","to show gratitude (in one's acts)."},["1068"]={"_pro maleficiis beneficia reddere_","to return good for evil."},["1077"]={"_meritum praemium alicui persolvere_","to reward a man according to his deserts."},["1086"]={"_precibus aliquem fatigare_","to importune with petitions."},["1095"]={"_aliquid ab aliquo impetrare_","to gain one's point...' 178499 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1059"]={"_gratiam alicui referre (meritam, debitam) pro aliqua re_","to show gratitude (in one's acts)."},["1068"]={"_pro maleficiis beneficia reddere_","to return good for evil."},["1077"]={"_meritum praemium alicui persolvere_","to reward a man according to his deserts."},["1086"]={"_precibus aliquem fatigare_","to importune with petitions."},["1095"]={"_aliquid ab aliquo impetrare_","to gain one's point with any one."},["1149"]={"_laudibus aliquem (aliquid) in caelum ferre, efferre, tollere_","to extol, laud to the skies."},["1158"]={"_res a me probatur_","I express my approval of a thing."},["1167"]={"_fama serpit (per urbem)_","a report is spreading imperceptibly."},["1176"]={"_in ore omnium_ or _omnibus_ (_hominum_ or _hominibus_, but only _mihi, tibi_, etc.) _esse_","to be in every one's mouth."},["1185"]={"_Romam nuntiatum est, allatum est_","news reached Rome."},["1194"]={"_laudem afferre_","to confer distinction on a person; to redound to his credit."},["1239"]={"_operam (laborem, curam) in_ or _ad aliquid impendere_","to expend great labour on a thing."},["1248"]={"_labori, operae non parcere_","to spare no pains."},["1257"]={"_fugiens laboris_","lazy."},["1266"]={"_negotium suscipere_","to undertake an affair."},["1275"]={"_magnum negotium est_ c. Inf.","it is a great undertaking to..."},["1284"]={"_otio abūti_[1] or _otium ad suum usum transferre_","to use up, make full use of one's spare time."},["1293"]={"_voluptates haurire_","to take one's fill of enjoyment."},["1329"]={"_cogitatione sibi aliquid depingere_","to picture to oneself."},["1338"]={"_illud succurrit mihi_","an idea strikes me."},["1347"]={"_cogitationes in res humiles abicere_ (De Amic. 9. 32) (Opp. _alte spectare, ad altiora tendere, altum, magnificum, divinum suspicere_)","to study the commonplace."},["1356"]={"_absolutio et perfectio_ (not _summa perfectio_)","ideal perfection."},["1365"]={"_illa civitas, quam Plato finxit_","Plato's ideal republic."},["1374"]={"_ad alicuius sententiam accedere, sententiam alicuius sequi_","to adopt some one's opinion."},["1383"]={"_mea (quidem) sententia_","according to my opinion."},["1392"]={"_monstra_ or _portenta_","marvellous ideas; prodigies."},["1419"]={"_in magno errore versari_","to be in gross error, seriously misled."},["1428"]={"_errorem amputare et circumcīdere_","to banish an error, do away with a false impression."},["1437"]={"_in dubium vocare_","to throw doubt upon a thing."},["1446"]={"_sine ulla dubitatione_","without any hesitation; without the least scruple."},["1455"]={"_hoc_ (not _tantum_) _certum est_","this much is certain."},["1464"]={"_velim tibi ita persuadeas_","convince yourself of this; rest assured on this point."},["1473"]={"_a consilio deterreri aliqua re_","to be deterred from one's intention by something."},["1482"]={"_consultare_ or _deliberare (de aliqua re)_","to deliberate, consider (of individuals)."},["1491"]={"_nullo consilio, nulla ratione, temere_","without reflection; inconsiderately; rashly."},["1509"]={"_in incepto_ or _conatu perstare_","to persevere in one's resolve."},["1518"]={"_id sequor, ut_","my intention is..."},["1527"]={"_eo consilio, ea mente, ut_","with the intention of..."},["1536"]={"_memoriā tenere aliquid_","to remember a thing perfectly."},["1545"]={"_memoriter_","(1) with good memory; (2) from personal recollection."},["1554"]={"_memoriam alicuius rei repraesentare_ (opp. _memoriam alicuius rei deponere, abicere_)","to picture to oneself again."},["1563"]={"_memoriam nominis sui immortalitati tradere, mandare, commendare_","to immortalise one's name."},["1572"]={"_memoria alicuius rei obscuratur, obliteratur, evanescit_","to be forgotten, pass into oblivion."},["1581"]={"_doctrinam ad usum adiungere_","to combine theory with practice."},["1590"]={"_(rerum) imperitum esse_","to have had no experience of the world."},["1608"]={"_in litteris acquiescere_ or _conquiescere_","to find recreation in study."},["1617"]={"_primis (ut dicitur)_[3] or _primoribus labris gustare_ or _attingere litteras_","to have a superficial knowledge, a smattering of literature, of the sciences."},["1626"]={"_vir perfecte planeque eruditus_","a man of profound erudition."},["1635"]={"_a doctrina mediocriter instructum esse_","to have received only a moderate education."},["1644"]={"_penitus percipere et comprehendere aliquid_ (De Or. 1. 23. 108)","to have a thorough grasp of a subject."},["1653"]={"_sunt in illo, ut in homine Romano, multae litterae_ (De Sen. 4. 12)","for a Roman he is decidedly well educated."},["1662"]={"_mores alicuius corrigere_","to improve a person."},["1671"]={"_multum esse cum aliquo_ (Fam. 16. 21)","to enjoy close intercourse with... (of master and pupil)."},["1680"]={"_erudire aliquem artibus, litteris_ (but _erudire aliquem in iure civili, in re militari_)","to teach some one letters."},["1707"]={"_aliquid exemplis probare, comprobare, confirmare_","to quote precedents for a thing."},["1716"]={"_auctorem aliquem habere alicuius rei_","to have as authority for a thing."},["1725"]={"_exemplum (severitatis) edere in aliquo_ (Q. Fr. 1. 2. 2. 5)","to inflict an exemplary punishment on some one."},["1734"]={"_animum appellere_ or _se applicare ad philosophiam_","to apply oneself to the study of philosophy."},["1743"]={"_praecepta philosophorum (penitus) percepta habere_","to be well acquainted with the views of philosophers."},["1752"]={"_scholas habere, explicare_ (Fin. 2. 1. 1)","to give lectures."},["1761"]={"_disserendi spinae_ (Fin. 4. 28. 79)","subtleties of logic; dilemmas."},["1770"]={"_philosophia,_[3] _quae in actione versatur_","practical philosophy."},["1806"]={"_argumentum afferre_","to bring forward a proof."},["1815"]={"_loci (τόποι) argumentorum_ (De Or. 2. 162)","the points on which proofs are based; the grounds of proof."},["1824"]={"_positum est a nobis primum_ (c. Acc. c. Inf.)","we start by presupposing that..."},["1833"]={"_in nullam partem disputare_","to say nothing either for or against an argument."},["1842"]={"_in controversiam cadere_","to be at variance with."},["1851"]={"_transigere aliquid cum aliquo_","to come to an understanding with a person."},["1860"]={"_omnes (uno ore) in hac re consentiunt_","all agree on this point."},["1905"]={"_ut a fabulis ad facta veniamus_","to pass from myth to history."},["1914"]={"_domestica (externa) nosse_","to be acquainted with the history of one's own land."},["1923"]={"_Africae situm paucis exponere_","to give a brief exposition of the geography of Africa."},["1932"]={"_numeri (-orum)_","arithmetic."},["1941"]={"_artis praecepta_, or also simply _ars_","the rules of art; aesthetics."},["1950"]={"_abhorrere ab artibus_ (opp. _delectari artibus_)","to have no taste for the fine arts."},["2049"]={"_ludi apparatissimi_","sumptuous public games."},["2058"]={"_rhetor, dicendi magister_","a teacher of rhetoric."},["2067"]={"_eloquentiae laude florere_","to be a distinguished orator."},["2076"]={"_subito, ex tempore_ (opp. _ex praeparato_) _dicere_","to speak extempore."},["2085"]={"_plane, aperte dicere_","to speak openly, straightforwardly."},["2094"]={"_finem dicendi facere_","to cease speaking."},["2139"]={"_exponere aliquid_ or _de aliqua re_","to give an account of a thing (either orally or in writing)."},["2148"]={"_summo colore aliquid illustrare_","to depict a thing in lively colours."},["2157"]={"_in brevi conspectu ponere aliquid_","to make a short survey of a thing."},["2166"]={"_pluribus verbis, copiosius explicare, persequi_[6] _aliquid_","to give a full, detailed account of a thing."},["2175"]={"_in medio ponere (proponere)_","to publish, make public."},["2184"]={"_digressus, digressio, egressio_","a digression, episode."},["2193"]={"_studio alicuius rei provectus sum_","my zeal for a thing has led me too far."},["2229"]={"_id quod quaerimus (quaeritur)_","a theme, subject proposed for discussion."},["2238"]={"_ponere_","to propose, set a theme."},["2247"]={"_quaerendum esse mihi visum est_","the question has forced itself on my mind."},["2256"]={"_haec iocatus sum, per iocum dixi_","I said it in jest."},["2265"]={"_dicta dicere in aliquem_","to make jokes on a person."},["2274"]={"_serio dicere_ (Plaut. Bacch. 1. 1. 42)","to say in earnest..."},["2283"]={"_eiusdem linguae societate coniunctum esse cum aliquo_ (De Or. 3. 59. 223)","to be united by having a common language."},["2292"]={"_incorrupta latini sermonis integritas_[1] (Brut. 35. 132)","pure, correct Latin."},["2319"]={"_ambitus, circuitus, comprehensio, continuatio (verborum, orationis)_, also simply _periodus_","the period."},["2328"]={"_verbo, nomine; re, re quidem vera_","nominally; really."},["2337"]={"_ne verbum_ (without _unum_) _quidem de aliquo facere_","to say not a syllable about a person."},["2346"]={"_verbum prorsus nullum intellegere_","not to understand a single word."},["2355"]={"_nomen amicitiae_ (or simply _amicitia_) _dicitur ab amando_","the word _amicitia_ comes from _amare_."},["2364"]={"_quid est virtus?_","what do we mean by 'virtue'?"},["2373"]={"_hoc vocabulum generis neutri_ (not _neutrius_) _est_)","this word is neuter."},["2382"]={"_dissimulatio_ (Off. 1. 30. 108)","irony."},["2391"]={"_proverbium vetustate_ or _sermone tritum_ (_vid._ sect. II. 3, note _tritus..._)","an old proverb which every one knows."},["2409"]={"_librum conficere, componere_ (De Sen. 1. 2)","to compose, compile a book."},["2418"]={"_exstat liber_ (notice the order of the words)","the book is still extant."},["2427"]={"_libro scriptor complexus est aliquid_","the book contains something... (not _continet aliquid_)."},["2436"]={"_liber accurate, diligenter scriptus_","a carefully written book."},["2445"]={"_Platonem legere et cognoscere_","to study Plato."},["2454"]={"_mendum (scripturae)_ (Fam. 6. 7. 1)","a clerical error, copyist's mistake."},["2463"]={"_epistularum commercium_","correspondence."},["2472"]={"_litteras recitare_ (Att. 8. 9. 2)","to read a letter aloud (in public)."},["2481"]={"_animos tentare_ (Cluent. 63. 176)","to try to divine a person's disposition."},["2490"]={"_alicuius mentem turbare, conturbare, perturbare_","to upset a person."},["2508"]={"_tuam vicem_[3] _doleo_","I am sorry for you."},["2517"]={"_dolor infixus animo haeret_ (Phil. 2. 26)","grief has struck deep into his soul."},["2526"]={"_in aegritudine, sollicitudine esse_","to be vexed, mortified, anxious."},["2535"]={"_aegritudinem alicuius elevare_","to comfort another in his trouble."},["2544"]={"_in sordibus luctuque iacēre_","to be in great trouble, affliction."},["2553"]={"_timor aliquem occupat_ (B. G. 1. 39)","fear comes upon some one."},["2562"]={"_respirandi spatium dare_","to give time for recovery."},["2571"]={"_bonum animum habere_","to be brave, courageous."},["2580"]={"_animum alicui augere_ (B. G. 7. 70)","to increase a person's courage."},["2607"]={"_de gradu deici, ut dicitur_[1]","to lose one's composure; to be disconcerted."},["2616"]={"_desperare_[3] _suis rebus_","to despair of one's position."},["2625"]={"_bene, optime (meliora) sperare de aliquo_ (Nep. Milt. 1. 1)","to hope well of a person."},["2634"]={"_spes affulget_ (Liv. 27. 28)","a ray of hope shines on us."},["2643"]={"_spes me frustratur_","hope has played me false."},["2652"]={"_praeter spem, exspectationem_","contrary to expectation."},["2661"]={"_misericordiam alicuius concitare_","to excite some one's pity."},["2670"]={"_omnem humanitatem ex animo exstirpare_ (Amic. 13. 48)","to stifle, repress all humane sentiments in one's mind."},["2706"]={"_ardor animi resēdit, consedit_","his enthusiasm has abated, cooled down."},["2715"]={"_fiducia sui_ (Liv. 25. 37)","self-confidence."},["2724"]={"_fide data et accepta_ (Sall. Iug. 81. 1)","having exchanged pledges, promises."},["2733"]={"_fidem persolvere_","to fulfil a promise."},["2742"]={"_sponsionem facere, sponsorem esse pro aliquo_","to be security for some one."},["2751"]={"_suspicionem a se removere, depellere, propulsare_ (Verr. 3. 60. 140)","to clear oneself of a suspicion."},["2760"]={"_odio, invidiae esse alicui_","to be hated by some one."},["2805"]={"_furore inflammari, incendi_","to become furious."},["2814"]={"_virtutem sequi, virtutis studiosum esse_","to strive to attain virtue."},["2823"]={"_a parentibus degenerare_","to degenerate (from one's ancestors)."},["2832"]={"_vitiis, sceleribus contaminari_ or _se contaminare_ (Off. 3. 8. 37)","to be tainted with vice."},["2841"]={"_scelere se devincire, se obstringere, astringi_","to commit a crime and so make oneself liable to the consequences of it."},["2850"]={"_aliquem cupiditate inflammare_","to rouse a person's interest, cupidity."},["2904"]={"_subsidere in insidiis_ (Mil. 19. 49)","to place oneself in ambush."},["2913"]={"_in speciem_","apparently; to look at."},["2922"]={"_dolis et fallaciis_ (Sall. Cat. 11. 2)","by the aid of fraud and lies."},["2931"]={"_omnibus artibus aliquem ludificari, eludere_","to fool a person thoroughly."},["2940"]={"_ab officio discedere_","to neglect one's duty."},["3039"]={"_aliquem in deorum numero referre_","to consider as a god."},["3048"]={"_religionem ex animis extrahere_ (N. D. 1. 43. 121)","to banish devout sentiment from the minds of others."},["3057"]={"_novas religiones instituere_","to introduce a new religion, a new cult."},["3066"]={"_iusiurandum (religionem) servare, conservare_","to keep one's oath."},["3075"]={"_impietas_","unbelief."},["3084"]={"_precari deum, deos_","to pray to God."},["3093"]={"_contestari deos hominesque_","to call gods and men to witness."},["3129"]={"_prodigia procurare_[1] (Liv. 22. 1)","to avert by expiatory sacrifices the effect of ominous portents."},["3138"]={"_faustis ominibus_","with favourable omens."},["3147"]={"_domus rimas agit_","the house walls are beginning to crack."},["3156"]={"_in publico_","in the streets."},["3165"]={"_fores obserare_","to bolt the door."},["3174"]={"_diligentem, frugi esse_","to be economical."},["3183"]={"_evertere aliquem bonis, fortunis patriis_","to drive a person out of house and home."},["3192"]={"_multitudinem in agris collocare_","to settle a large number of people in a country."},["3219"]={"_alicui bibere ministrare_","to serve some one with drink."},["3228"]={"_res ad victum cultumque necessariae_","things indispensable to a life of comfort."},["3237"]={"_non habeo, qui (unde) vivam_","I have no means, no livelihood."},["3246"]={"_delicate ac molliter vivere_","to live a luxurious and effeminate life."},["3255"]={"_mensae exstructae_","a table bountifully spread."},["3264"]={"_adhibere aliquem cenae_ or _ad cenam, convivio_ or _in convivium_","to welcome some one to one's table."},["3273"]={"_hospitio aliquem accipere_ or _excipere (domum ad se)_","to welcome a man as a guest in one's house."},["3282"]={"_aliquem socium admittere_","to admit a person into one's society."},["3291"]={"_se dare in consuetudinem alicuius_","to devote oneself to a person's society."},["3309"]={"_sermonem habere cum aliquo de aliqua re_ (De Am. 1. 3)","to converse, talk with a person on a subject."},["3318"]={"_sui potestatem facere, praebere alicui_","to give audience to some one."},["3327"]={"_sermo cotidianus_, or simply _sermo_","conversational language."},["3336"]={"_quid agitur? quid fit?_","what is going on? how are you getting on?"},["3345"]={"_te valere_[3] _iubeo_","I bid you good-bye, take my leave."},["3354"]={"_ducere uxorem_","to marry (of the man)."},["3363"]={"_nuntium remittere alicui_ (De Or. 1. 40)","to separate, be divorced (used of man or woman)."},["3372"]={"_testamentum subicere, supponere_","to produce a false will."},["3381"]={"_exheredari a patre_","to be disinherited."},["3390"]={"_consuetudinem suam tenere, retinere,[TR1] servare_","to keep up a usage."},["3408"]={"_negotii bene gerentes_ (Quint. 19. 62)","good men of business."},["3417"]={"_quaestui aliquid habere_ (Off. 2. 3. 13)","to make a profit out of something."},["3426"]={"_pecunia exigua_ or _tenuis_","little money."},["3435"]={"_pecuniam alicui debere_","to owe some one money."},["3444"]={"_non solvendo_[3] _esse_ (Phil. 2. 2. 4)","to be bankrupt."},["3453"]={"_argentariam dissolvere_ (Caecin. 4. 11)","to close one's bank, give up banking."},["3462"]={"_inita subductaque ratione aliquid facere_","to do something after careful calculation."},["3471"]={"_rationem ab aliquo reptere de aliqua re_ (Cluent. 37. 104)","to demand an account, an audit of a matter."},["3480"]={"_quadrantes usurae_","3 per cent (a quarter of centesima)."},["3507"]={"_incidere in aes alienum_","to get into debt."},["3516"]={"_ex aere alieno exire_","to get out of debt."},["3525"]={"_turrim excitare, erigere, facere_","to build a tower."},["3534"]={"_agros fertiles deserere_","to leave fertile ground untilled."},["3543"]={"_odores, qui efflantur e floribus_","the perfume exhaled by flowers."},["3552"]={"_arbores caedere_","to fell trees."},["3561"]={"_rem pecuariam facere, exercere_ (cf. Varr R. R. 2. 1)","to rear stock."},["3570"]={"_instituta et leges_","the constitution."},["3606"]={"_rei publicae rationibus_ or simply _rei publicae consulere_","to further the public interests."},["3615"]={"_viri rerum civilium, rei publicae gerendae periti_ or _viri in re publica prudentes_","statesmen."},["3624"]={"_rei publicae muneribus orbatus_","banished from public life."},["3633"]={"_homo novus_[1]","a parvenu (a man no member of whose family has held curule office)."},["3642"]={"_summi (et) infimi_ (Rep. 1. 34. 53)","high and low."},["3651"]={"_infima fortuna_ or _condicio servorum_","a degraded, servile condition."},["3660"]={"_aliquem gradu movere, depellere_ or _de gradu (statu) deicere_","to overthrow a person (cf. sect. IX. 6)."},["3705"]={"_sententia_ or _voluntas legis_","the spirit of the law."},["3714"]={"_acta rescindere, dissolvere_ (Phil. 13. 3. 5)","to declare a magistrate's decisions null and void."},["3723"]={"_gratiosum esse_ (opp. _invisum esse_)","to be popular, influential."},["3732"]={"_invidia_","unpopularity."},["3741"]={"_certamen partium_","party-strife."},["3750"]={"_nullius_ or _neutrius_ (of two) _partis esse_","to be neutral."},["3804"]={"_omnia turbare ac miscere_","to cause universal disorder."},["3813"]={"_plebem continere_","to hold the people in one's power, in check."},["3822"]={"_de, e civitate aliquem eicere_","to banish a person, send him into exile."},["3831"]={"_exsulare_ (Div. 2. 24. 52)","to live in exile."},["3840"]={"_imperium tenere (in aliquem)_","to have power over some one."},["3903"]={"_colōnos mittere_ (Div. 1. 1. 3)","to send out colonists."},["3912"]={"_provinciam obire_","to visit, traverse a province."},["3921"]={"_omnes centurias ferre_ or _omnium suffragiis, cunctis centuriis creari_","to be elected unanimously"},["3930"]={"_prorogare alicui imperium (in annum)_","to prolong a person's command."},["4029"]={"_aequo iure vivere cum aliquo_","to live with some one on an equal footing."},["4038"]={"_ius praecipuum, beneficium, donum_, also _immunitas_[2] c. Gen.","prerogative, privilege."},["4047"]={"_deprehendere aliquem in manifesto scelere_","to take a person in the act."},["4056"]={"_testem prodire (in aliquem)_","to appear as witness against a person."},["4065"]={"_causa privata_","a civil case."},["4074"]={"_patronus_[1] _(causae)_ (De Or. 2. 69)","counsel; advocate."},["4083"]={"_causam_ or _litem amittere, perdere_","to lose one's case."},["4092"]={"_iudices reicere_ (Verr. 3. 11. 28)","to challenge, reject jurymen."},["4119"]={"_culpam alicui attribuere, assignare_","to attribute the fault to some one."},["4128"]={"_animadvertere in aliquem_","to punish some one."},["4137"]={"_poenas (graves) dare alicui_","to be (heavily) punished by some one."},["4146"]={"_decem milibus aeris damnari_","to be fined 10,000 asses."},["4155"]={"_supplicium sumere de aliquo_","to execute the death-sentence on a person."},["4164"]={"_mortem_[2] _deprecari_ (B. G. 7. 40. 6)","to beg for life."},["4173"]={"_ad nomen non respondere_ (Liv. 7. 4)","to fail to answer one's name."},["4182"]={"_evocati, voluntarii_ (B. G. 5. 56)","the volunteers."},["4191"]={"_parare exercitum, copias_","to equip an army, troops."},["4209"]={"_emeritis stipendiis_ (Sall. Iug. 84. 2)","after having completed one's service."},["4218"]={"_intercludere, prohibere hostes commeatu_","to cut off all supplies of the enemy."},["4227"]={"_res bene gesta_","a success; a glorious feat of arms."},["4236"]={"_modestia_[2] (opp. _immodestia_)","discipline (insubordination)."},["4245"]={"_ab armis discedere_ (Phil. 11. 33)","to lay down arms."},["4254"]={"_eminus hastis, comminus gladiis uti_","to use javelins at a distance, swords at close quarters."},["4263"]={"_bellum parare_","to make preparations for war."},["4272"]={"_bellum moliri_","to meditate war."},["4281"]={"_bellum coniungere_ (Imp. Pomp. 9. 26)","to wage war in conjunction with some one."},["4290"]={"_bello persequi aliquem, lacessere_","to harass with war."},["4308"]={"_raptim agmen ducere_","to lead the army with forced marches."},["4317"]={"_signa convertere_ (B. G. 1. 25)","to deviate, change the direction."},["4326"]={"_ordines turbare, perrumpere_","to break the ranks."},["4335"]={"_gradum sistere_","to halt."},["4344"]={"_praesidia, custodias disponere_","to station posts, pickets, at intervals."},["4353"]={"_castra munire vallo (aggere)_","to fortify the camp with a rampart."},["4362"]={"_custodias agere in vallo_","to keep watch on the rampart."},["4371"]={"_capere equos_","to capture horses."},["4380"]={"_consilium habere, convocare_","to hold a council of war."},["4407"]={"_munitiones perrumpere_","to break through the lines (and relieve a town)."},["4416"]={"_in oppidum irruptionem facere_","to break into the town."},["4425"]={"_salutem petere a victore_","to beg for mercy from the conqueror."},["4434"]={"_potestatem sui facere (alicui)_ (cf. sect. XII. 9, note _audientia..._)","to accept battle."},["4443"]={"_vexillum proponere_ (Liv. 22. 3)","to fix the ensign on the general's tent (as a signal to commence the engagement)."},["4452"]={"_media acies_","the centre."},["4461"]={"_proelium facere_","to give battle."},["4470"]={"_proelium renovare, redintegrare_","to begin the fight again."},["4506"]={"_gladio comminus_ (opp. _eminus_) _rem gerere_","to fight with swords at close quarters."},["4515"]={"_in latus hostium incurrere_","to fall upon the enemy's flank."},["4524"]={"_phalangem perfringere_","to break through the phalanx."},["4533"]={"_repellere, propulsare hostem_","to repulse an attack."},["4542"]={"_in fugam dare, conicere hostem_","to put the enemy to flight."},["4551"]={"_fugae se mandare_ (B. G. 2. 24)","to take to flight."},["4560"]={"_ex (in) fuga dissipati_ or _dispersi_ (B. G. 2. 24)","soldiers routed and dispersed."},["4605"]={"_victoriam_ or _de victoria gratulari alicui_","to congratulate a person on his victory."},["4614"]={"_agere cum aliquo de pace_","to treat with some one about peace."},["4623"]={"_summa pax_","deep peace."},["4632"]={"_foedus frangere, rumpere, violare_","to violate a treaty, terms of alliance."},["4641"]={"_populum perdomare, subigere_","to subjugate a nation."},["4650"]={"_aliquem ad officium_ (cf. sect. X. 7, note _officium..._) _reducere_ (Nep. Dat. 2. 3)","to reduce a people to their former obedience."},["4704"]={"_procella (tempestas) aliquem ex alto ad ignotas terras (oras) defert_","the storm drives some one on an unknown coast."},["4713"]={"_ad ancoras deligari_","to ride at anchor."},["4722"]={"_navis praetoria_ (Liv. 21. 49)","the admiral's ship; the flagship."},["4731"]={"_navem capere, intercipere, deprehendere_","to capture a boat."},["4740"]={"_ne dicam_","not to say... (used in avoiding a stronger expression)."},["4803"]={"_hoc est luce (sole ipso) clarius_","this is as clear as daylight."},["4812"]={"_si quaeris, si verum quaerimus_","to put it exactly."},["4821"]={"_audio, fateor_","I admit it, say on."},["4830"]={"_rem acu tetigisti_","you have hit the nail on the head."}} local grc_RWoodhouse_lemma_to_infinitives = { ["πρυτανεύω"]={"πρυτανεύειν","πρυτανεύεσθαι","πρυτανεῦσαι"},["τυροπωλέω"]={"τυροπωλῆσαι"},["δουλόω"]={"δεδουλῶσθαι","δουλοῦσθαι","δουλώσασθαι","δουλώσεσθαι","δουλωθῆναι"},["εϝερρο"]={"ευερρερε","εϝερρερε","εϝερρι"},["προδιαγιγνώσκω"]={"προδιαγνῶναι"},["ϝερεορ"]={"υερερι"}} local la_NLW_headwords_to_path = { ["coequestris"]={"2/021462"},["conuexitudo"]={"1/015181"},["corruscator"]={"0/009224"},["doctorculus"]={"0/004804"},["festomastix"]={"2/011282"},["flatulentus"]={"1/011865"},["flexuositas"]={"2/007598"},["frontiuagus"]={"0/008328"},["futuridicus"]={"3/003907"},["inassecutus"]={"3/008571"},["inclaustrum"]={"3/011163"},["inerticulus"]={"2/013194"},["infortitudo"]={"1/015197"},["insaturitas"]={"1/009261"},["intorticium"]={"2/014702"},["monopetalus"]={"1/018625"},["perausculto"]={"0/020780"},["perliquidus"]={"2/021182"},["perstudiose"]={"2/017674"},["pertrepidus"]={"2/008842"},["populariter"]={"3/006607"},["prolongator"]={"2/012218"},["redemptiuus"]={"3/016995"},["responsatio"]={"0/006728"},["semiadustus"]={"2/004114"},["semicrispus"]={"0/012676"},["seminatiuus"]={"1/004669"},["singularizo"]={"1/009501"},["subinfirmus"]={"2/009054"},["subplumbeus"]={"0/019392"},["subsordidus"]={"0/009336"},["suffuraneus"]={"2/020178"},["superductio"]={"1/002481"},["supermelior"]={"2/002126"},["sustentamen"]={"0/008088"},["sustinentia"]={"2/017834"},["triformiter"]={"0/019532"},["tripartilis"]={"0/013080"},["uerbunculum"]={"0/013036"},["uituperalis"]={"3/020687"}} local grc_RLBG_lemma_to_index = { ["ἀέθλευμα"]={"1064"},["ἀνάσκελα"]={"4151"},["βραχύωρος"]={"13211"},["βρυχησμός"]={"13425"},["γεφύρωσις"]={"14006"},["διαχρυσόω"]={"16820"},["ἔμποινος"]={"22318"},["ἐξεβραία"]={"24236"},["λαθριδίῃ"]={"40589"},["μυρταΐτης"]={"46899"},["νυμφαῖοι"]={"48097"},["ὀγδοήντα"]={"48661"},["οἰκήτρια"]={"48853"},["ὁλοβαθής"]={"49397"},["ὁμάγαθος"]={"49583"},["ὁμαδιάζω"]={"49590"},["περικύπτω"]={"55888"},["περιπόνως"]={"56134"},["περιωπεύω"]={"56563"},["περσεϊνός"]={"56603"},["πιναρωτός"]={"57058"},["προϊστάνω"]={"60791"},["προσεπιγλισχραίνω"]={"62208"},["ἀζωοδόχητος"]={"1257"},["ἀκατασχεσία"]={"1924"},["ἀκεσμοφόρος"]={"1975"},["ἀνδρόμορφος"]={"4438"},["αὐγουστικός"]={"10347"},["αὐτόπλεκτος"]={"10850"},["Ἀφαντόπολις"]={"11059"},["δενδρύλλιον"]={"15434"},["ἐγκωμιαστός"]={"19841"},["ἐμβιώτευσις"]={"21980"},["ἐμβρόντησις"]={"22016"},["ἐντρυφητέον"]={"23699"},["ἐξαριστερών"]={"24152"},["ἐριθευτικός"]={"27156"},["ἰνστρουμεύω"]={"32266"},["καμηλαύχιον"]={"34151"},["κολακόλαλος"]={"38126"},["νεομηνιακός"]={"47412"},["ἀντιστρεπτικός"]={"6196"},["ἀρτοφυλακεῖον"]={"9326"},["εὐπαροίστρωτος"]={"28404"},["εὐπροστάτευτος"]={"28512"},["θαλασσόφθαλμος"]={"30197"},["καράπα"]={"34509"},["καταστορεύομαι"]={"35930"},["κλοφός"]={"37824"},["κόλφος"]={"38222"},["κόμους"]={"38351"},["κόντος"]={"38555"},["κτόνος"]={"39877"},["μουκός"]={"46309"},["πεζοτοξοκράτης"]={"54926"},["πεντηκοντάριος"]={"55310"},["πλυνών"]={"57727"},["προδιαγιγνώσκω"]={"60219"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["doctissimus"]={"1625","1629","1868"},["populariter"]={"3783"},["amplissimus"]={"1076","3634","3663"},["an"]={"1436","1847","2246","3116"},["testamentum"]={"3368","3369","3370","3371","3372","3373","3374","3376"}} local grc_RCunliffe_lemma_to_index = { ["ἀγορήνδε"]={"94"},["ἀγκλίνας"]={"69"},["κοντός"]={"5707"},["νόσφιν"]={"6718"},["θόωκος"]={"4839"},["φολκός"]={"9483"},["κορθύω"]={"5713"}} local grc_RWoodhouse_lemma_to_headwords = { ["Οἰνόμαος"]={"oenomaus"},["εἵμαρται"]={"appoint"},["εὐγνώμων"]={"attentive","charitable","considerate","feeling","kind","thoughtful","well-intentioned","well-meaning"},["εὐσέβεια"]={"awe","conscience","conscientiousness","devotion","dutifulness","godliness","holiness","morality","piety","religion","religiousness","reverence","righteousness","sanctification","sanctity","scrupulousness","sinlessness","unworldliness","veneration"},["φαεσφόρος"]={"blazing","bright","dazzling","flashing","gleaming","radiant","shining"},["ἐντύνειν"]={"harness"},["ὀνείδεσι"]={"ply"},["ὀφθαλμία"]={"eye-disease","ophthalmia"},["γαργαλίζειν"]={"tickle"},["κινδυνεύειν"]={"danger","dare","endanger","gauntlet","hazard","imperil","jeopardy","lncur","risk","stake","venture"},["Κέκροψ"]={"cecrops"},["Μύλασα"]={"mylasa"},["Πασίων"]={"pasion"},["βραχέα"]={"shallows"},["κοντός"]={"pole","stave"},["μόχθος"]={"effort","exertion","hardship","labour","strain","striving","struggle","suffering","task","toil","trouble","work"},["ξουθός"]={"brown","russet","tawny","yellow"},["φθόνος"]={"animus","denial","disfavour","displeasure","envy","grudge","grudging","hatred","hostility","ill will","jealousy","loathing","malice","malignity","mischief","odium","offence","pique","prejudice","rancour","refusal","reluctance","repulse","revenge","spite","stint","unpopularity","venom","will"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} jga2abno59f4u43jctm0vjhz88zr45d 178508 178499 2026-10-27T06:10:01Z GinawaSaHapon 3989 178508 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1059"]={"_gratiam alicui referre (meritam, debitam) pro aliqua re_","to show gratitude (in one's acts)."},["1068"]={"_pro maleficiis beneficia reddere_","to return good for evil."},["1077"]={"_meritum praemium alicui persolvere_","to reward a man according to his deserts."},["1086"]={"_precibus aliquem fatigare_","to importune with petitions."},["1095"]={"_aliquid ab aliquo impetrare_","to gain one's point with any one."},["1149"]={"_laudibus aliquem (aliquid) in caelum ferre, efferre, tollere_","to extol, laud to the skies."},["1158"]={"_res a me probatur_","I express my approval of a thing."},["1167"]={"_fama serpit (per urbem)_","a report is spreading imperceptibly."},["1176"]={"_in ore omnium_ or _omnibus_ (_hominum_ or _hominibus_, but only _mihi, tibi_, etc.) _esse_","to be in every one's mouth."},["1185"]={"_Romam nuntiatum est, allatum est_","news reached Rome."},["1194"]={"_laudem afferre_","to confer distinction on a person; to redound to his credit."},["1239"]={"_operam (laborem, curam) in_ or _ad aliquid impendere_","to expend great labour on a thing."},["1248"]={"_labori, operae non parcere_","to spare no pains."},["1257"]={"_fugiens laboris_","lazy."},["1266"]={"_negotium suscipere_","to undertake an affair."},["1275"]={"_magnum negotium est_ c. Inf.","it is a great undertaking to..."},["1284"]={"_otio abūti_[1] or _otium ad suum usum transferre_","to use up, make full use of one's spare time."},["1293"]={"_voluptates haurire_","to take one's fill of enjoyment."},["1329"]={"_cogitatione sibi aliquid depingere_","to picture to oneself."},["1338"]={"_illud succurrit mihi_","an idea strikes me."},["1347"]={"_cogitationes in res humiles abicere_ (De Amic. 9. 32) (Opp. _alte spectare, ad altiora tendere, altum, magnificum, divinum suspicere_)","to study the commonplace."},["1356"]={"_absolutio et perfectio_ (not _summa perfectio_)","ideal perfection."},["1365"]={"_illa civitas, quam Plato finxit_","Plato's ideal republic."},["1374"]={"_ad alicuius sententiam accedere, sententiam alicuius sequi_","to adopt some one's opinion."},["1383"]={"_mea (quidem) sententia_","according to my opinion."},["1392"]={"_monstra_ or _portenta_","marvellous ideas; prodigies."},["1419"]={"_in magno errore versari_","to be in gross error, seriously misled."},["1428"]={"_errorem amputare et circumcīdere_","to banish an error, do away with a false impression."},["1437"]={"_in dubium vocare_","to throw doubt upon a thing."},["1446"]={"_sine ulla dubitatione_","without any hesitation; without the least scruple."},["1455"]={"_hoc_ (not _tantum_) _certum est_","this much is certain."},["1464"]={"_velim tibi ita persuadeas_","convince yourself of this; rest assured on this point."},["1473"]={"_a consilio deterreri aliqua re_","to be deterred from one's intention by something."},["1482"]={"_consultare_ or _deliberare (de aliqua re)_","to deliberate, consider (of individuals)."},["1491"]={"_nullo consilio, nulla ratione, temere_","without reflection; inconsiderately; rashly."},["1509"]={"_in incepto_ or _conatu perstare_","to persevere in one's resolve."},["1518"]={"_id sequor, ut_","my intention is..."},["1527"]={"_eo consilio, ea mente, ut_","with the intention of..."},["1536"]={"_memoriā tenere aliquid_","to remember a thing perfectly."},["1545"]={"_memoriter_","(1) with good memory; (2) from personal recollection."},["1554"]={"_memoriam alicuius rei repraesentare_ (opp. _memoriam alicuius rei deponere, abicere_)","to picture to oneself again."},["1563"]={"_memoriam nominis sui immortalitati tradere, mandare, commendare_","to immortalise one's name."},["1572"]={"_memoria alicuius rei obscuratur, obliteratur, evanescit_","to be forgotten, pass into oblivion."},["1581"]={"_doctrinam ad usum adiungere_","to combine theory with practice."},["1590"]={"_(rerum) imperitum esse_","to have had no experience of the world."},["1608"]={"_in litteris acquiescere_ or _conquiescere_","to find recreation in study."},["1617"]={"_primis (ut dicitur)_[3] or _primoribus labris gustare_ or _attingere litteras_","to have a superficial knowledge, a smattering of literature, of the sciences."},["1626"]={"_vir perfecte planeque eruditus_","a man of profound erudition."},["1635"]={"_a doctrina mediocriter instructum esse_","to have received only a moderate education."},["1644"]={"_penitus percipere et comprehendere aliquid_ (De Or. 1. 23. 108)","to have a thorough grasp of a subject."},["1653"]={"_sunt in illo, ut in homine Romano, multae litterae_ (De Sen. 4. 12)","for a Roman he is decidedly well educated."},["1662"]={"_mores alicuius corrigere_","to improve a person."},["1671"]={"_multum esse cum aliquo_ (Fam. 16. 21)","to enjoy close intercourse with... (of master and pupil)."},["1680"]={"_erudire aliquem artibus, litteris_ (but _erudire aliquem in iure civili, in re militari_)","to teach some one letters."},["1707"]={"_aliquid exemplis probare, comprobare, confirmare_","to quote precedents for a thing."},["1716"]={"_auctorem aliquem habere alicuius rei_","to have as authority for a thing."},["1725"]={"_exemplum (severitatis) edere in aliquo_ (Q. Fr. 1. 2. 2. 5)","to inflict an exemplary punishment on some one."},["1734"]={"_animum appellere_ or _se applicare ad philosophiam_","to apply oneself to the study of philosophy."},["1743"]={"_praecepta philosophorum (penitus) percepta habere_","to be well acquainted with the views of philosophers."},["1752"]={"_scholas habere, explicare_ (Fin. 2. 1. 1)","to give lectures."},["1761"]={"_disserendi spinae_ (Fin. 4. 28. 79)","subtleties of logic; dilemmas."},["1770"]={"_philosophia,_[3] _quae in actione versatur_","practical philosophy."},["1806"]={"_argumentum afferre_","to bring forward a proof."},["1815"]={"_loci (τόποι) argumentorum_ (De Or. 2. 162)","the points on which proofs are based; the grounds of proof."},["1824"]={"_positum est a nobis primum_ (c. Acc. c. Inf.)","we start by presupposing that..."},["1833"]={"_in nullam partem disputare_","to say nothing either for or against an argument."},["1842"]={"_in controversiam cadere_","to be at variance with."},["1851"]={"_transigere aliquid cum aliquo_","to come to an understanding with a person."},["1860"]={"_omnes (uno ore) in hac re consentiunt_","all agree on this point."},["1905"]={"_ut a fabulis ad facta veniamus_","to pass from myth to history."},["1914"]={"_domestica (externa) nosse_","to be acquainted with the history of one's own land."},["1923"]={"_Africae situm paucis exponere_","to give a brief exposition of the geography of Africa."},["1932"]={"_numeri (-orum)_","arithmetic."},["1941"]={"_artis praecepta_, or also simply _ars_","the rules of art; aesthetics."},["1950"]={"_abhorrere ab artibus_ (opp. _delectari artibus_)","to have no taste for the fine arts."},["2049"]={"_ludi apparatissimi_","sumptuous public games."},["2058"]={"_rhetor, dicendi magister_","a teacher of rhetoric."},["2067"]={"_eloquentiae laude florere_","to be a distinguished orator."},["2076"]={"_subito, ex tempore_ (opp. _ex praeparato_) _dicere_","to speak extempore."},["2085"]={"_plane, aperte dicere_","to speak openly, straightforwardly."},["2094"]={"_finem dicendi facere_","to cease speaking."},["2139"]={"_exponere aliquid_ or _de aliqua re_","to give an account of a thing (either orally or in writing)."},["2148"]={"_summo colore aliquid illustrare_","to depict a thing in lively colours."},["2157"]={"_in brevi conspectu ponere aliquid_","to make a short survey of a thing."},["2166"]={"_pluribus verbis, copiosius explicare, persequi_[6] _aliquid_","to give a full, detailed account of a thing."},["2175"]={"_in medio ponere (proponere)_","to publish, make public."},["2184"]={"_digressus, digressio, egressio_","a digression, episode."},["2193"]={"_studio alicuius rei provectus sum_","my zeal for a thing has led me too far."},["2229"]={"_id quod quaerimus (quaeritur)_","a theme, subject proposed for discussion."},["2238"]={"_ponere_","to propose, set a theme."},["2247"]={"_quaerendum esse mihi visum est_","the question has forced itself on my mind."},["2256"]={"_haec iocatus sum, per iocum dixi_","I said it in jest."},["2265"]={"_dicta dicere in aliquem_","to make jokes on a person."},["2274"]={"_serio dicere_ (Plaut. Bacch. 1. 1. 42)","to say in earnest..."},["2283"]={"_eiusdem linguae societate coniunctum esse cum aliquo_ (De Or. 3. 59. 223)","to be united by having a common language."},["2292"]={"_incorrupta latini sermonis integritas_[1] (Brut. 35. 132)","pure, correct Latin."},["2319"]={"_ambitus, circuitus, comprehensio, continuatio (verborum, orationis)_, also simply _periodus_","the period."},["2328"]={"_verbo, nomine; re, re quidem vera_","nominally; really."},["2337"]={"_ne verbum_ (without _unum_) _quidem de aliquo facere_","to say not a syllable about a person."},["2346"]={"_verbum prorsus nullum intellegere_","not to understand a single word."},["2355"]={"_nomen amicitiae_ (or simply _amicitia_) _dicitur ab amando_","the word _amicitia_ comes from _amare_."},["2364"]={"_quid est virtus?_","what do we mean by 'virtue'?"},["2373"]={"_hoc vocabulum generis neutri_ (not _neutrius_) _est_)","this word is neuter."},["2382"]={"_dissimulatio_ (Off. 1. 30. 108)","irony."},["2391"]={"_proverbium vetustate_ or _sermone tritum_ (_vid._ sect. II. 3, note _tritus..._)","an old proverb which every one knows."},["2409"]={"_librum conficere, componere_ (De Sen. 1. 2)","gumawa, magbigkis ng aklat"},["2418"]={"_exstat liber_ (notice the order of the words)","the book is still extant."},["2427"]={"_libro scriptor complexus est aliquid_","the book contains something... (not _continet aliquid_)."},["2436"]={"_liber accurate, diligenter scriptus_","a carefully written book."},["2445"]={"_Platonem legere et cognoscere_","to study Plato."},["2454"]={"_mendum (scripturae)_ (Fam. 6. 7. 1)","a clerical error, copyist's mistake."},["2463"]={"_epistularum commercium_","correspondence."},["2472"]={"_litteras recitare_ (Att. 8. 9. 2)","to read a letter aloud (in public)."},["2481"]={"_animos tentare_ (Cluent. 63. 176)","to try to divine a person's disposition."},["2490"]={"_alicuius mentem turbare, conturbare, perturbare_","to upset a person."},["2508"]={"_tuam vicem_[3] _doleo_","I am sorry for you."},["2517"]={"_dolor infixus animo haeret_ (Phil. 2. 26)","grief has struck deep into his soul."},["2526"]={"_in aegritudine, sollicitudine esse_","to be vexed, mortified, anxious."},["2535"]={"_aegritudinem alicuius elevare_","to comfort another in his trouble."},["2544"]={"_in sordibus luctuque iacēre_","to be in great trouble, affliction."},["2553"]={"_timor aliquem occupat_ (B. G. 1. 39)","fear comes upon some one."},["2562"]={"_respirandi spatium dare_","to give time for recovery."},["2571"]={"_bonum animum habere_","to be brave, courageous."},["2580"]={"_animum alicui augere_ (B. G. 7. 70)","to increase a person's courage."},["2607"]={"_de gradu deici, ut dicitur_[1]","to lose one's composure; to be disconcerted."},["2616"]={"_desperare_[3] _suis rebus_","to despair of one's position."},["2625"]={"_bene, optime (meliora) sperare de aliquo_ (Nep. Milt. 1. 1)","to hope well of a person."},["2634"]={"_spes affulget_ (Liv. 27. 28)","a ray of hope shines on us."},["2643"]={"_spes me frustratur_","hope has played me false."},["2652"]={"_praeter spem, exspectationem_","contrary to expectation."},["2661"]={"_misericordiam alicuius concitare_","to excite some one's pity."},["2670"]={"_omnem humanitatem ex animo exstirpare_ (Amic. 13. 48)","to stifle, repress all humane sentiments in one's mind."},["2706"]={"_ardor animi resēdit, consedit_","his enthusiasm has abated, cooled down."},["2715"]={"_fiducia sui_ (Liv. 25. 37)","self-confidence."},["2724"]={"_fide data et accepta_ (Sall. Iug. 81. 1)","having exchanged pledges, promises."},["2733"]={"_fidem persolvere_","to fulfil a promise."},["2742"]={"_sponsionem facere, sponsorem esse pro aliquo_","to be security for some one."},["2751"]={"_suspicionem a se removere, depellere, propulsare_ (Verr. 3. 60. 140)","to clear oneself of a suspicion."},["2760"]={"_odio, invidiae esse alicui_","to be hated by some one."},["2805"]={"_furore inflammari, incendi_","to become furious."},["2814"]={"_virtutem sequi, virtutis studiosum esse_","to strive to attain virtue."},["2823"]={"_a parentibus degenerare_","to degenerate (from one's ancestors)."},["2832"]={"_vitiis, sceleribus contaminari_ or _se contaminare_ (Off. 3. 8. 37)","to be tainted with vice."},["2841"]={"_scelere se devincire, se obstringere, astringi_","to commit a crime and so make oneself liable to the consequences of it."},["2850"]={"_aliquem cupiditate inflammare_","to rouse a person's interest, cupidity."},["2904"]={"_subsidere in insidiis_ (Mil. 19. 49)","to place oneself in ambush."},["2913"]={"_in speciem_","apparently; to look at."},["2922"]={"_dolis et fallaciis_ (Sall. Cat. 11. 2)","by the aid of fraud and lies."},["2931"]={"_omnibus artibus aliquem ludificari, eludere_","to fool a person thoroughly."},["2940"]={"_ab officio discedere_","to neglect one's duty."},["3039"]={"_aliquem in deorum numero referre_","to consider as a god."},["3048"]={"_religionem ex animis extrahere_ (N. D. 1. 43. 121)","to banish devout sentiment from the minds of others."},["3057"]={"_novas religiones instituere_","to introduce a new religion, a new cult."},["3066"]={"_iusiurandum (religionem) servare, conservare_","to keep one's oath."},["3075"]={"_impietas_","unbelief."},["3084"]={"_precari deum, deos_","to pray to God."},["3093"]={"_contestari deos hominesque_","to call gods and men to witness."},["3129"]={"_prodigia procurare_[1] (Liv. 22. 1)","to avert by expiatory sacrifices the effect of ominous portents."},["3138"]={"_faustis ominibus_","with favourable omens."},["3147"]={"_domus rimas agit_","the house walls are beginning to crack."},["3156"]={"_in publico_","in the streets."},["3165"]={"_fores obserare_","to bolt the door."},["3174"]={"_diligentem, frugi esse_","to be economical."},["3183"]={"_evertere aliquem bonis, fortunis patriis_","to drive a person out of house and home."},["3192"]={"_multitudinem in agris collocare_","to settle a large number of people in a country."},["3219"]={"_alicui bibere ministrare_","to serve some one with drink."},["3228"]={"_res ad victum cultumque necessariae_","things indispensable to a life of comfort."},["3237"]={"_non habeo, qui (unde) vivam_","I have no means, no livelihood."},["3246"]={"_delicate ac molliter vivere_","to live a luxurious and effeminate life."},["3255"]={"_mensae exstructae_","a table bountifully spread."},["3264"]={"_adhibere aliquem cenae_ or _ad cenam, convivio_ or _in convivium_","to welcome some one to one's table."},["3273"]={"_hospitio aliquem accipere_ or _excipere (domum ad se)_","to welcome a man as a guest in one's house."},["3282"]={"_aliquem socium admittere_","to admit a person into one's society."},["3291"]={"_se dare in consuetudinem alicuius_","to devote oneself to a person's society."},["3309"]={"_sermonem habere cum aliquo de aliqua re_ (De Am. 1. 3)","to converse, talk with a person on a subject."},["3318"]={"_sui potestatem facere, praebere alicui_","to give audience to some one."},["3327"]={"_sermo cotidianus_, or simply _sermo_","conversational language."},["3336"]={"_quid agitur? quid fit?_","what is going on? how are you getting on?"},["3345"]={"_te valere_[3] _iubeo_","I bid you good-bye, take my leave."},["3354"]={"_ducere uxorem_","to marry (of the man)."},["3363"]={"_nuntium remittere alicui_ (De Or. 1. 40)","to separate, be divorced (used of man or woman)."},["3372"]={"_testamentum subicere, supponere_","to produce a false will."},["3381"]={"_exheredari a patre_","to be disinherited."},["3390"]={"_consuetudinem suam tenere, retinere,[TR1] servare_","to keep up a usage."},["3408"]={"_negotii bene gerentes_ (Quint. 19. 62)","good men of business."},["3417"]={"_quaestui aliquid habere_ (Off. 2. 3. 13)","to make a profit out of something."},["3426"]={"_pecunia exigua_ or _tenuis_","little money."},["3435"]={"_pecuniam alicui debere_","to owe some one money."},["3444"]={"_non solvendo_[3] _esse_ (Phil. 2. 2. 4)","to be bankrupt."},["3453"]={"_argentariam dissolvere_ (Caecin. 4. 11)","to close one's bank, give up banking."},["3462"]={"_inita subductaque ratione aliquid facere_","to do something after careful calculation."},["3471"]={"_rationem ab aliquo reptere de aliqua re_ (Cluent. 37. 104)","to demand an account, an audit of a matter."},["3480"]={"_quadrantes usurae_","3 per cent (a quarter of centesima)."},["3507"]={"_incidere in aes alienum_","to get into debt."},["3516"]={"_ex aere alieno exire_","to get out of debt."},["3525"]={"_turrim excitare, erigere, facere_","to build a tower."},["3534"]={"_agros fertiles deserere_","to leave fertile ground untilled."},["3543"]={"_odores, qui efflantur e floribus_","the perfume exhaled by flowers."},["3552"]={"_arbores caedere_","to fell trees."},["3561"]={"_rem pecuariam facere, exercere_ (cf. Varr R. R. 2. 1)","to rear stock."},["3570"]={"_instituta et leges_","the constitution."},["3606"]={"_rei publicae rationibus_ or simply _rei publicae consulere_","to further the public interests."},["3615"]={"_viri rerum civilium, rei publicae gerendae periti_ or _viri in re publica prudentes_","statesmen."},["3624"]={"_rei publicae muneribus orbatus_","banished from public life."},["3633"]={"_homo novus_[1]","a parvenu (a man no member of whose family has held curule office)."},["3642"]={"_summi (et) infimi_ (Rep. 1. 34. 53)","high and low."},["3651"]={"_infima fortuna_ or _condicio servorum_","a degraded, servile condition."},["3660"]={"_aliquem gradu movere, depellere_ or _de gradu (statu) deicere_","to overthrow a person (cf. sect. IX. 6)."},["3705"]={"_sententia_ or _voluntas legis_","the spirit of the law."},["3714"]={"_acta rescindere, dissolvere_ (Phil. 13. 3. 5)","to declare a magistrate's decisions null and void."},["3723"]={"_gratiosum esse_ (opp. _invisum esse_)","to be popular, influential."},["3732"]={"_invidia_","unpopularity."},["3741"]={"_certamen partium_","party-strife."},["3750"]={"_nullius_ or _neutrius_ (of two) _partis esse_","to be neutral."},["3804"]={"_omnia turbare ac miscere_","to cause universal disorder."},["3813"]={"_plebem continere_","to hold the people in one's power, in check."},["3822"]={"_de, e civitate aliquem eicere_","to banish a person, send him into exile."},["3831"]={"_exsulare_ (Div. 2. 24. 52)","to live in exile."},["3840"]={"_imperium tenere (in aliquem)_","to have power over some one."},["3903"]={"_colōnos mittere_ (Div. 1. 1. 3)","to send out colonists."},["3912"]={"_provinciam obire_","to visit, traverse a province."},["3921"]={"_omnes centurias ferre_ or _omnium suffragiis, cunctis centuriis creari_","to be elected unanimously"},["3930"]={"_prorogare alicui imperium (in annum)_","to prolong a person's command."},["4029"]={"_aequo iure vivere cum aliquo_","to live with some one on an equal footing."},["4038"]={"_ius praecipuum, beneficium, donum_, also _immunitas_[2] c. Gen.","prerogative, privilege."},["4047"]={"_deprehendere aliquem in manifesto scelere_","to take a person in the act."},["4056"]={"_testem prodire (in aliquem)_","to appear as witness against a person."},["4065"]={"_causa privata_","a civil case."},["4074"]={"_patronus_[1] _(causae)_ (De Or. 2. 69)","counsel; advocate."},["4083"]={"_causam_ or _litem amittere, perdere_","to lose one's case."},["4092"]={"_iudices reicere_ (Verr. 3. 11. 28)","to challenge, reject jurymen."},["4119"]={"_culpam alicui attribuere, assignare_","to attribute the fault to some one."},["4128"]={"_animadvertere in aliquem_","to punish some one."},["4137"]={"_poenas (graves) dare alicui_","to be (heavily) punished by some one."},["4146"]={"_decem milibus aeris damnari_","to be fined 10,000 asses."},["4155"]={"_supplicium sumere de aliquo_","to execute the death-sentence on a person."},["4164"]={"_mortem_[2] _deprecari_ (B. G. 7. 40. 6)","to beg for life."},["4173"]={"_ad nomen non respondere_ (Liv. 7. 4)","to fail to answer one's name."},["4182"]={"_evocati, voluntarii_ (B. G. 5. 56)","the volunteers."},["4191"]={"_parare exercitum, copias_","to equip an army, troops."},["4209"]={"_emeritis stipendiis_ (Sall. Iug. 84. 2)","after having completed one's service."},["4218"]={"_intercludere, prohibere hostes commeatu_","to cut off all supplies of the enemy."},["4227"]={"_res bene gesta_","a success; a glorious feat of arms."},["4236"]={"_modestia_[2] (opp. _immodestia_)","discipline (insubordination)."},["4245"]={"_ab armis discedere_ (Phil. 11. 33)","to lay down arms."},["4254"]={"_eminus hastis, comminus gladiis uti_","to use javelins at a distance, swords at close quarters."},["4263"]={"_bellum parare_","to make preparations for war."},["4272"]={"_bellum moliri_","to meditate war."},["4281"]={"_bellum coniungere_ (Imp. Pomp. 9. 26)","to wage war in conjunction with some one."},["4290"]={"_bello persequi aliquem, lacessere_","to harass with war."},["4308"]={"_raptim agmen ducere_","to lead the army with forced marches."},["4317"]={"_signa convertere_ (B. G. 1. 25)","to deviate, change the direction."},["4326"]={"_ordines turbare, perrumpere_","to break the ranks."},["4335"]={"_gradum sistere_","to halt."},["4344"]={"_praesidia, custodias disponere_","to station posts, pickets, at intervals."},["4353"]={"_castra munire vallo (aggere)_","to fortify the camp with a rampart."},["4362"]={"_custodias agere in vallo_","to keep watch on the rampart."},["4371"]={"_capere equos_","to capture horses."},["4380"]={"_consilium habere, convocare_","to hold a council of war."},["4407"]={"_munitiones perrumpere_","to break through the lines (and relieve a town)."},["4416"]={"_in oppidum irruptionem facere_","to break into the town."},["4425"]={"_salutem petere a victore_","to beg for mercy from the conqueror."},["4434"]={"_potestatem sui facere (alicui)_ (cf. sect. XII. 9, note _audientia..._)","to accept battle."},["4443"]={"_vexillum proponere_ (Liv. 22. 3)","to fix the ensign on the general's tent (as a signal to commence the engagement)."},["4452"]={"_media acies_","the centre."},["4461"]={"_proelium facere_","to give battle."},["4470"]={"_proelium renovare, redintegrare_","to begin the fight again."},["4506"]={"_gladio comminus_ (opp. _eminus_) _rem gerere_","to fight with swords at close quarters."},["4515"]={"_in latus hostium incurrere_","to fall upon the enemy's flank."},["4524"]={"_phalangem perfringere_","to break through the phalanx."},["4533"]={"_repellere, propulsare hostem_","to repulse an attack."},["4542"]={"_in fugam dare, conicere hostem_","to put the enemy to flight."},["4551"]={"_fugae se mandare_ (B. G. 2. 24)","to take to flight."},["4560"]={"_ex (in) fuga dissipati_ or _dispersi_ (B. G. 2. 24)","soldiers routed and dispersed."},["4605"]={"_victoriam_ or _de victoria gratulari alicui_","to congratulate a person on his victory."},["4614"]={"_agere cum aliquo de pace_","to treat with some one about peace."},["4623"]={"_summa pax_","deep peace."},["4632"]={"_foedus frangere, rumpere, violare_","to violate a treaty, terms of alliance."},["4641"]={"_populum perdomare, subigere_","to subjugate a nation."},["4650"]={"_aliquem ad officium_ (cf. sect. X. 7, note _officium..._) _reducere_ (Nep. Dat. 2. 3)","to reduce a people to their former obedience."},["4704"]={"_procella (tempestas) aliquem ex alto ad ignotas terras (oras) defert_","the storm drives some one on an unknown coast."},["4713"]={"_ad ancoras deligari_","to ride at anchor."},["4722"]={"_navis praetoria_ (Liv. 21. 49)","the admiral's ship; the flagship."},["4731"]={"_navem capere, intercipere, deprehendere_","to capture a boat."},["4740"]={"_ne dicam_","not to say... (used in avoiding a stronger expression)."},["4803"]={"_hoc est luce (sole ipso) clarius_","this is as clear as daylight."},["4812"]={"_si quaeris, si verum quaerimus_","to put it exactly."},["4821"]={"_audio, fateor_","I admit it, say on."},["4830"]={"_rem acu tetigisti_","you have hit the nail on the head."}} local grc_RWoodhouse_lemma_to_infinitives = { ["πρυτανεύω"]={"πρυτανεύειν","πρυτανεύεσθαι","πρυτανεῦσαι"},["τυροπωλέω"]={"τυροπωλῆσαι"},["δουλόω"]={"δεδουλῶσθαι","δουλοῦσθαι","δουλώσασθαι","δουλώσεσθαι","δουλωθῆναι"},["εϝερρο"]={"ευερρερε","εϝερρερε","εϝερρι"},["προδιαγιγνώσκω"]={"προδιαγνῶναι"},["ϝερεορ"]={"υερερι"}} local la_NLW_headwords_to_path = { ["coequestris"]={"2/021462"},["conuexitudo"]={"1/015181"},["corruscator"]={"0/009224"},["doctorculus"]={"0/004804"},["festomastix"]={"2/011282"},["flatulentus"]={"1/011865"},["flexuositas"]={"2/007598"},["frontiuagus"]={"0/008328"},["futuridicus"]={"3/003907"},["inassecutus"]={"3/008571"},["inclaustrum"]={"3/011163"},["inerticulus"]={"2/013194"},["infortitudo"]={"1/015197"},["insaturitas"]={"1/009261"},["intorticium"]={"2/014702"},["monopetalus"]={"1/018625"},["perausculto"]={"0/020780"},["perliquidus"]={"2/021182"},["perstudiose"]={"2/017674"},["pertrepidus"]={"2/008842"},["populariter"]={"3/006607"},["prolongator"]={"2/012218"},["redemptiuus"]={"3/016995"},["responsatio"]={"0/006728"},["semiadustus"]={"2/004114"},["semicrispus"]={"0/012676"},["seminatiuus"]={"1/004669"},["singularizo"]={"1/009501"},["subinfirmus"]={"2/009054"},["subplumbeus"]={"0/019392"},["subsordidus"]={"0/009336"},["suffuraneus"]={"2/020178"},["superductio"]={"1/002481"},["supermelior"]={"2/002126"},["sustentamen"]={"0/008088"},["sustinentia"]={"2/017834"},["triformiter"]={"0/019532"},["tripartilis"]={"0/013080"},["uerbunculum"]={"0/013036"},["uituperalis"]={"3/020687"}} local grc_RLBG_lemma_to_index = { ["ἀέθλευμα"]={"1064"},["ἀνάσκελα"]={"4151"},["βραχύωρος"]={"13211"},["βρυχησμός"]={"13425"},["γεφύρωσις"]={"14006"},["διαχρυσόω"]={"16820"},["ἔμποινος"]={"22318"},["ἐξεβραία"]={"24236"},["λαθριδίῃ"]={"40589"},["μυρταΐτης"]={"46899"},["νυμφαῖοι"]={"48097"},["ὀγδοήντα"]={"48661"},["οἰκήτρια"]={"48853"},["ὁλοβαθής"]={"49397"},["ὁμάγαθος"]={"49583"},["ὁμαδιάζω"]={"49590"},["περικύπτω"]={"55888"},["περιπόνως"]={"56134"},["περιωπεύω"]={"56563"},["περσεϊνός"]={"56603"},["πιναρωτός"]={"57058"},["προϊστάνω"]={"60791"},["προσεπιγλισχραίνω"]={"62208"},["ἀζωοδόχητος"]={"1257"},["ἀκατασχεσία"]={"1924"},["ἀκεσμοφόρος"]={"1975"},["ἀνδρόμορφος"]={"4438"},["αὐγουστικός"]={"10347"},["αὐτόπλεκτος"]={"10850"},["Ἀφαντόπολις"]={"11059"},["δενδρύλλιον"]={"15434"},["ἐγκωμιαστός"]={"19841"},["ἐμβιώτευσις"]={"21980"},["ἐμβρόντησις"]={"22016"},["ἐντρυφητέον"]={"23699"},["ἐξαριστερών"]={"24152"},["ἐριθευτικός"]={"27156"},["ἰνστρουμεύω"]={"32266"},["καμηλαύχιον"]={"34151"},["κολακόλαλος"]={"38126"},["νεομηνιακός"]={"47412"},["ἀντιστρεπτικός"]={"6196"},["ἀρτοφυλακεῖον"]={"9326"},["εὐπαροίστρωτος"]={"28404"},["εὐπροστάτευτος"]={"28512"},["θαλασσόφθαλμος"]={"30197"},["καράπα"]={"34509"},["καταστορεύομαι"]={"35930"},["κλοφός"]={"37824"},["κόλφος"]={"38222"},["κόμους"]={"38351"},["κόντος"]={"38555"},["κτόνος"]={"39877"},["μουκός"]={"46309"},["πεζοτοξοκράτης"]={"54926"},["πεντηκοντάριος"]={"55310"},["πλυνών"]={"57727"},["προδιαγιγνώσκω"]={"60219"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["doctissimus"]={"1625","1629","1868"},["populariter"]={"3783"},["amplissimus"]={"1076","3634","3663"},["an"]={"1436","1847","2246","3116"},["testamentum"]={"3368","3369","3370","3371","3372","3373","3374","3376"}} local grc_RCunliffe_lemma_to_index = { ["ἀγορήνδε"]={"94"},["ἀγκλίνας"]={"69"},["κοντός"]={"5707"},["νόσφιν"]={"6718"},["θόωκος"]={"4839"},["φολκός"]={"9483"},["κορθύω"]={"5713"}} local grc_RWoodhouse_lemma_to_headwords = { ["Οἰνόμαος"]={"oenomaus"},["εἵμαρται"]={"appoint"},["εὐγνώμων"]={"attentive","charitable","considerate","feeling","kind","thoughtful","well-intentioned","well-meaning"},["εὐσέβεια"]={"awe","conscience","conscientiousness","devotion","dutifulness","godliness","holiness","morality","piety","religion","religiousness","reverence","righteousness","sanctification","sanctity","scrupulousness","sinlessness","unworldliness","veneration"},["φαεσφόρος"]={"blazing","bright","dazzling","flashing","gleaming","radiant","shining"},["ἐντύνειν"]={"harness"},["ὀνείδεσι"]={"ply"},["ὀφθαλμία"]={"eye-disease","ophthalmia"},["γαργαλίζειν"]={"tickle"},["κινδυνεύειν"]={"danger","dare","endanger","gauntlet","hazard","imperil","jeopardy","lncur","risk","stake","venture"},["Κέκροψ"]={"cecrops"},["Μύλασα"]={"mylasa"},["Πασίων"]={"pasion"},["βραχέα"]={"shallows"},["κοντός"]={"pole","stave"},["μόχθος"]={"effort","exertion","hardship","labour","strain","striving","struggle","suffering","task","toil","trouble","work"},["ξουθός"]={"brown","russet","tawny","yellow"},["φθόνος"]={"animus","denial","disfavour","displeasure","envy","grudge","grudging","hatred","hostility","ill will","jealousy","loathing","malice","malignity","mischief","odium","offence","pique","prejudice","rancour","refusal","reluctance","repulse","revenge","spite","stint","unpopularity","venom","will"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} 9a9xfat52d3bvdpwvn0g4m0ghochp2p Module:data tables/dataM200 828 38990 178500 2026-10-27T05:49:59Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1007"]={"_rationibus alicuius prospicere_ or _consulere_ (opp. _officere, obstare, adversari_)","to look after, guard a person's interests, welfare."},["1016"]={"_damnum_ (opp. _lucrum_) _facere_","to suffer loss, harm, damage.[2]"},["1025"]={"_damnum compensare cum aliqua re_","to balance a loss by anything."},["1034"]={"_in gratia esse apud aliquem_","to be popular with; to stand well with a person."},["1...' 178500 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1007"]={"_rationibus alicuius prospicere_ or _consulere_ (opp. _officere, obstare, adversari_)","to look after, guard a person's interests, welfare."},["1016"]={"_damnum_ (opp. _lucrum_) _facere_","to suffer loss, harm, damage.[2]"},["1025"]={"_damnum compensare cum aliqua re_","to balance a loss by anything."},["1034"]={"_in gratia esse apud aliquem_","to be popular with; to stand well with a person."},["1043"]={"_alicui morem gerere, obsequi_","to comply with a person's wishes; to humour."},["1052"]={"_beneficio aliquem afficere, ornare_","to do any one a service or kindness."},["1061"]={"_grates agere (dis immortalibus)_","to give thanks to heaven."},["1070"]={"_male mereri de aliquo_","to deserve ill of a person; to treat badly."},["1106"]={"_amicitiam colere_","to keep up, foster a connection."},["1115"]={"_ad alicuius amicitiam se conferre, se applicare_","to gain some one's friendship; to become intimate with."},["1124"]={"_aequi iniqui_","friend and foe."},["1133"]={"_multum auctoritate valere, posse apud aliquem_","to have great influence with a person; to have considerable weight."},["1142"]={"_aliquid alienum (a) dignitate sua_ or merely _a se ducere_","to consider a thing beneath one's dignity."},["1151"]={"_aliquem beatum praedicare_","to consider happy."},["1160"]={"_vituperationem subire_","to suffer reproof; to be criticised, blamed."},["1205"]={"_stimulis gloriae concitari_","to be spurred on by ambition."},["1214"]={"_bona, mala existimatio est de aliquo_","to have a good or bad reputation, be spoken well, ill of."},["1223"]={"_aliquem honore afficere, augere, ornare, prosequi_ (_vid._ sect. VI. 11., note _Prosequi..._)","to honour, show respect for, a person."},["1232"]={"_vitae splendori(em) maculas(is) aspergere_","to sully one's fair fame."},["1241"]={"_studium, industriam_ (not _diligentiam_) _collocare, ponere in aliqua re_","to apply oneself zealously, diligently to a thing."},["1250"]={"_nullum tempus a labore intermittere_","not to leave off work for an instant."},["1304"]={"_animum_ or simply _se remittere_","to indulge oneself."},["1313"]={"_ingenio valere_","to be talented, gifted."},["1322"]={"_sanae mentis esse_","to be of sound mind."},["1331"]={"_ingenii vis_ or _celeritas_","vivid, lively imagination."},["1340"]={"_aliquid animo meo obversatur_ (cf. sect. III, s. v. _oculi_)","a vague notion presents itself to my mind."},["1403"]={"_veritatis amans, diligens, studiosus_","truthful; veracious."},["1412"]={"_haec speciosiora quam veriora sunt_","this is more plausible than true."},["1421"]={"_erroribus implicari_ (Tusc. 4. 27. 58)","to fall into error."},["1430"]={"_errorem deponere, corrigere_","to amend, correct one's mistake."},["1502"]={"_stat mihi sententia_ (Liv. 21. 30.)","I am firmly resolved."},["1511"]={"_incepto_ or _conatu desistere_","to give up one's project."},["1520"]={"_res eo spectat, ut_","the matter tends towards..., has this object.[1]"},["1601"]={"_litteras adamasse_ (only in perf. and plup.)","to be an enthusiastic devotee of letters."},["1610"]={"_omne (otiosum) tempus in litteris consumere_","to devote all one's leisure moments to study."},["1700"]={"_exemplum clarum, praeclarum_","a good,[1] brilliant example; a striking example."},["2006"]={"_fabulam docere_ (διδάσκειν) (of the writer) (opp. _fabulam discere_","to study a piece, of the actor); to get a piece played, rehearse it."},["2015"]={"_familia, grex, caterva histrionum_","a theatrical company."},["2024"]={"_fabulam exigere_ (Ter. Andr. Pol.)","to hiss a play."},["2033"]={"_caterva, chorus_","the Chorus in Tragedy."},["2042"]={"_munus gladiatorium edere, dare_ (or simply _munus edere, dare_)","to give a gladiatorial show."},["2051"]={"_Olympia vincere_ (Ολύμπια νικαν)","to win a prize at the Olympian games."},["2060"]={"_natum, factum esse ad dicendum_","to be a born orator."},["2105"]={"_genus dicendi grave_ or _grande, medium, tenue_[2] (cf. Or. 5. 20; 6. 21)","elevated, moderate, plain style."},["2114"]={"_tragoediae_","tragic pathos."},["2123"]={"_oratio pura, pura et emendata_","pure, correct language."},["2132"]={"_sententias (verbis) explicare, aperire_","to explain one's sentiments."},["2141"]={"_perpetuitas verborum_","the connection."},["2150"]={"_oculis_ or _sub oculos, sub aspectum subicere aliquid_","to represent a thing vividly."},["2204"]={"_interpellare aliquem (dicentem)_","to interrupt."},["2213"]={"_nulla vox est ab eo audita_","no sound passed his lips."},["2222"]={"_res componere ac digerere_","to arrange and divide the subject-matter."},["2231"]={"_a proposito aberrare, declinare, deflectere, digredi, egredi_","to digress from the point at issue."},["2240"]={"_ponere iubere, qua de re quis audire velit_ (Fin. 2. 1. 1)","to let those present fix any subject they like for discussion."},["2303"]={"_aliquid (graeca) latine reddere_ or _sermone latino interpretari_","to render something into Latin."},["2312"]={"_leges dicendi_","the rules of speech, grammar."},["2321"]={"_adiungi, addi coniunctivo_ (Marc. Cap. 3. 83)","to be used with the conjunctive mood."},["2330"]={"_verbis alicuius_, e.g. _salutare_ (Liv. 9. 36)","in some one's name; on some one's behalf (not _nomine alicuius_)."},["2402"]={"_litteris mandare_ or _consignare aliquid_ (Acad. 2. 1. 2)","to put down in writing."},["2411"]={"_librum evolvere, volvere_","to open a book."},["2420"]={"_liber deperditus_","a book which has been entirely lost sight of."},["2501"]={"_effusa_[2] _laetitia_","a transport of joy."},["2510"]={"_dolorem capere (percipere) ex aliqua re_","to be vexed about a thing."},["2600"]={"_aequo (aequissimo) animo ferre aliquid_","to endure a thing with (the greatest) sang-froid."},["3005"]={"_mores in dies magis labuntur_ (also with _ad_, e.g. _ad mollitiem_)","immorality is daily gaining ground."},["3014"]={"_omnia temere agere, nullo iudicio uti_","to have no principles."},["3023"]={"_dei propitii_ (opp. _irati_)","the favour of heaven."},["3032"]={"_sacra, res divinae, religiones, caerimoniae_","ritual; ceremonial."},["3041"]={"_alicui divinos honores tribuere, habere_","to pay divine honours to some one."},["3050"]={"_religionem labefactare_ (_vid._ sect. V. 7, note _In Latin metaphor..._)","to shake the foundations of religion."},["3104"]={"_sacra, sacrificium facere (ἱερὰ ῥέζειν), sacrificare_","to sacrifice."},["3113"]={"_pro victimis homines immolare_","to sacrifice human victims."},["3122"]={"_oraculum consulere_","to consult an oracle."},["3131"]={"_augurium agere,_[2] _auspicari_ (N. D. 2. 4. 11)","to take the auspices, observe the flight of birds."},["3140"]={"_domus necessariis rebus instructa_","a comfortably-furnished house."},["3203"]={"_togam virilem (puram) sumere_","to assume the _toga virilis_."},["3212"]={"_ieiunium servare_","to fast."},["3221"]={"_bene tibi_ or _te!_","your health!"},["3230"]={"_omnes ad vitam copias suppeditare alicui_","to provide some one with a livelihood."},["3302"]={"_in eum sermonem_[2] _incidere, qui tum fere multis erat in ore_","to talk of a subject which was then the common topic of conversation."},["3311"]={"_sermo inductus a tali exordio_","the conversation began in this way."},["3320"]={"_conveniendi aditum_[3] _dare alicui_","to give audience to some one."},["3401"]={"_ut solet, ut fieri solet_","as usually happens."},["3410"]={"_negotium (rem) conficere, absolvere_","to settle, finish a transaction."},["3500"]={"_fides tota Italia est angusta_","credit is low throughout Italy."},["4004"]={"_dicendi mora diem extrahere, eximere, tollere_","to pass the whole day in discussion."},["4013"]={"_(ex) iure, lege agere cum aliquo_","to go to law with a person."},["4022"]={"_quaestiones perpetuae_ (Brut. 27. 106)","the standing commissions of inquiry."},["4031"]={"_iustitium remittere_","to re-open the courts."},["4040"]={"_quaerere aliquid_ or _de aliqua re_","to hold an inquiry into a matter."},["4103"]={"_accusare aliquem inter sicarios_ (Rosc. Am. 32. 90)","to accuse a person of assassination."},["4112"]={"_mea culpa est_","it is my fault."},["4121"]={"_culpam committere, contrahere_","to commit some blameworthy action."},["4130"]={"_ulcisci aliquem (pro aliqua re)_","to punish some one."},["4202"]={"_qui magnum in castris usum habent_","veterans; experienced troops."},["4211"]={"_rude donatum esse_[2] (Phil. 2. 29)","to retire from service."},["4220"]={"_praeficere aliquem bello gerendo_","to charge some one with the conduct of a war."},["4301"]={"_signa_[1] _ferre, tollere_","to begin the march, break up the camp."},["4310"]={"_loca, regiones, loci naturam explorare_","to reconnoitre the ground."},["4400"]={"_oppidum tormentis verberare_","to rain missiles on a town, bombard it."}} local grc_RWoodhouse_lemma_to_infinitives = { ["καταλούομαι"]={"κάλλων"},["Λυδίζω"]={"λυδίζειν"},["βλώσκω"]={"ἀντιμολεῖν","ἀποβλώσκειν","βλώσκειν","μολεῖν","μολεῖσθαι"},["εχξυσο"]={"εχξυσαρε","εχξυσαρι","εχξυσασσε","εχξυσαϝισσε"},["προσπίτνω"]={"προσπεπτωκέναι","προσπεσεῖν","προσπεσεῖσθαι","προσπίπτειν","προσπίτνειν"},["προσχάσκω"]={"προσκεχηνέναι"},["ὑμεναιόω"]={"ὑμεναιοῦσθαι"}} local la_NLW_headwords_to_path = { ["alimentiuus"]={"0/010308"},["arithmantus"]={"2/002374"},["armigerulus"]={"3/013235"},["assassinium"]={"3/014031"},["auizamentum"]={"2/000138"},["cauteriolus"]={"2/017710"},["centuriator"]={"0/017900"},["circumexulo"]={"0/021096"},["circumspiro"]={"2/008914"},["compulsatio"]={"2/017810"},["condormitor"]={"3/018071"},["contrapugno"]={"0/009200"},["cymbularius"]={"3/013067"},["doctorellus"]={"1/011349"},["episcopatus"]={"3/000503"},["exhumiliter"]={"3/010907"},["exsomniatio"]={"2/002610"},["fatiloquium"]={"2/019830"},["foediloquus"]={"1/012369"},["gloriositas"]={"3/007583"},["glutinatura"]={"0/011436"},["iannissarus"]={"3/002863"},["illustramen"]={"2/018134"},["imbrattatus"]={"2/021414"},["impactorius"]={"1/010701"},["indissimulo"]={"2/007002"},["inflatorius"]={"2/016898"},["interspecto"]={"3/011519"},["morticinium"]={"0/002016"},["multiciplex"]={"0/011588"},["multisciens"]={"3/019035"},["octolinguis"]={"0/015668"},["onomanticus"]={"1/011949"},["pauxillitas"]={"1/014077"},["pediculosus"]={"1/010437"},["perdiffusus"]={"1/016421"},["physionomia"]={"0/002472"},["pontigradus"]={"2/019250"},["praeluridus"]={"1/009345"},["praemonitor"]={"2/002194"},["prognauiter"]={"1/017897"},["refractulus"]={"0/006812"},["regiunculum"]={"2/003534"},["sensamentum"]={"1/020413"},["singulariso"]={"1/009501"},["stratilates"]={"1/006349"},["subsidiolum"]={"1/005653"},["subtremisco"]={"1/013569"},["suctiuncula"]={"3/003599"},["superbannum"]={"1/020521"},["supersagino"]={"2/010342"},["Teutonismus"]={"3/004431"},["thalmutista"]={"2/001722"},["theologisso"]={"1/004853"},["transductio"]={"2/001402"},["transhumano"]={"0/008468"},["ubiquetista"]={"3/008239"},["uersiuncula"]={"2/013034"},["unguiuncula"]={"3/020999"}} local grc_RLBG_lemma_to_index = { ["ἀγριόχοιρος"]={"681"},["αἰσχρώνυμος"]={"1679"},["ἀναψυκτικός"]={"4368"},["ἀντευκτικός"]={"5607"},["ἀποσύνταξις"]={"8207"},["ἀποτυροόμαι"]={"8329"},["ἀποφθειριόω"]={"8353"},["αὐτοαπλότης"]={"10579"},["βαλανηφαγία"]={"11702"},["βρενθύνομαι"]={"13229"},["ἐκσκουβίτωρ"]={"21348"},["ἐμπλαστώδης"]={"22276"},["ἐπαιτητικός"]={"24863"},["ἐπιδεσμητός"]={"25549"},["ἐπιδεύτερος"]={"25553"},["ἐπιστοιχάζω"]={"26386"},["Ἰβηροτρόφος"]={"31706"},["καλλίκλωνος"]={"33801"},["κενοδρόμημα"]={"36886"},["ματρονίκιον"]={"43497"},["μικροκομψία"]={"45386"},["μονοκάμαρος"]={"46018"},["μονοκάρδιος"]={"46020"},["ὀλιγότριχος"]={"49335"},["ὀρθοτόμησις"]={"50648"},["ὀστρειδαρέα"]={"51001"},["ποικιλείμων"]={"57950"},["ἀπηρυθριακότως"]={"7198"},["διαπορηματικός"]={"16390"},["ἑλμινθοβοτάνη"]={"21927"},["ἐμμιμνήσκομαι"]={"22085"},["καταστειρόομαι"]={"35896"},["κόγχος"]={"37926"},["κόριος"]={"38718"},["κοτζός"]={"38932"},["κυνώπη"]={"40186"},["λατινεπίσκοπος"]={"40895"},["Λίβυος"]={"41636"},["λιθομαργάρωτος"]={"41751"},["μασχαλιστήριον"]={"43431"},["μικτός"]={"45452"},["μυδρών"]={"46506"},["μώρωμα"]={"47045"},["πόλιος"]={"58130"},["πολιός"]={"58131"},["πρηξών"]={"59624"},["αἰγείρων"]={"1413"},["ἀναβιβάω"]={"3464"},["ἀναμερία"]={"3860"},["δυσοίστως"]={"18999"},["δυστέχνως"]={"19133"},["ἐκλαξεύω"]={"20944"},["ἔλεκτρον"]={"21765"},["ἔλλευκος"]={"21879"},["ἐνδημεύω"]={"22895"},["ἔνθρηνος"]={"23210"},["ἐρνόομαι"]={"27224"},["εὔκολπος"]={"28172"},["ζωροτέρως"]={"29555"},["ἰδιωτεία"]={"31840"},["καδδαρᾶς"]={"32934"},["κουρσάτωρ"]={"39184"},["παραχύτος"]={"53958"},["Παυλικῶς"]={"54793"},["περεχύτης"]={"55454"},["πλαστότης"]={"57308"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["respirandus"]={"2562"},["interregnum"]={"3809","3942"},["adulterinus"]={"3430"},["existimatio"]={"1214","1220","3730"}} local grc_RCunliffe_lemma_to_index = { ["πολιός"]={"7885"},["ὑψίκομος"]={"9352"},["βλώσκω"]={"1773"},["ἐξοφέλλω"]={"3430"},["ἑλκηθμός"]={"3061"},["εὔκυκλος"]={"4232"},["τοκεύς"]={"8979"},["ἐπιστοναχέω"]={"3799"},["ἰοχέαιρα"]={"5022"},["πόλιος"]={"7886"},["κλιτύς"]={"5646"},["λωβεύω"]={"6140"}} local grc_RWoodhouse_lemma_to_headwords = { ["τριηραρχεῖν"]={"trierarch"},["ἀντιτύπτειν"]={"strike"},["Κυρήνη"]={"cyrene"},["Νάρβων"]={"narbo"},["Τισίας"]={"tisias"},["καταισχύνεσθαι"]={"ashamed","shame"},["κλιτύς"]={"declivity","descent","down","inclination","incline","slope"},["κόγχος"]={"cockle","muscle","shell"},["λοιπός"]={"future","left","outstanding","remaining"},["μικτός"]={"blended","mingled","mixed","promiscuous"},["πολιός"]={"gray","gray-haired","hoary","white"},["τερμών"]={"bourn"},["τοκεύς"]={"parent"},["ψελλός"]={"bewildering","dark","inarticulate","incoherent","mysterious","obscure","unintelligible"},["ἐπισκοπεῖσθαι"]={"haunt"},["Αἰμύλιος"]={"aemilius"},["εἰσαγωγη"]={"conveyance"},["εὔγομφος"]={"nail","studded"},["εὔκυκλος"]={"circular","curved","round","wheeled"},["κλοπαῖος"]={"stolen"},["τρίπτυχοι"]={"three"},["φαιδρωπός"]={"animated","beaming","blithe","bright","cheerful","gay","genial","glad","gleeful","jocund","joyful","lively","merry","radiant","smiling","sprightly","unclouded"},["ἀνανδρία"]={"cowardice","effeminacy","faint-heartedness","timidity","unmanliness"},["Ἀκύλλιος"]={"aquilius"},["ἔκδρομος"]={"skirmisher"},["Ἐνδυμίων"]={"endymion"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} oydju5tpy1rlpdoqoqjsitn1x8rls3i Module:data tables/dataM208 828 38991 178501 2026-10-27T05:50:43Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1069"]={"_bene, praeclare (melius, optime) mereri_[1] _de aliquo_","to deserve well at some one's hands; to do a service to..."},["1078"]={"_praemium exponere_ or _proponere_","(to encourage) by offering a reward."},["1087"]={"_supplicibus verbis orare_","to crave humbly; to supplicate."},["1096"]={"_optata mihi contingunt_","my wishes are being fulfilled."},["1159"]={"_hoc in te reprehendo_ (not _ob eam re...' 178501 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1069"]={"_bene, praeclare (melius, optime) mereri_[1] _de aliquo_","to deserve well at some one's hands; to do a service to..."},["1078"]={"_praemium exponere_ or _proponere_","(to encourage) by offering a reward."},["1087"]={"_supplicibus verbis orare_","to crave humbly; to supplicate."},["1096"]={"_optata mihi contingunt_","my wishes are being fulfilled."},["1159"]={"_hoc in te reprehendo_ (not _ob eam rem_)","I blame this in you; I censure you for this."},["1168"]={"_rumor increbrescit_","a report, an impression is gaining ground."},["1177"]={"_per omnium ora ferri_","to be in every one's mouth."},["1186"]={"_certiorem facere aliquem_ (_alicuius rei_ or _de aliqua re_)","to inform a person."},["1195"]={"_gloria, laude florere_","to be very famous, illustrious."},["1249"]={"_laborem non intermittere_","to work without intermission."},["1258"]={"_operae pretium est_ (c. Inf.)","it is worth while."},["1267"]={"_negotium obire, exsequi_","to execute, manage a business, undertaking."},["1276"]={"_nullo negotio_","without any trouble."},["1285"]={"_(in) otio languere et hebescere_","to grow slack with inactivity, stagnate."},["1294"]={"_se totum voluptatibus dedere, tradere_","to devote oneself absolutely to the pursuit of pleasure."},["1339"]={"_mihi in mentem venit alicuius rei_","something comes into my mind."},["1348"]={"_notiones animo (menti) insitae, innatae_","innate ideas."},["1357"]={"_cogitatione, non re_","ideally, not really."},["1366"]={"_in sententia manere, permanere, perseverare, perstare_","to abide by, persist in one's opinion."},["1375"]={"_idem sentire_ (opp. _dissentire ab aliquo_)","to hold the same views."},["1384"]={"_quot homines, tot sententiae_","many men, many minds."},["1393"]={"_coniectura assequi, consequi, aliquid coniectura colligere_","to conjecture."},["1429"]={"_errorem stirpitus extrahere_","to totally eradicate false principles."},["1438"]={"_in dubio ponere_","to throw doubt upon a thing."},["1447"]={"_scrupulum ex animo alicuius evellere_ (Rosc. Am. 2. 6)","to relieve a man of his scruple."},["1456"]={"_aliquid compertum habere_","to know a thing for certain."},["1465"]={"_sic volo te tibi persuadere_","convince yourself of this; rest assured on this point."},["1474"]={"_mediocribus consiliis uti_","to adopt half-measures."},["1483"]={"_consiliis arcanis interesse_ (Liv. 35. 18)","to be present at secret consultations."},["1492"]={"_secum (cum animo) reputare aliquid_","to think over, consider a thing."},["1519"]={"_spectare aliquid_ or _ad aliquid_","to have an object in view."},["1528"]={"_de industria, dedita opera_ (opp. _imprudens_)","designedly; intentionally."},["1537"]={"_memoriam alicuius rei tenere_","to remember a thing perfectly."},["1546"]={"_memoria custodire_","to keep in mind."},["1555"]={"_memoriam alicuius rei conservare, retinere_","to retain the recollection of a thing."},["1564"]={"_post hominum memoriam_","within the memory of man."},["1573"]={"_oblivioni esse, dari_","to be forgotten, pass into oblivion."},["1582"]={"_in rebus atque in usu versatum esse_","to have had practical experience."},["1591"]={"_multa acerba expertus est_[2]","he has had many painful experiences."},["1609"]={"_aetatem in litteris ducere, agere_","to devote one's life to science, study."},["1618"]={"_litterae_","literature."},["1627"]={"_vir omni doctrina eruditus_","a man perfect in all branches of learning."},["1636"]={"_doctrina exquisita, subtilis, elegans_[2]","sound knowledge; scholarship."},["1645"]={"_scientia augere aliquem_","to enrich a person's knowledge."},["1654"]={"_litteris leviter imbutum_ or _tinctum esse_","to have received a superficial education."},["1663"]={"_in viam reducere aliquem_","to bring a person back to the right way."},["1672"]={"_ludus (discendi_ or _litterarum_)","an elementary school."},["1681"]={"_natum, factum esse ad aliquid (faciendum)_","to be born for a thing, endowed by nature for it."},["1690"]={"_aliquid efficere, consequi in aliqua re_ (De Or. 1. 33. 152)","to obtain a result in something."},["1708"]={"_aliquid exemplis ostendere_","to demonstrate by instances."},["1717"]={"_auctoritatem alicuius sequi_","to be guided by another's example."},["1726"]={"_bene (male) praecipere alicui_","to inculcate good (bad) principles."},["1735"]={"_philosophiae (sapientiae) studio teneri_ (Acad. 1. 2. 4)","to be enamoured of philosophy."},["1744"]={"_illae sententiae evanuerunt_","those views are out of date."},["1753"]={"_scholis interesse_","to attend lectures."},["1762"]={"_disserendi peritus et artifex_","an accomplished dialectician."},["1771"]={"_omnes philosophiae loci_","the whole domain of philosophy."},["1780"]={"_totam rationem evertere_ (pass. _iacet tota ratio_)","to upset the whole system."},["1807"]={"_argumentum immortalitatis afferre_ (not _pro_)","to quote an argument in favour of immortality."},["1816"]={"_argumenta refellere, confutare_","to refute arguments."},["1825"]={"_hoc posito_","on this supposition, hypothesis."},["1834"]={"_non repugno_","I have nothing to say against it."},["1843"]={"_in controversiam vocare, adducere aliquid_","to make a thing the subject of controversy."},["1852"]={"_res mihi tecum est_","I have a point to discuss with you."},["1861"]={"_una et consentiens vox est_","all are unanimous."},["1870"]={"_inter se pugnare_ or _repugnare_","to be mutually contradictory."},["1906"]={"_historicorum fide contestata memoria_","historic times."},["1915"]={"_temporum ratio, descriptio, ordo_","chronology."},["1924"]={"_regionum terrestrium aut maritimarum scientia_","geographical knowledge."},["1933"]={"_bis bina quot sint non didicisse_","to be absolutely ignorant of arithmetic."},["1942"]={"_(artis, artium) intellegens, peritus_[1] (opp. _idiota_, a layman)","a connoisseur; a specialist."},["1951"]={"_veritatem_[2] _imitari_ (Div. 1. 13. 23)","(1) to make a lifelike natural representation of a thing (used of the artist); (2) to be lifelike (of a work of art)."},["1960"]={"_poeta epicus_","an epic, heroic poet."},["2059"]={"_facultas dicendi_","oratorical talent."},["2068"]={"_vis dicendi_","oratorical power."},["2077"]={"_oratio subita_","an extempore speech."},["2086"]={"_perspicue, diserte dicere_","to speak in clear, expressive language."},["2095"]={"_perorare_","(1) to make one's peroration; (2) to deliver the closing speech (in a case where several speeches have been made)."},["2149"]={"_ante oculos ponere aliquid_","to bring a thing vividly before the eyes."},["2158"]={"_uno conspectu videre aliquid_","to have a general idea of a thing."},["2167"]={"_fusius, uberius, copiosius disputare, dicere de aliqua re_","to speak at great length on a subject, discuss very fully."},["2176"]={"_silentio praeterire_ (not _praetermittere_) _aliquid_","to pass over in silence."},["2185"]={"_quod ornandi causa additum est_","a digression, episode."},["2194"]={"_longe, alte (longius, altius) repetere_ (either absolute or _ab aliqua re_)","to go a long way back (in narrative)."},["2239"]={"_ponere alicui, de quo disputet_","to set some one a theme for discussion."},["2248"]={"_quaestionem solvere_","to decide, determine a question."},["2257"]={"_animo prompto esse ad iocandum_","to be humorously inclined."},["2266"]={"_aspergere sales orationi_ (Or. 26. 87)","to intersperse one's speech with humorous remarks."},["2275"]={"_severitatem adhibere_","to show that one is serious."},["2284"]={"_orationis expertem esse_","to be unable to express one's ideas."},["2293"]={"_sermo latinus_ (opp. _sermo parum latinus_) (cf. sect. VII. 2., note _For the use of adverbs..._)","good Latin."},["2329"]={"_si verba spectas_","literally."},["2338"]={"_verba facere (de aliqua re, apud aliquem)_","to speak on a subject."},["2347"]={"_huic rei deest apud nos vocabulum_","we have no expression for that."},["2356"]={"_in aliqua re dici_","to be used in speaking _of_ a thing."},["2365"]={"_idem valere, significare, declarare_","to have the same meaning."},["2374"]={"_ordo verborum_ (Or. 63. 214)","the order of words."},["2383"]={"_vetus (verbum) est_ (c. Acc. c. Inf.)","it was said long ago that..."},["2392"]={"_syllabam, litteram producere_ (opp. _corripere_) (Quintil. 9. 4. 89)","to lengthen the pronunciation of a syllable or letter."},["2419"]={"_liber intercidit, periit_","the book has been lost."},["2428"]={"_in extremo libro_ (Q. Fr. 2. 7. 1)","at the end of the book."},["2437"]={"_aliquid, multa ex Ciceronis libris excerpere_ (not _excerpere librum_)","to make extracts from Cicero's writings."},["2446"]={"_legendo percurrere aliquid_","to read cursorily."},["2455"]={"_mendose scriptum_","full of orthographical errors."},["2464"]={"_litterae missae et allatae_","correspondence."},["2473"]={"_litterae hoc exemplo_ (Att. 9. 6. 3)","a letter, the tenor of which is..."},["2482"]={"_animum alicuius_ or simply _aliquem flectere_","to make a person change his intention."},["2491"]={"_quid tibi animi est?_","what sort of humour are you in?"},["2509"]={"_dolore affici_","to feel pain."},["2518"]={"_dolore confici, tabescere_","to be wasted with grief; to die of grief."},["2527"]={"_aegritudine, sollicitudine affici_","to be vexed, mortified, anxious."},["2536"]={"_aliquem aegritudine levare_","to comfort another in his trouble."},["2545"]={"_mors alicuius luctum mihi attulit_","some one's death has plunged me in grief."},["2554"]={"_in timore esse, versari_","to be in fear."},["2563"]={"_terror incidit alicui_","terror, panic seizes some one."},["2572"]={"_animus alicui accedit, crescit_","to take courage."},["2581"]={"_animum alicuius redintegrare_","to re-inspire courage."},["2590"]={"_inflatum, elatum esse aliqua re_","to be proud, arrogant by reason of something."},["2608"]={"_perturbari (animo)_","to lose one's composure; to be disconcerted."},["2617"]={"_ad (summam) desperationem pervenire, adduci_ (B. C. 2. 42)","to be plunged into the depths of despair."},["2626"]={"_in spem venire, ingredi, adduci_","to conceive a hope."},["2635"]={"_spem falsam alicui ostendere_","to rouse a vain, groundless hope in some one's mind."},["2644"]={"_spes extenuatur et evanescit_","hope is vanishing by degrees."},["2653"]={"_exspectationem_[1] _sui facere, commovere_","to cause oneself to be expected."},["2662"]={"_ad misericordiam aliquem allicere, adducere, inducere_","to arouse feelings of compassion in some one."},["2671"]={"_nullam partem sensus habere_","to possess not the least spark of feeling."},["2680"]={"_carum atque iucundum esse alicui_","to be dear to some one."},["2707"]={"_fidem_[1] _habere alicui_","to believe a person."},["2716"]={"_committere aliquid alicui_ or _alicuius fidei_","to entrust a thing to a person's good faith."},["2725"]={"_se conferre, se tradere, se permittere in alicuius fidem_","to put oneself under some one's protection."},["2734"]={"_fidem (promissum) praestare_","to fulfil a promise."},["2743"]={"_praestare aliquem, aliquid, de aliqua re_ or Acc. c. Inf.","to be answerable for a person, a thing."},["2752"]={"_suspicionem ex animo delere_","to banish all feeling of prejudice from the mind."},["2761"]={"_in invidia esse alicui_","to be hated by some one."},["2770"]={"_invidiam alicui conflare_ (Catil. 1. 9. 23)","to make a person odious, unpopular."},["2806"]={"_furore incensus, abreptus, impulsus_","in a transport of rage."},["2815"]={"_virtutis perfectae perfecto munere fungi_ (Tusc. 1. 45. 109)","to live a perfect life."},["2824"]={"_corrumpi, depravari_","to be demoralised, corrupted."},["2833"]={"_vitiis, sceleribus inquinatum, contaminatum, obrutum esse_","to be vicious, criminal."},["2842"]={"_scelus (in se) concipere, suscipere_","to commit a crime and so make oneself liable to the consequences of it."},["2851"]={"_cupiditatibus occaecari_ (Fin. 1. 10. 33)","to be blinded by passions."},["2860"]={"_animum vincere_ (Marcell. 3. 8)","to have self-control; to restrain oneself, master one's inclinations."},["2905"]={"_minitari (minari) alicui mortem, crucem et tormenta, bellum_","to threaten some one with death, crucifixion, torture, war."},["2914"]={"_specie_ (De Amic. 13. 47)","apparently; to look at."},["2923"]={"_sine fuco ac fallaciis_ (Att. 1. 1. 1)","without any disguise, frankly."},["2932"]={"_per ludibrium_","in sport, mockery."},["2941"]={"_de, ab officio decedere_","to neglect one's duty."},["2950"]={"_aliquem officiis suis complecti, prosequi_","to be courteous, obliging to some one."},["3049"]={"_omnem religionem tollere, delere_","to annihilate all religious feeling."},["3058"]={"_bellum pro religionibus susceptum_","a religious war."},["3067"]={"_periurium facere; peierare_","to commit perjury, perjure oneself."},["3076"]={"_qui deum esse negat_","an atheist."},["3085"]={"_supplicare deo_ (Sall. Iug. 63. 1)","to pray to God."},["3094"]={"_dis bene iuvantibus_ (Fam. 7. 20. 2)","with the help of the gods."},["3139"]={"_omen infaustum, triste_","an evil omen; presage of ill."},["3148"]={"_apud eum sic fui tamquam domi meae_ (Fam. 13. 69)","I felt quite at home in his house."},["3157"]={"_in publicum prodire_ (Verr. 2. 1. 31)","to show oneself in the streets, in public."},["3166"]={"_ianuam effringere, revellere_","to burst open the door."},["3175"]={"_diligens paterfamilias_","a careful master of the house."},["3184"]={"_possessione alicuius rei cedere alicui_ (Mil. 27. 75)","to give up a thing to some one else."},["3193"]={"_domo emigrare_ (B. G. 1. 31)","to emigrate."},["3229"]={"_vitae commoditas iucunditasque_","comfort"},["3238"]={"_laute vivere_[1] (Nep. Chab. 3. 2)","to live well."},["3247"]={"_luxuria diffluere_ (Off. 1. 30. 106)","to be abandoned to a life of excess."},["3256"]={"_caput cenae_ (Fin. 2. 8. 25)","the main dish."},["3265"]={"_cenam alicui apponere_","to set a repast before a person."},["3274"]={"_hospitium renuntiare_ (Liv. 25. 18)","to sever (previous) hospitable relations."},["3283"]={"_assiduum esse cum aliquo_","to be always in some one's company."},["3292"]={"_se insinuare in consuetudinem alicuius_ (Fam. 4. 13. 6)","to insinuate oneself into a person's society."},["3319"]={"_colloquendi copiam facere, dare_","to give audience to some one."},["3328"]={"_coram loqui (cum aliquo)_","to speak personally to..."},["3337"]={"_Cicero Attico_[2] _S.D.P. (salutem dicit plurimam)_","Cicero sends cordial greetings to Atticus."},["3346"]={"_vale_ or _cura ut valeas_","good-bye; farewell."},["3355"]={"_ducere aliquam in matrimonium_","to marry (of the man)."},["3364"]={"_repudium dicere_ or _scribere alicui_","to separate, be divorced (used of man or woman)."},["3373"]={"_testamentum irritum facere, rumpere_","to annul, revoke a will."},["3382"]={"_hereditate aliquid relictum est ab aliquo_","something has been left as a legacy by some one."},["3391"]={"_consuetudo inveterascit_ (B. G. 5. 41. 5)","a custom is taking root, growing up."},["3409"]={"_negotium obire_ or _exsequi_","to be engaged upon a transaction, carry it out."},["3418"]={"_res, quae importantur et exportantur_","imports and exports."},["3427"]={"_pecunia praesens_ (_vid._ sect. V. 9, note _Notice too..._) or _numerata_","cash; ready money."},["3436"]={"_pecuniam alicui credere (sine fenore, usuris)_","to lend some one money (without interest)."},["3445"]={"_pecuniam exigere (acerbe)_","to demand payment."},["3454"]={"_codex_ or _tabulae ratio accepti et expensi_","account-book; ledger."},["3463"]={"_rationes putare_[3] _cum aliquo_","to balance accounts with some one."},["3472"]={"_centesimae_ (sc. _usurae_) (Att. 5. 21. 11)","interest at 1 per cent per month, 12 per cent per annum."},["3481"]={"_trientes_ or _trientariae usurae_ (Att. 4. 15)","4 per cent."},["3490"]={"_centesimis cum anatocismo contentum esse_ (Att. 5. 21. 12)","to be content with 12 per cent at compound interest."},["3508"]={"_aes alienum habere_","to be in debt."},["3517"]={"_aere alieno liberari_","to get out of debt."},["3526"]={"_oppidum constituere, condere_","to build, found a city."},["3535"]={"_agriculturae studere_ (opp. _agriculturam deserere_)","to have a taste for agriculture."},["3544"]={"_messis in herbis est_ (Liv. 25. 15)","the crop is in the blade."},["3553"]={"_inopia_ (opp. _copia_) _rei frumentariae_","want of corn; scarcity in the corn-market."},["3562"]={"_pastum agere_","to drive to pasture."},["3571"]={"_rem publicam constituere_[1]","to give the state a constitution."},["3580"]={"_rei publicae praeesse_","to have the management of the state."},["3607"]={"_ad rei publicae rationes aliquid referre_","to consider a thing from a political point of view."},["3616"]={"_auctores consilii publici_","statesmen."},["3625"]={"_gerendis negotiis orbatus_ (Fin. 5. 20. 57)","banished from public life."},["3634"]={"_ordo senatorius (amplissimus)_","the senatorial order."},["3643"]={"_homines omnis generis_","people of every rank."},["3652"]={"_unus e togatorum numero_","an ordinary, average Roman citizen."},["3661"]={"_dignitatis gradum ascendere_","to attain a position of dignity."},["3670"]={"_convocare populi concilium_ and _populum ad concilium_","to summon an assembly of the people."},["3706"]={"_leges scribere, facere, condere, constituere_ (not _dare_)","to make laws (of a legislator)."},["3715"]={"_in album referre_ (De Or. 2. 12. 52)","to record in the official tablets (_Annales maximi_)."},["3724"]={"_opibus, gratia, auctoritate valere, florere_","to have great influence."},["3733"]={"_offensio populi, popularis_","unpopularity."},["3742"]={"_contentio partium_ (Phil. 5. 12. 32)","party-strife."},["3751"]={"_in neutris partibus esse_","to be neutral."},["3760"]={"_studio ad rem publicam ferri_","to throw oneself heart and soul into politics."},["3805"]={"_perturbatio omnium rerum_ (Flacc. 37)","general confusion; anarchy."},["3814"]={"_proscribere aliquem_ or _alicuius possessiones_","to proscribe a person, declare him an outlaw."},["3823"]={"_exterminare (ex) urbe, de civitate aliquem_ (Mil. 37. 101)","to expel a person from the city, country."},["3832"]={"_in exsilio esse, exsulem esse_","to live in exile."},["3841"]={"_imperium obtinere_","to maintain power, authority."},["3850"]={"_rerum potiri_","(1) to usurp supreme power, (2) to be in a position of power."},["3904"]={"_coloniam constituere_ (Leg. Agr. 1. 5. 16)","to found a colony."},["3913"]={"_petere magistratum, honores_","to seek office."},["3922"]={"_repulsam ferre consulatus (a populo)_ (Tusc. 5. 19. 54)","to fail in one's candidature for the consulship."},["3931"]={"_magistratus et imperia_ (Sall. Iug. 3. 1)","civil and military offices."},["3940"]={"_abire magistratu_","to give up, lay down office (usually at the end of one's term of office)."},["4039"]={"_aliquid, causam cognoscere_","to hold an inquiry into a matter."},["4048"]={"_testis gravis_","an important witness."},["4057"]={"_testimonium dicere pro aliquo_","to give evidence on some one's behalf."},["4066"]={"_causa publica_ (Brut. 48. 178)","a criminal case."},["4075"]={"_causam suscipere_","to undertake a case."},["4084"]={"_causā_ or _lite cadere_ (owing to some informality)","to lose one's case."},["4093"]={"_crimina diluere, dissolvere_","to refute charges."},["4129"]={"_punire aliquem_","to punish some one."},["4138"]={"_poenas alicui pendere (alicuius rei)_","to be punished by some one (on account of a thing)."},["4147"]={"_in vincula (custodiam) dare aliquem_","to put some one in irons, chains."},["4156"]={"_supplicio (capitis) affici_","to suffer capital punishment."},["4165"]={"_aetas militaris_","military age."},["4174"]={"_militiam_ (only in the sing.) _capessere_","to take service in the army."},["4183"]={"_omnes ad arma convocare_","to issue a general call to arms."},["4192"]={"_alere exercitum_ (Off. 1. 8. 25)","to support an army."},["4219"]={"_praeficere aliquem exercitui_","to place some one at the head of an army, give him the command."},["4228"]={"_res gestae_[1]","exploits in war; brilliant actions."},["4237"]={"_dicto audientem esse alicui_","to obey a person's orders."},["4246"]={"_in armis esse_","to be under arms."},["4255"]={"_gladium educere (e vagīna)_","to draw one's sword (from the scabbard)."},["4264"]={"_apparatus_ (rare in plur.) _belli_","preparations for war; war-material."},["4273"]={"_bellum incipere, belli initium facere_ (B. G. 7. 1. 5)","to commence hostilities."},["4282"]={"_bellum ducere, trahere, extrahere_","to protract, prolong a war."},["4291"]={"_belli finem facere, bellum finire_","to put an end to war."},["4309"]={"_citato gradu incedere_ (cf. sect. II. 5)","to advance rapidly."},["4318"]={"_averso itinere contendere in..._","to change one's route and march towards..."},["4327"]={"_agmine quadrato incedere, ire_","to march with closed ranks, in order of battle."},["4336"]={"_capere, occupare locum_","to occupy a position (with troops)."},["4345"]={"_vigilias crebras ponere_ (Sall. Iug. 45. 2)","to place a close line of sentry-posts."},["4354"]={"_fossam ducere_","to make a ditch, a fosse."},["4363"]={"_stationes agere pro portis_","to be on duty before the gates."},["4372"]={"_lignatum, aquatum ire_","to go to fetch wood, water."},["4381"]={"_rem ad consilium deferre_","to refer a matter to a council of war."},["4390"]={"_opera facere_","to raise siege-works."},["4408"]={"_urbis obsidionem liberare_","to raise a siege (used of the army of relief)."},["4417"]={"_oppidum capere, expugnare_","to take, storm a town."},["4426"]={"_se suaque omnia dedere victori_","to give up one's person and all one's possessions to the conqueror."},["4435"]={"_proelio (ad pugnam) hostes lacessere, provocare_","to provoke the enemy to battle."},["4444"]={"_ad arma concurrere_","to rush to arms."},["4453"]={"_subsidia collocare_","to station reserve troops."},["4462"]={"_proelio equestri contendere_","to give battle with a cavalry-division."},["4471"]={"_proelium deserere_","to give up the fight."},["4480"]={"_proelium iustum_ (opp. _tumultuarium_)","a pitched battle."},["4507"]={"_omissis pilis gladiis rem gerere_","to throw down the javelins (_pila_) and fight with the sword."},["4516"]={"_circumvenire hostem aversum_ or _a tergo_ (B. G. 2. 26)","to surround the enemy from the rear."},["4525"]={"_subsidia summittere_","to send up reserves."},["4534"]={"_undique premi, urgeri_ (B. G. 2. 26)","to be pressed on all sides."},["4543"]={"_fugare hostem_","to put the enemy to flight."},["4552"]={"_fugam capessere, capere_","to take to flight."},["4561"]={"_hostes insequi, prosequi_","to pursue the enemy."},["4570"]={"_effugere, elābi e manibus hostium_","to escape from the hands of the enemy."},["4606"]={"_victoria multo sanguine ac vulneribus stetit_ (Liv. 23. 30)","the victory cost much blood and many wounds, was very dearly bought."},["4615"]={"_pacem conciliare_ (Fam. 10. 27)","to bring about a peace."},["4624"]={"_captivos permutare, commutare_","to exchange prisoners."},["4633"]={"_socium aliquem asciscere_ (B. G. 1. 5)","to make some one one's ally."},["4642"]={"_populum, terram suo imperio, suae potestati subicere_ (not _sibi_ by itself)","to make oneself master of a people, country."},["4651"]={"_aliquem in officio continere_","to keep some one in subjection."},["4660"]={"_oppidum maritimum_","a seaport town."},["4705"]={"_naufragium colligere_ (Sest. 6. 15)","to collect the wreckage."},["4714"]={"_in ancoris esse, stare, consistere_","to ride at anchor."},["4723"]={"_pugnam navalem facere_[1]","to fight a battle at sea."},["4732"]={"_vela armamentaque_","sails and rigging."},["4741"]={"_ne (quid) gravius dicam_","to say the least..."},["4750"]={"_ne longum sit_","not to be prolix."},["4804"]={"_hoc facile intellegi potest_","that is self-evident, goes without saying."},["4813"]={"_id quod maximum, gravissimum est_","the main point."},["4822"]={"_ain tu?_","do you think so? are you in earnest?"},["4831"]={"_ita prorsus existimo_","that is exactly what I think."},["4840"]={"_neque id immerito (iniuria)_","and rightly too."}} local grc_RWoodhouse_lemma_to_infinitives = { ["κολπόω"]={"ἐγκεκολπῶσθαι"},["κυκλόω"]={"κεκυκλῶσθαι","κύκλωσαι","κυκλοῦσθαι","κυκλώσασθαι","κυκλῶσαι","κυκλωθῆναι"},["σκύλλω"]={"σκύλλειν","σκῦλαι"},["συμπροθυμέομαι"]={"συμπροθυμεῖσθαι","συμπροθυμήσεσθαι","συμπροθυμηθῆναι"},["ἀγαλλιάω"]={"ἀγαλλιαθῆναι","ἠγαλλίασεν"}} local la_NLW_headwords_to_path = { ["antiloquium"]={"2/012358"},["cantiloquus"]={"3/007843"},["circumdutus"]={"1/020849"},["cupediuorus"]={"0/007684"},["diuersorium"]={"3/000415"},["excitatiuus"]={"1/017613"},["gnatonismus"]={"3/020427"},["granulentus"]={"3/016243"},["hugonoticus"]={"3/007891"},["impugnatrix"]={"3/010643"},["inaniloquus"]={"3/012427"},["internitium"]={"1/003461"},["internumero"]={"2/012778"},["intertinguo"]={"1/007293"},["intumulesco"]={"1/020941"},["largiloquus"]={"2/003758"},["litterarius"]={"3/016095"},["luminositas"]={"2/007934"},["mensularius"]={"3/018307"},["mortilogium"]={"2/011570"},["mulionarius"]={"0/021516"},["nunciatiuus"]={"0/005208"},["parciloquus"]={"1/021377"},["paruipensor"]={"2/005986"},["perinfestus"]={"3/019211"},["perinsuauis"]={"0/019216"},["perinutilis"]={"3/021575"},["perplusculi"]={"2/013734"},["polypragmon"]={"2/013422"},["portanarius"]={"0/014328"},["prooemiolum"]={"1/009177"},["prosperatio"]={"2/005950"},["quampluries"]={"2/011738"},["scurriliter"]={"0/001260"},["scutiformis"]={"1/015893"},["semiappulus"]={"0/012648"},["semidiurnus"]={"1/004017"},["semifuratus"]={"2/002906"},["sensiterium"]={"0/013656"},["signatorius"]={"1/005457"},["suauiuscule"]={"3/013479"},["subinflexus"]={"1/009053"},["subleuatrix"]={"2/008886"},["superinnato"]={"3/008011"},["syllabismus"]={"3/005019"},["talmudismus"]={"3/014579"},["tinnimentum"]={"0/011288"},["topologicus"]={"2/017346"},["transnomino"]={"0/009272"},["transsubstantiatiuus"]={"3/020331"}} local grc_RLBG_lemma_to_index = { ["ἀποστολιμαῖος"]={"8153"},["γενεσιουργικός"]={"13895"},["δερβάς"]={"15479"},["διαπροσεύχομαι"]={"16415"},["δωδεκατημόριος"]={"19291"},["Καρποκρατιανοί"]={"34636"},["κόχλος"]={"39281"},["κραββαττόξυλον"]={"39297"},["μεγαλοϋπέροχος"]={"43771"},["νώτιος"]={"48158"},["πεντηκοστάριον"]={"55327"},["περιλημματικός"]={"55914"},["ἀγγάριον"]={"230"},["ἀειδινής"]={"1086"},["ἀλλαγίζω"]={"2583"},["ἀμάλαγος"]={"2903"},["βοητρόπως"]={"12642"},["δρυφακτόω"]={"18402"},["ἐμμιγνύω"]={"22084"},["ἐμμύθιος"]={"22103"},["ἔνθρονος"]={"23220"},["ἐξόμπλιν"]={"24552"},["θεοπρόπως"]={"30816"},["ἱκεσιάζω"]={"32094"},["ἰπνοκαής"]={"32351"},["ἰσομαθής"]={"32565"},["καταφυτόω"]={"36138"},["κεραμοῦς"]={"36997"},["κρυψίφρων"]={"39793"},["λυσόπορτα"]={"42471"},["ὀνομύλων"]={"50104"},["περιϊδρύω"]={"55747"},["ποταμοπεριπάτητος"]={"59266"},["προπετεύω"]={"61423"},["προσαπλόω"]={"61717"},["αὐτοδαΐκτως"]={"10635"},["βαλανοφαγία"]={"11715"},["γιγαντοκοιλιολάτρης"]={"14113"},["ἐκκαυστικός"]={"20816"},["ἐκπυρρόομαι"]={"21299"},["ἐπιζεφύριος"]={"25630"},["ἡμιτέταρτος"]={"29979"},["Ἰσαυροφόνος"]={"32490"},["μουνικίπιον"]={"46329"},["ξανθόμαλλος"]={"48186"},["ξενιτεύομαι"]={"48243"},["ὀβριμόφωνος"]={"48634"},["ὀνειρόσοφος"]={"50039"},["ὀρθόπλουμος"]={"50621"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["praeteritus"]={"3835"},["planissimus"]={"3703"}} local grc_RCunliffe_lemma_to_index = { ["φοινός"]={"9481"},["ἀνθρακιή"]={"908"},["αἰγιαλός"]={"217"}} local grc_RWoodhouse_lemma_to_headwords = { ["Κράνων"]={"cranon"},["Τάναϊς"]={"tanais (river)"},["κόχλος"]={"shell"},["μοιχός"]={"adulterer"},["φλογώψ"]={"bright","dazzling","fiery","flashing","gleaming","shining"},["φόνιος"]={"murderous"},["ἀρτᾶν"]={"attach","hang","suspend"},["ὀπτᾶν"]={"bake","broil","burn","cook","fry","grill","roast"},["Αἰακίδης"]={"aeacus"},["αἰγιαλός"]={"beach","coast","shingle","shore"},["κωμωδεῖν"]={"hit"},["πορνεῖον"]={"brothel"},["προνοεῖν"]={"discern","foresee","perceive"},["πρόχειρος"]={"available","disposable","forth-coming","hand","handy","on ","reach","ready","within"},["ἀκολασία"]={"debauchery","dissipation","dissoluteness","excess","incontinence","intemperance","lasciviousness","lewdness","libidinousness","licence","licentiousness","lust","profligacy","self-indulgence","sensuality","unruliness"},["ἀρίθμημα"]={"amount","number"},["ἰσηγορια"]={"equality"},["ὑπόλογον"]={"allow"},["αὐτόπρεμνος"]={"branch","root","utterly"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} tv8wdsuhlq40u1yq8o8fqzes772mvt7 Module:data tables/dataM201 828 38992 178502 2026-10-27T05:51:26Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1008"]={"_commodis alicuius servire_","to look after, guard a person's interests, welfare."},["1017"]={"_damno affici_","to suffer loss, harm, damage."},["1026"]={"_res repetere_","to demand restitution, satisfaction."},["1035"]={"_multum valere gratia apud aliquem_","to be highly favoured by; to be influential with..."},["1044"]={"_alicuius causa_[1] _velle_ or _cupere_","to be favourably disposed towards....' 178502 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1008"]={"_commodis alicuius servire_","to look after, guard a person's interests, welfare."},["1017"]={"_damno affici_","to suffer loss, harm, damage."},["1026"]={"_res repetere_","to demand restitution, satisfaction."},["1035"]={"_multum valere gratia apud aliquem_","to be highly favoured by; to be influential with..."},["1044"]={"_alicuius causa_[1] _velle_ or _cupere_","to be favourably disposed towards."},["1053"]={"_beneficia in aliquem conferre_","to heap benefits upon..."},["1062"]={"_gratiam mereri_","to merit thanks; to do a thankworthy action."},["1071"]={"_meritum alicuius in_ or _erga aliquem_","what a man merits at another's hands."},["1080"]={"_palmam deferre, dare alicui_","to award the prize to..."},["1107"]={"_uti aliquo amico_","to be friendly with any one."},["1116"]={"_aliquem (tertium) ad (in) amicitiam ascribere_","to admit another into the circle of one's intimates."},["1125"]={"_placare aliquem alicui_ or _in aliquem_","to reconcile two people; to be a mediator."},["1134"]={"_magna auctoritas alicuius est apud aliquem_","to have great influence with a person; to have considerable weight."},["1143"]={"_aliquid infra se ducere_ or _infra se positum arbitrari_","to consider a thing beneath one's dignity."},["1152"]={"_omnium undique laudem colligere_","to win golden opinions from every one."},["1161"]={"_in vituperationem, reprehensionem cadere, incidere, venire_","to suffer reproof; to be criticised, blamed."},["1170"]={"_famam dissipare_","to spread a rumour."},["1206"]={"_gloriae, laudis cupiditate incensum esse, flagrare_","to be consumed by the fires of ambition."},["1215"]={"_famam crudelitatis subire_ (Catil. 4. 6. 12)","to gain the reputation of cruelty."},["1224"]={"_aliquem cupiditate honorum inflammare_ (or _aliquem ad cupiditatem honorum inflammare_)","to kindle ambition in some one's mind."},["1233"]={"_notam turpitudinis alicui_ or _vitae alicuius inurere_","to injure a man's character, tarnish his honour."},["1242"]={"_incumbere in (ad) aliquid_","to be energetic about, throw one's heart into a thing."},["1251"]={"_lucubrare_ (Liv. 1. 57)","to work by night, burn the midnight oil."},["1260"]={"_contentionem adhibere_","to exert oneself."},["1305"]={"_animo_ or simply _sibi indulgere_","to indulge oneself."},["1314"]={"_ingenio abundare_","to be very talented."},["1323"]={"_mentis quasi luminibus officere_ (_vid._ sect. XIII. 6) or _animo caliginem offundere_","to obscure the mental vision."},["1332"]={"_rerum imagines_","creatures of the imagination."},["1341"]={"_aliquem ad eam cogitationem adducere ut_","to induce a person to think that..."},["1350"]={"_notionem_ or _rationem alicuius rei in animo informare_ or _animo concipere_","to form a conception, notion of a thing."},["1404"]={"_a vero aversum esse_ (Catil. 3. 1. 29)","to be averse to truth."},["1413"]={"_vera et falsa (a falsis) diiudicare_","to distinguish true and false."},["1422"]={"_per errorem labi_, or simply _labi_","to take a false step."},["1431"]={"_alicui errorem demere, eripere, extorquere_","to undeceive a person."},["1440"]={"_quod aliquam (magnam) dubitationem habet_ (Leg. Agr. 1. 4. 11)","a thing which is rather (very) dubious."},["1503"]={"_incertus sum, quid consilii capiam_","I am undecided..."},["1512"]={"_parare aliquid_","to take measures for..."},["1521"]={"_res spectat ad vim (arma)_","there seems a prospect of armed violence; things look like violence."},["1530"]={"_infecta re_ (Liv. 9. 32)","to no purpose; ineffectually."},["1602"]={"_in studio litterarum versari_","to be engaged in literary pursuits."},["1611"]={"_omne studium in litteris collocare, ad litteras conferre_","to employ all one's energies on literary work."},["1620"]={"_litterae latinae_[4]","Roman literature."},["1701"]={"_exemplum luculentum_","a good, brilliant example; a striking example."},["1710"]={"_exempla a rerum Romanarum (Graecarum) memoria petita_","examples taken from Roman (Greek) history."},["1800"]={"_apte (aptissime) cohaerere_","to be very intimately related."},["2007"]={"_fabulam agere_","to act a play (said of the actors)."},["2016"]={"_dominus gregis_","the manager."},["2025"]={"_fabula cadit_","a piece is a failure, falls flat."},["2034"]={"_carmen chori, canticum_","a choric ode in a tragedy."},["2043"]={"_gladiatores dare_","to give a gladiatorial show."},["2052"]={"_ludi gymnici_","gymnastic contests."},["2061"]={"_facilem et expeditum esse ad dicendum_ (Brut. 48. 180)","to be a ready, fluent speaker."},["2070"]={"_eloquentiae principatum tenere_","to be considered the foremost orator."},["2106"]={"_fusum orationis genus_","a running style."},["2115"]={"_expedita et facile currens oratio_","an easy, fluent style."},["2124"]={"_integritas, sinceritas orationis_ (not _puritas_)","purity of style."},["2133"]={"_sententiae reconditae ex exquisitae_ (Brut. 97. 274)","profound sentiments."},["2142"]={"_contextus orationis_ (not _nexus, conexus sententiarum_)","the connection."},["2151"]={"_rerum sub aspectum paene subiectio_ (De Or. 3. 53. 202)","graphic depiction."},["2160"]={"_strictim, leviter tangere, attingere, perstringere aliquid_","to make a cursory mention of a thing; to mention by the way (not _obiter_ or _in transcursu_)."},["2205"]={"_vox magna, clara_ (Sulla 10. 30)","a strong, loud voice."},["2214"]={"_magna voce clamare_","to shout at the top of one's voice."},["2223"]={"_dispositio rerum_ (De Inv. 1. 7. 9)","the arrangement of the subject-matter."},["2232"]={"_ad propositum reverti, redire_","to come back to the point."},["2241"]={"_quaestionem ponere, proponere_","to propose a subject of debate, put a question."},["2250"]={"_ad interrogata respondere_[1]","to answer questions."},["2304"]={"_ad verbum transferre, exprimere_","to translate literally, word for word (not _verbo tenus_)."},["2313"]={"_praecepta_[2] _grammaticorum_","the rules of speech, grammar."},["2322"]={"_copia, ubertas verborum_","profusion of words."},["2331"]={"_haec verba sunt_ (Ter. Phorm. 3. 2. 32)","these are mere empty phrases."},["2340"]={"_verbis concertare_ or _altercari cum aliquo_ (B. C. 3. 19. 6)","to hold an altercation with a man."},["2403"]={"_litteris persequi_ (_vid._ sect. VIII. 2, note _persequi..._) _aliquid_","to treat in writing."},["2412"]={"_volumen explicare_","to open a book."},["2421"]={"_liber perditus_","a lost book of which fragments (_relliquiae_, not _fragmenta_) remain."},["2430"]={"_librum in manibus habere_ (Acad. 1. 1. 2)","to be engaged on a book."},["2502"]={"_laetitia gestiens_","a transport of joy."},["2511"]={"_doloribus premi, angi, ardere, cruciari, distineri et divelli_","to feel acute pain."},["2520"]={"_dolori resistere_","to struggle against grief."},["2601"]={"_humane, modice, moderate, sapienter, constanter ferre aliquid_","to bear a thing with resignation, composure."},["2610"]={"_non esse apud se_[2] (Plaut. Mil. 4. 8. 26)","to lose one's head, be beside oneself."},["2700"]={"_admiratione incensum esse_","to be fired with admiration."},["3006"]={"_severus morum castigator_","a stern critic of morals."},["3015"]={"_caeco impetu ferri_","to have no principles."},["3024"]={"_superi; inferi_","the gods of the upper, lower world."},["3033"]={"_rebus divinis interesse_ (B. G. 6. 13)","to take part in divine service (of the priest)."},["3042"]={"_propius ad deos accedere_ (Mil. 22. 59)","to approach the gods."},["3051"]={"_religione obstrictos habere multitudinis animos_ (Liv. 6. 1. 10)","to have power over the people by trading on their religious scruples."},["3060"]={"_iusiurandum dare alicui_[2]","to swear an oath to a person."},["3105"]={"_rem divinam facere (dis)_","to sacrifice."},["3114"]={"_parentare_ (Leg. 2. 21. 54)","to make a sacrifice on the tomb of one's ancestors."},["3123"]={"_oraculum petere (ab aliquo)_","to ask for an oracular response."},["3132"]={"_de caelo servare_ (Att. 4. 3. 3)","to observe the sky (_i.e._ the flight of birds, lightning, thunder, etc.)"},["3141"]={"_domus ruina_[1] _impendet_","the house threatens to fall in (_vid._ sect. X. 5, note _'Threaten'..._)."},["3150"]={"_tectum subire_","to enter the house."},["3204"]={"_vestem ponere_[3] _(exuere)_","to undress."},["3213"]={"_tantum cibi et potionis adhibere quantum satis est_","to take only enough food to support life."},["3222"]={"_inter pocula_","whilst drinking; at table."},["3231"]={"_quae suppeditant ad victum_ (Off. 1. 4. 12)","a livelihood."},["3240"]={"_sumptus effusi_ (_vid._ sect. IX. 2, note _Cf. effusa fuga..._) or _profusi_","prodigal expenditure."},["3303"]={"_sermo incidit de aliqua re_","the conversation turned on..."},["3312"]={"_multus sermo_","a long conversation."},["3321"]={"_aditum conveniendi_ or _colloquium_[4] _petere_","to ask a hearing, audience, interview."},["3330"]={"_capita conferre_ (Liv. 2. 45)","to put our heads together."},["3402"]={"_ita fert consuetudo_","so custom, fashion prescribes."},["3411"]={"_mercaturam facere_","to be engaged in commerce, wholesale business."},["3420"]={"_parvo, vili pretio_ or _bene emere_","to buy cheaply."},["3501"]={"_fidem moliri_ (Liv. 6. 11. 8)","to shake credit."},["3510"]={"_in suis nummis versari_ (Verr. 4. 6. 11)","to have no debts."},["3600"]={"_rem publicam augere, amplificare_","to aggrandise, extend the power of the state."},["4005"]={"_dimittere senatum_[5]","to dismiss the senate."},["4014"]={"_summo iure agere cum aliquo_ (cf. _summum ius, summa iniuria_)","to proceed against some one with the utmost rigour of the law; to strain the law in one's favour."},["4023"]={"_aliquem in integrum_ (_vid._ sect. V. 4, note _The proper..._) _restituere_","to reinstate a person in his right."},["4032"]={"_ius ad artem redigere_","to reduce law to a system."},["4041"]={"_quaestionem habere de aliquo, de aliqua re_ or _in aliquem_","to examine a person, a matter."},["4050"]={"_testis incorruptus atque integer_","an impartial witness."},["4104"]={"_sententiae iudicum_","the finding of the jury."},["4113"]={"_culpa carere, vacare_","to be free from blame."},["4122"]={"_facinus, culpam in se admittere_","to commit some blameworthy action."},["4131"]={"_poenas alicuius persequi_","to exact a penalty from some one."},["4140"]={"_poenam (alicuius rei) ferre, perferre_","to suffer punishment."},["4203"]={"_expeditus_ (opp. _impeditus_) _miles_","a soldier lightly armed, ready for battle."},["4212"]={"_milites mercennarii_ or _exercitus conducticius_","mercenary troops."},["4221"]={"_praeesse exercitui_","to be at the head of an army."},["4230"]={"_cum imperio esse_","to hold a high command."},["4302"]={"_castra movere_","to begin the march, break up the camp."},["4311"]={"_iter facere_","to march."},["4320"]={"_agmen, exercitum demittere in..._","to march down on to..."},["4401"]={"_tela ingerere, conicere_","to discharge showers of missiles."},["4410"]={"_obsidionem quattuor menses sustinere_","to hold out for four months."},["4500"]={"_diu anceps stetit pugna_","the issue of the day was for a long time uncertain."}} local grc_RWoodhouse_lemma_to_infinitives = { ["εἰσβαίνω"]={"ἐσβαίνειν","ἐσβήσεσθαι","ἐσβῆναι","εἰσβαίνειν"},["καταψευδομαρτυρέω"]={"καταψευδομαρτυρεῖν"},["περλυστρο"]={"περλυστραρε","περλυστραρι","περλυστρασσε"},["ἀμφικαλύπτω"]={"ἀμφικαλύπτειν","ἀμφικαλύψαι","ἀμφικεκαλύφθαι"},["ἀπᾴδω"]={"ἀπᾴδειν"},["κληρόω"]={"ἀνακληροῦσθαι","κεκληρῶσθαι","κληροῦσθαι","κληρώσασθαι","κληρῶσαι","παρακληρῶσαι"},["λυξτορ"]={"αδλυξταρι","λυξταρι"},["νεκρόω"]={"νεκρωθῆναι","νενεκρῶσθαι"},["φλυιτο"]={"φλυιταρε","φλυιτασσε"}} local la_NLW_headwords_to_path = { ["altiloquens"]={"0/011088"},["amoenisonus"]={"3/004275"},["amussitatim"]={"2/010066"},["angustiator"]={"1/007485"},["antiquaster"]={"2/011526"},["arziguelfus"]={"1/019765"},["castratinus"]={"0/003548"},["chrysopoeta"]={"1/009073"},["concinnulus"]={"0/016856"},["confortator"]={"0/001756"},["contubernor"]={"1/020249"},["cordintimus"]={"0/001536"},["crassiculus"]={"1/010309"},["cunctiparus"]={"0/014684"},["desipiturio"]={"0/011836"},["diuersitudo"]={"1/015201"},["essentiator"]={"3/005683"},["euthymetria"]={"3/012967"},["exorcizatio"]={"0/005072"},["expectatrix"]={"1/010941"},["ferripotens"]={"1/016153"},["frondifluus"]={"0/019764"},["fruticarius"]={"3/013983"},["geminisonus"]={"2/013538"},["harlequinus"]={"3/011011"},["hilarisonus"]={"1/010501"},["Hussitismus"]={"3/017223"},["inaugurator"]={"2/010290"},["interpartio"]={"2/012466"},["irregenitus"]={"3/007011"},["latinizator"]={"0/007216"},["litteratura"]={"2/000806"},["multicollis"]={"1/011589"},["myrothecion"]={"2/000890"},["obsoporatio"]={"0/008584"},["perplexitas"]={"3/001015"},["plaustrifer"]={"0/007968"},["polyanthula"]={"1/018341"},["postergatio"]={"1/001069"},["praedeuotus"]={"1/012801"},["praeimbutus"]={"0/021520"},["propagatrix"]={"1/018077"},["quatriduans"]={"0/017132"},["rumigerator"]={"0/009624"},["semicolonus"]={"1/004153"},["seminatiuum"]={"1/004669"},["sesquiopera"]={"2/009818"},["sprecatinus"]={"3/017215"},["subcommodus"]={"0/017832"},["subcredulus"]={"3/016463"},["templiculum"]={"1/018481"},["transubstantiatorius"]={"2/020330"},["tympanidium"]={"3/016379"}} local grc_RLBG_lemma_to_index = { ["ἀγκινάρα"]={"403"},["αὐθαδίας"]={"10359"},["βαρυφόρος"]={"12007"},["Γαινῖται"]={"13575"},["ἐκκαινόω"]={"20786"},["ἔνζουδος"]={"23136"},["ἔνομβρος"]={"23418"},["εὔγνωμος"]={"27813"},["εὐεπιβουλευμένος"]={"27927"},["ζαρταλοῦ"]={"29199"},["ἰαματίζω"]={"31618"},["καυστηρός"]={"36704"},["μυλιαῖος"]={"46579"},["ὁμόνοιος"]={"49873"},["ὀρδινεία"]={"50511"},["πάμπτωχος"]={"52118"},["περιγυρόω"]={"55594"},["πετραϊκός"]={"56700"},["προρροφέω"]={"61512"},["ἀγαθοθελῶς"]={"153"},["ἀκταιοφόρος"]={"2290"},["ἀνθυποφωνέω"]={"5108"},["ἀπεριγραψία"]={"7076"},["ἀρτιόδρομος"]={"9251"},["ἀσύμπλεκτος"]={"10043"},["αὐθύβριστος"]={"10396"},["αὐτόρειθρος"]={"10887"},["αὐτούργησις"]={"10955"},["γαννύσκομαι"]={"13723"},["δικαιοφύλαξ"]={"17231"},["δολομήχανος"]={"17972"},["ἐθελοπρωτέω"]={"20015"},["ἐκτοπουργέω"]={"21484"},["ἐμπυριστέον"]={"22405"},["ἐναπόφραξις"]={"22773"},["ἐνιστουργέω"]={"23255"},["ἐξουσιάρχης"]={"24629"},["ἐπιχυτάριον"]={"26773"},["καλαμαύχιον"]={"33660"},["καναβούριον"]={"34261"},["κοινοφειλής"]={"38035"},["κορσελήνιον"]={"38756"},["λειποθύμημα"]={"41083"},["λινομέταξος"]={"41892"},["μεγαλόνικος"]={"43713"},["μονοπέδιλος"]={"46081"},["μουχάνδιδον"]={"46433"},["ὀλοθρευσμός"]={"49430"},["ὀπτόπλινθος"]={"50430"},["ὀστοκοπώδης"]={"50984"},["ἀπαρανόσφιστος"]={"6793"},["γαράρα"]={"13731"},["γόμφος"]={"14488"},["γομφός"]={"14489"},["δόρυον"]={"18096"},["ἐπιθαρσυντήρως"]={"25652"},["κιτεύω"]={"37483"},["κορκός"]={"38729"},["κούρτη"]={"39197"},["κώντης"]={"40439"},["λούπις"]={"42258"},["μυαλόω"]={"46491"},["ὀστρακοθρύπτης"]={"50995"},["προεκπετάννυμι"]={"60432"},["προσεπιλεκτέον"]={"62268"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["tribunicius"]={"3981"},["de"]={"22","23","142","204","205","211","236","238","297","298","409","410","444","473","474","480","531","538","578","710","711","713","741","742","812","982","1069","1070","1164","1186","1187","1188","1207","1214","1243","1247","1347","1349","1369","1370","1371","1372","1396","1470","1481","1482","1528","1544","1580","1607","1634","1638","1644","1653","1658","1690","1691","1720","1727","1740","1750","1754","1760","1767","1768","1774","1795","1815","1830","1832","1844","1848","1890","1958","1983","1992","1996","2001","2013","2063","2064","2117","2125","2131","2139","2147","2151","2165","2167","2188","2192","2195","2203","2223","2239","2240","2245","2252","2264","2276","2283","2301","2314","2325","2337","2338","2394","2409","2417","2425","2433","2479","2506","2530","2605","2606","2607","2619","2620","2625","2654","2663","2702","2723","2740","2743","2745","2772","2789","2830","2881","2914","2941","2956","3000","3002","3044","3132","3160","3177","3181","3235","3278","3301","3303","3309","3342","3348","3363","3380","3389","3414","3468","3471","3499","3502","3540","3551","3612","3613","3614","3618","3622","3645","3649","3659","3660","3667","3668","3715","3756","3795","3822","3823","3837","3916","3941","3945","3946","3950","3989","3992","3996","4012","4040","4041","4061","4062","4074","4090","4098","4101","4102","4106","4134","4142","4155","4605","4607","4608","4614","4696","4715","4738","4763","4776","4783","4785","4786","4825","4846"},["perturbatio"]={"2871","3805"},["exercitatus"]={"2062","3619","4204"}} local grc_RCunliffe_lemma_to_index = { ["οἰνοχόος"]={"6865"},["γουνός"]={"1965"},["ἐξοιχνέω"]={"3422"},["κόλπος"]={"5688"},["ἀμφικαλύπτω"]={"653"},["καταστορέννυμι"]={"5340"},["βοόωσι"]={"1789"},["γόμφος"]={"1956"},["χρυσάορος"]={"9690"},["κρόκος"]={"5807"},["ἀεσιφροσύνη"]={"180"},["χόανος"]={"9652"},["ἀνέδραμε"]={"826"},["εἰσβαίνω"]={"2801"},["κεκρυμμένον"]={"5491"},["πεφυζότες"]={"7723"}} local grc_RWoodhouse_lemma_to_headwords = { ["αἴρεσθαι"]={"ascend","begin","commence","elate","face","hand","mount","rise","start","take","tower","undertake","wage"},["οἰνοχόος"]={"cup-bearer"},["συμμέτρως"]={"appropriately","aptly","becomingly","befittingly","characteristically","conveniently","duly","felicitously","fitly","happily","opportunely","properly","regularly","seasonably","suitably","symmetrically"},["Ὀλύνθιος"]={"olynthus"},["ἱπποτοξότης"]={"archer","bowman","mounted"},["ὀμβροκτύπος"]={"rainy"},["Γέσκων"]={"gisco"},["Θηβαΐς"]={"thebes (in boeotia)","thebes (in egypt)"},["Καρύαι"]={"caryae"},["Κλάρος"]={"","clarus"},["Ξέρξης"]={"xerxes"},["Πάρνης"]={"parnes (mt.)"},["γόμφος"]={"bolt","clamp","nail","rivet","stud"},["κρόκος"]={"crocus","saffron"},["κόλπος"]={"bay","bosom","breast","cove","creek","estuary","fold","gulf","inlet","lap","tuck","valley"},["κύριος"]={"absolute","all-powerful","almighty","appoint","arbiter","authorised","authoritative","authority","binding","cardinal","chief","competent","decisive","dominant","effective","entitle","force","foremost","fundamental","guardian","head","imperative","imperious","influence","influential","king","leading","lord","main","master","official","paramount","plenary","possessed","prince","principal","ruler","ruling","sovereign","staple","supreme","suzerain","unabolished","unalterable","unrepealed","valid"},["πλόκος"]={"braid","bunch","chaplet","curl","lock","plait","ribbon","ringlet","tress","wreath"},["στενόν"]={"channel","strait"},["τολύπη"]={"clew","skein"},["τύφειν"]={"fume","smoke","smother","smoulder","stupefy"},["Ὀποῦς"]={"opus"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} sic5uh71o662epitz4lemu5nkmblums Module:data tables/dataM202 828 38993 178503 2026-10-27T05:52:05Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1009"]={"_commoda alicuius tueri_","to look after, guard a person's interests, welfare."},["1018"]={"_detrimentum capere, accipere, facere_","to suffer loss, harm, damage."},["1027"]={"_res restituere_","to give restitution, satisfaction."},["1036"]={"_florere gratia alicuius_","to be highly favoured by; to be influential with..."},["1045"]={"_gratum (gratissimum) alicui facere_","to do any one a (great) fa...' 178503 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1009"]={"_commoda alicuius tueri_","to look after, guard a person's interests, welfare."},["1018"]={"_detrimentum capere, accipere, facere_","to suffer loss, harm, damage."},["1027"]={"_res restituere_","to give restitution, satisfaction."},["1036"]={"_florere gratia alicuius_","to be highly favoured by; to be influential with..."},["1045"]={"_gratum (gratissimum) alicui facere_","to do any one a (great) favour."},["1054"]={"_beneficiis aliquem obstringere, obligare, devincire_","to lay any one under an obligation by kind treatment."},["1063"]={"_par pari referre_","to return like for like."},["1072"]={"_nullo meo merito_","I had not deserved it."},["1081"]={"_palmam ferre, auferre_","to win the prize."},["1090"]={"_magnis (infimis) precibus moveri_","to be influenced by, to yield to urgent (abject) entreaty."},["1108"]={"_est_ or _intercedit mihi cum aliquo amicitia_","I am on good terms with a person."},["1117"]={"_amicitiam renuntiare_","to renounce, give up a friendship."},["1126"]={"_reconciliare alicuius animum_ or simply _aliquem alicui_","to reconcile two people; to be a mediator."},["1135"]={"_alicuius auctoritas multum valet apud aliquem_","to have great influence with a person; to have considerable weight."},["1144"]={"_laudem tribuere, impertire alicui_","to praise, extol, commend a person."},["1153"]={"_maximam ab omnibus laudem adipisci_","to win golden opinions from every one."},["1162"]={"_exprobrare alicui aliquid_","to reproach a person with..."},["1171"]={"_dubii rumores afferuntur ad nos_","vague rumours reach us."},["1180"]={"_foras efferri, palam fieri, percrebrescere, divulgari, in medium proferri, exire, emanare_","to become known, become a topic of common conversation (used of things)."},["1207"]={"_de gloria, fama alicuius detrahere_","to detract from a person's reputation, wilfully underestimate a person."},["1216"]={"_infamiam alicui inferre, aspergere_","to damage a person's character, bring him into bad odour."},["1225"]={"_honores concupiscere_ (opp. _aspernari_)","to aspire to dignity, high honours."},["1234"]={"_ignominiam non ferre_","to chafe under an indignity, repudiate it."},["1243"]={"_opus_[1] _facere_ (De Senect. 7. 24)","to do work (especially agricultural)."},["1252"]={"_inanem laborem suscipere_","to lose one's labour."},["1261"]={"_omnes nervos_[2] _in aliqua re contendere_","to strain every nerve, do one's utmost in a matter."},["1270"]={"_multis negotiis implicatum, districtum, distentum, obrutum esse_","to be involved in many undertakings; to be much occupied, embarrassed, overwhelmed by business-claims."},["1306"]={"_magno animo esse_","to be magnanimous, broad-minded."},["1315"]={"_natura et ingenium_","natural gifts."},["1324"]={"_intellegentia_ or _mente multum valere_[2]","to possess great ability."},["1333"]={"_res cogitatione fictae_ or _depictae_","creatures of the imagination."},["1342"]={"_alicuius animum ab aliqua re abducere_","to draw away some one's attention from a thing."},["1351"]={"_absolutus et perfectus_","absolutely perfect."},["1360"]={"_comprehensam quandam animo speciem (alicuius rei) habere_","to have formed an ideal notion of a thing."},["1405"]={"_a veritate deflectere, desciscere_","to swerve from the truth."},["1414"]={"_vera cum falsis confundere_","to confuse true with false."},["1423"]={"_aliquem in errorem inducere, rapere_","to lead a person into error."},["1432"]={"_nisi fallor_","if I am not mistaken."},["1441"]={"_dubitatio mihi affertur, inicitur_","a doubt arises in my mind."},["1450"]={"_probe scio, non ignoro_","I know very well."},["1504"]={"_mihi non constat_ (with indirect question)","I have not made up my mind."},["1513"]={"_animum inducere_ c. Inf. (not _in animum inducere_)","to persuade oneself to..."},["1522"]={"_id quod voluit consecutus est_","he attained his object."},["1531"]={"_moram alicui rei afferre, inferre, facere_","to retard, delay a thing."},["1540"]={"_memorem esse_ (opp. _obliviosum esse_)","to have a good memory."},["1603"]={"_in aliquo litterarum genere versari_","to be engaged in any branch of study."},["1612"]={"_optimarum artium studio incensum esse_","to be interested in, have a taste for culture."},["1621"]={"_clarissima litterarum lumina_","shining lights in the literary world."},["1630"]={"_nemo doctus_","no man of learning."},["1702"]={"_exemplum illustre_","a good, brilliant example; a striking example."},["1711"]={"_multa exempla in unum (locum) colligere_","to collect, accumulate instances."},["1720"]={"_sibi exemplum sumere ex aliquo_ or _exemplum capere de aliquo_","to take a lesson from some one's example."},["1801"]={"_continuatio seriesque rerum, ut alia ex alia nexa et omnes inter se aptae colligataeque sint_ (N. D. 1. 4. 9)","systematic succession, concatenation."},["1810"]={"_aliquid planum facere_ (Ad Herenn. 2. 5)","to demonstrate, make a thing clear."},["1900"]={"_memoriam annalium_ or _temporum replicare_","to consult history."},["2008"]={"_fabulam edere_","to bring out a play, put it on the stage (used of the man who finds the money)."},["2017"]={"_theatrum_[1]","the playhouse."},["2026"]={"_histrionem exsibilare, explodere, eicere, exigere_","to hiss an actor off the stage."},["2035"]={"_loci melici_","the lyric portions of a tragedy."},["2044"]={"_familia_[4] _gladiatoria_ (Sest. 64. 134)","a band, troupe of gladiators under the management of a _lanista_."},["2053"]={"_certamina gymnica_","gymnastic contests."},["2062"]={"_rudem, tironem ac rudem_ (opp. _exercitatum_) _esse in dicendo_","to be an inexperienced speaker."},["2071"]={"_primum_ or _principem inter oratores locum obtinere_","to be considered the foremost orator."},["2080"]={"_oratio composita_","an elaborate speech."},["2107"]={"_inconditum dicendi genus_ (Brut. 69. 242)","a rough, unpolished style."},["2116"]={"_oratio aequabiliter fluens_","an easy, fluent style."},["2125"]={"_oratio inquinata_[4] (De Opt. Gen. Or. 3. 7)","incorrect language."},["2134"]={"_ubertas_ (not _divitiae_) _et copia orationis_","a full and copious style of speech."},["2143"]={"_ratio sententiarum_","the connection of thought."},["2152"]={"_perlustrare, lustrare oculis aliquid_","to scrutinise, examine closely."},["2161"]={"_quasi praeteriens, in transitu attingere aliquid_","to make a cursory mention of a thing; to mention by the way (not _obiter_ or _in transcursu_)."},["2170"]={"_rebus ipsis par est oratio_","the circumstances are described in language worthy of them."},["2206"]={"_vox gravis, acuta, parva, mediocris_","a deep, high, thin, moderate voice."},["2215"]={"_clamorem tollere_ (Liv. 3. 28)","to raise a shout, a cry."},["2224"]={"_materia rerum et copia uberrima_","abundance of material."},["2233"]={"_ad rem redire_","to come back to the point."},["2242"]={"_quaestionem poscere_ (Fin. 2. 1. 1)","to get a question submitted to one."},["2251"]={"_bene interrogare_","to cross-examine cleverly, put leading questions."},["2260"]={"_facetiis uti, facetum esse_","to make witty remarks."},["2305"]={"_verbum e verbo exprimere_","to translate literally, word for word (not _verbo tenus_)."},["2314"]={"_grammaticus_[3] (De Or. 1. 3. 10)","a linguist, philologian."},["2323"]={"_verbis abundantem esse, abundare_","to be rich in words."},["2332"]={"_inanis verborum sonitus_","mere words; empty sound."},["2341"]={"_verborum concertatio_","an altercation, debate."},["2350"]={"_nominum interpretatio_","etymology (not _etymologia_)."},["2404"]={"_scriptor_ (not _auctor_ = guarantor)","the writer, author."},["2413"]={"_librum mittere ad aliquem_ (Fin. 1. 3. 8)","to dedicate a book to some one."},["2422"]={"_liber qui fertur alicuius_","a book which is attributed to some one."},["2431"]={"_liber, oratio in manibus est_","the book, speech can easily be obtained."},["2440"]={"_se abdere in bibliothecam suam_","to bury oneself in one's library."},["2503"]={"_gaudio, laetitia efferri_","to be beside oneself with joy."},["2512"]={"_dolorem alicui facere, afferre, commovere_","to cause a person pain."},["2521"]={"_callum obducere_[4] _dolori_ (Tusc. 2. 15. 36)","to render insensible to pain."},["2530"]={"_non laborare de aliqua re_","not to trouble oneself about a thing."},["2602"]={"_(animo) paratum esse ad aliquid_","to be resigned to a thing."},["2611"]={"_mente vix constare_ (Tusc. 4. 17. 39)","to compose oneself with difficulty."},["2620"]={"_actum est de me_","it's all over with me; I'm a lost man."},["2701"]={"_admirabilia_ (= παράδοξα)","paradoxes; surprising things."},["2710"]={"_fidem abrogare, derogare alicui_","to rob a person of his credit."},["2800"]={"_ulcisci aliquid, poenas alicuius rei expetere_","to revenge oneself for a thing."},["3007"]={"_aliquid abhorret a meis moribus_ (opp. _insitum [atque innatum] est animo_ or _in animo alicuius_)","something is contrary to my moral sense, goes against my principles."},["3016"]={"_natura et mores; vita moresque; indoles animi ingeniique_; or simply _ingenium, indoles, natura, mores_","character."},["3025"]={"_inferi_ (_Orcus_ and _Tartarus_ only poetical)","the world below."},["3034"]={"_sacris adesse_","to be present at divine service (of the people)."},["3043"]={"_supera et caelestia; humana et citerioria_","heavenly things; earthly things."},["3052"]={"_religionem alicui afferre, inicere, incutere_","to inspire some one with religious scruples."},["3061"]={"_ex animi mei sententia iuro_","I swear on my conscience."},["3070"]={"_deum esse credimus_","we believe in the existence of a God."},["3106"]={"_ture et odoribus incensis_","with incense and perfumes."},["3115"]={"_libare_","to offer libations."},["3124"]={"_mittere Delphos consultum_","to send and consult the oracle at Delphi."},["3133"]={"_aves (alites, oscines)_[3] _addīcunt alicui_ (opp. _abdicunt aliquid_)","the omens are favourable to some one."},["3142"]={"_domus collapsura, corruitura (esse) videtur_","the house threatens to fall in (_vid._ sect. X. 5, note _'Threaten'..._)."},["3151"]={"_tecto, (in) domum suam aliquem recipere_ (opp. _prohibere aliquem tecto, domo_)","to welcome to one's house (opp. to shut one's door against some one)."},["3160"]={"_deducere_[3] _aliquem de domo_","to escort a person from his house."},["3205"]={"_cibum sumere, capere_","to take food."},["3214"]={"_cibus delicatus_","delicacies."},["3223"]={"_exhaurire poculum_","to empty a cup at a draught."},["3232"]={"_copiae cotidianis sumptibus suppetunt_ (_vid._ sect. IV. 2, note _suppeditare..._)","his means suffice to defray daily expenses."},["3241"]={"_sumptui parcere_ (Fam. 16. 4)","to incur few expenses."},["3250"]={"_effundere, profundere pecuniam, patrimonium_","to squander one's money, one's patrimony."},["3304"]={"_in sermonem ingredi_","to begin a conversation."},["3313"]={"_narratio, fabula_","a narrative, tale, story."},["3322"]={"_(ad colloquium) admitti_ (B. C. 3. 57)","to obtain an audience of some one."},["3331"]={"_remotis arbitris_ or _secreto_","in private; tête-à-tête."},["3340"]={"_adscribere alicui salutem_ (Att. 5. 20. 9)","to add to one's letter good wishes to some one."},["3403"]={"_ex consuetudine mea_ (opp. _praeter consuetudinem_)","according to my custom."},["3412"]={"_negotia habere (in Sicilia)_","to have commercial interests in Sicily."},["3421"]={"_magno_ or _male emere_","to buy dearly."},["3430"]={"_nummi adulterini_","bad money; base coin."},["3502"]={"_laborare de pecunia_","to have pecuniary difficulties."},["3511"]={"_aere alieno obrutum, demersum esse_","to be deeply in debt."},["3520"]={"_opus redimere, conducere_","to undertake the contract for a work."},["3601"]={"_saluti rei publicae non deesse_","to further the common weal."},["3610"]={"_omnes curas in rei publicae salute defigere_ (Phil. 14. 5. 13)","to devote one's every thought to the state's welfare."},["3700"]={"_legem ratam esse iubere_","to declare a law valid."},["4006"]={"_nox senatum dirimit_","night breaks up the sitting."},["4015"]={"_in ius, in iudicium vocare aliquem_","to summon some one before the court."},["4024"]={"_aequum iudicem se alicui praebere_","to judge some one equitably."},["4033"]={"_ius nullum_","absence of justice."},["4042"]={"_quaestioni praeesse_","to preside over an inquiry."},["4051"]={"_aliquem testem alicuius rei (in aliquid) citare_","to cite a person to give evidence on a matter."},["4060"]={"_alicui admovere tormenta_","to have a person tortured."},["4105"]={"_sententiam ferre, dicere_ (Off. 3. 16. 66)","to give sentence (of the judge, cf. sect. VI. 4, note _Not..._)."},["4114"]={"_extra culpam esse_","to be free from blame."},["4123"]={"_non committere, ut..._","to take care not to..."},["4132"]={"_poenam petere, repetere ab aliquo_","to exact a penalty from some one."},["4141"]={"_poenam luere (alicuius rei)_ (Sull. 27. 76)","to be punished for a thing, expiate it."},["4150"]={"_capitis_ or _capite damnare aliquem_","to condemn some one to death."},["4204"]={"_exercitatus in armis_","practised in arms."},["4213"]={"_rem frumentariam comparare, providere_","to look after the commissariat."},["4222"]={"_magnum usum in re militari habere_ (Sest. 5. 12)","to possess great experience in military matters."},["4231"]={"_imperii summam tenere_ (Rep. 2. 28)","to be commander-in-chief."},["4240"]={"_arma capere, sumere_","to take up one's arms."},["4303"]={"_agmen agere_","to set the army in motion."},["4312"]={"_iter conficere_ (B. C. 1. 70)","to traverse a route."},["4321"]={"_exercitum admovere, adducere ad..._","to advance on..."},["4330"]={"_novissimos turbare_","to throw the rearguard into confusion."},["4402"]={"_murum nudare defensoribus_","to drive the defenders from the walls."},["4411"]={"_oppugnationem, obsidionem relinquere_","to give up an assault, a siege."},["4420"]={"_oppidum diripere_","to plunder a town."},["4501"]={"_res est in periculo, in summo discrimine_","the position is critical."},["4510"]={"_strictis gladiis in hostem ferri_","to throw oneself on the enemy with drawn sword."},["4600"]={"_victoriam reportare ab hoste_","to gain a victory over the enemy."}} local grc_RWoodhouse_lemma_to_infinitives = { ["εἰσκαλαμάομαι"]={"ἐσκαλαμᾶσθαι"},["ξορρυο"]={"ξορρυερε","ξορρυι"},["ἀνέραμαι"]={"ἀνερασθῆναι"},["διαπτύσσω"]={"διαπτύξαι"},["προσουρέω"]={"προσουρεῖν"},["ὑλοτομέω"]={"ὑλοτομεῖν"}} local la_NLW_headwords_to_path = { ["admonitiuus"]={"2/002874"},["aggressiuus"]={"0/014824"},["ampulositas"]={"3/007263"},["calzarettus"]={"1/020713"},["commodiosus"]={"0/015904"},["commodosius"]={"3/016535"},["corporatura"]={"1/003689"},["crucularius"]={"1/010037"},["diuulgatrix"]={"1/013017"},["epitomarius"]={"1/008433"},["eremitorium"]={"0/005516"},["exinsperato"]={"0/012424"},["exsultantia"]={"0/013940"},["firmatiuius"]={"1/017053"},["florisuccus"]={"1/014473"},["futuribilis"]={"2/011878"},["hydromantis"]={"0/002452"},["inexpetitio"]={"2/008906"},["ingenerosus"]={"2/007310"},["ingrossatio"]={"0/018012"},["interminito"]={"2/021050"},["licentiosus"]={"2/012742"},["ligonizator"]={"2/009258"},["longipeplus"]={"2/009358"},["marranismus"]={"2/015622"},["moselmannus"]={"2/002850"},["moslemannus"]={"2/002850"},["occultatrix"]={"0/014348"},["panduristes"]={"3/008767"},["pastoriceus"]={"2/002182"},["perinfensus"]={"2/009622"},["phrasimimus"]={"1/004473"},["planatorius"]={"1/006689"},["ponticellus"]={"0/017068"},["pontifragus"]={"3/001063"},["praeexiguus"]={"2/015090"},["prataritium"]={"2/021026"},["prensitatio"]={"0/016136"},["principatus"]={"0/003808"},["pudoricolor"]={"1/010585"},["quinquedens"]={"1/005097"},["retrocessio"]={"0/020468"},["retrogradus"]={"2/014654"},["reuisitatio"]={"0/013932"},["semiatratus"]={"0/004064"},["semiconiunx"]={"0/017112"},["semicrassus"]={"2/017122"},["semiremitto"]={"3/021151"},["serpentipes"]={"3/010327"},["sesquimaior"]={"2/009714"},["somnidatrix"]={"3/011415"},["stipulaceus"]={"3/006631"},["suauitatula"]={"1/016057"},["subincensus"]={"1/009041"},["subpoenitet"]={"2/013642"},["superinfero"]={"0/011980"},["suppaenitet"]={"2/013642"},["symphradmon"]={"2/020842"},["thesaurator"]={"3/007227"},["tincturalis"]={"0/015264"},["tormentalis"]={"1/006265"},["transilitio"]={"2/009566"},["tropolepsia"]={"2/011542"},["uermiformis"]={"1/014441"},["uranologium"]={"0/016344"}} local grc_RLBG_lemma_to_index = { ["ἀπροσωποληπτέω"]={"8564"},["Γηβοβασίλευτος"]={"14043"},["ἐνζωογονέομαι"]={"23141"},["ζώηχος"]={"29452"},["κόμπος"]={"38397"},["κομπός"]={"38398"},["λιτεύω"]={"41979"},["λόφωμα"]={"42299"},["περισμιλευτέον"]={"56215"},["πολυμετάβλητος"]={"58570"},["προδιακωδωνίζω"]={"60236"},["ἀειμάκαρ"]={"1113"},["ἀθελησία"]={"1284"},["ἀκανθίας"]={"1806"},["ἀκούφιον"]={"2129"},["ἀνάδεσμα"]={"3556"},["ἀνάδιπλα"]={"3564"},["ἀνώφλιον"]={"6500"},["βραχύπους"]={"13187"},["δελφῖνος"]={"15391"},["ἐμετικόν"]={"22043"},["ἐμμύακος"]={"22101"},["ἐναύριον"]={"22842"},["ἔξομβρος"]={"24538"},["ἐπεύκιον"]={"25358"},["ἡμίγυρον"]={"29845"},["ἡμιπέλυξ"]={"29911"},["ἡπλησίον"]={"30060"},["θεωρεῖον"]={"31122"},["κατατυπόω"]={"36065"},["κοσμοψυχοσωτήριος"]={"38919"},["ὀγκινάρα"]={"48670"},["πάμψυχρος"]={"52159"},["παρανύττω"]={"53547"},["παρῴδημα"]={"54535"},["παυστικός"]={"54804"},["ἀγριόμορφος"]={"640"},["ἀποφλητικός"]={"8360"},["ἐδαφιστικός"]={"19946"},["ἐκλαμπρότης"]={"20942"},["ἐκπιαστικός"]={"21186"},["ἐμβροντήτως"]={"22017"},["ἐμπατταλεύω"]={"22167"},["ἐξιστουργέω"]={"24445"},["ἐρυθροποιέω"]={"27308"},["ἑτεροκλήτως"]={"27590"},["εὐοχέτευτος"]={"28368"},["θησαυροπλουτόχρηστος"]={"31286"},["κεντονάριον"]={"36927"},["μελαμπόδιον"]={"43973"},["ὀλεθριόφρων"]={"49202"},["ὀξυθεώρητος"]={"50201"},["ὀργανόφωνος"]={"50481"},["πολυδέμνιον"]={"58304"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["ai"]={"4822"},["matrimonium"]={"3355","3360","3361"},["principatus"]={"2070","3666","3667","3668","3842"},["locupletior"]={"2278"}} local grc_RCunliffe_lemma_to_index = { ["ἠμαθόεις"]={"4565"},["πολλός"]={"7890"},["θρόνος"]={"4855"},["ἔντοσθεν"]={"3286"},["κόμπος"]={"5699"},["ἀναφανδά"]={"797"}} local grc_RWoodhouse_lemma_to_headwords = { ["θρόνος"]={"chair","dais","rule","sceptre","seat","throne"},["κομπός"]={"boaster","brag","ranter","vaunter"},["κόμπος"]={"bluster","boast","bravado","idle","ostentation","rhapsody","vapouring","vaunt"},["πώλοις"]={"apply"},["τεθωρακισμένος"]={"arm","coat","mail-clad"},["τομεύς"]={"knife","scalpel"},["Παγγαῖος"]={"pangaeus (mt.)"},["αἵρεσθαι"]={"set"},["εἰρωνεία"]={"dissimulation","hypocrisy","irony"},["πρόσταξις"]={"assessment"},["ἀσέλγημα"]={"debauchery"},["ἐμπόδιον"]={"curb","handicap","tie","trammel"},["ἔμμισθος"]={"hired","pay","pensionary","pensioner","salaried"},["ὀργάζειν"]={"knead","soften","work"},["Ξενοκλείδας"]={"xenocleidas"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} 369bgxazokprnn6o4pnrzc6tfbyv90j Module:data tables/dataM210 828 38994 178504 2026-10-27T06:02:36Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1089"]={"_alicui petenti satisfacere, non deesse_","to accede to a man's petitions."},["1098"]={"_ex sententia_","as one would wish; to one's mind."},["1179"]={"_efferre_ or _edere aliquid in vulgus_","to divulge, make public."},["1188"]={"_mentionem inicere de aliqua re_ or Acc. c. Inf.","to mention a thing incidentally, casually."},["1197"]={"_clarum fieri, nobilitari, illustrari_ (not the post-classical...' 178504 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1089"]={"_alicui petenti satisfacere, non deesse_","to accede to a man's petitions."},["1098"]={"_ex sententia_","as one would wish; to one's mind."},["1179"]={"_efferre_ or _edere aliquid in vulgus_","to divulge, make public."},["1188"]={"_mentionem inicere de aliqua re_ or Acc. c. Inf.","to mention a thing incidentally, casually."},["1197"]={"_clarum fieri, nobilitari, illustrari_ (not the post-classical _clarescere_ or _inclarescere_","to become famous, distinguish oneself."},["1269"]={"_negotia agere, gerere_","to be occupied with business, busy."},["1278"]={"_in otio esse_ or _vivere_","to be at leisure."},["1287"]={"_desidiae et languori se dedere_","to abandon oneself to inactivity and apathy."},["1296"]={"_voluptatis illecebris deleniri_","to be led astray, corrupted by the allurements of pleasure."},["1359"]={"_species optima_ or _eximia, specimen_, also simply _species, forma_","an ideal."},["1368"]={"_a sententia sua discedere_","to give up one's opinion."},["1377"]={"_sententiam fronte celare, tegere_","not to betray one's feelings by one's looks."},["1386"]={"_opinionibus falsis imbui_","to be imbibing false opinions."},["1395"]={"_coniecturam alicuius rei facere_ or _capere ex aliqua re_","to infer by comparison, judge one thing by another."},["1449"]={"_certo (certe) scio_[1] (Arch. 12. 32)","I know for a fact."},["1458"]={"_mihi exploratum est, exploratum (certum) habeo_","I am quite certain on the point."},["1467"]={"_non possum adduci, ut (credam)_","I cannot make myself believe that..."},["1476"]={"_suo consilio uti_[1]","to go one's own way, proceed independently."},["1485"]={"_auctorem esse alicui, ut_","to give a person advice."},["1494"]={"_agitare (in) mente_ or _(in) animo aliquid_","to think over, consider a thing."},["1539"]={"_memoriā (multum) valere_ (opp. _memoriā vacillare_)","to have a good memory."},["1548"]={"_memoriam alicuius rei repetere_","to recall to mind a thing or person."},["1557"]={"_gratam (gratissimam) alicuius memoriam retinere_","to retain a (most) pleasant impression of a person."},["1566"]={"_memoriae causa, ad_ (not _in_) _memoriam_[3] (Brut. 16. 62)","in memory of..."},["1575"]={"_oblivione obrui, deleri, exstingui_","to be forgotten, pass into oblivion."},["1584"]={"_magnum usum in aliqua re habere_","to have had great experience in a thing."},["1593"]={"_optima studia, bonae, optimae, liberales, ingenuae artes, disciplinae_","the sciences; the fine arts."},["1629"]={"_omnes docti, quivis doctus, doctissimus quisque_","all learned men."},["1638"]={"_studia, quae in reconditis artibus versantur_ (De Or. 1. 2. 8)","abstruse studies."},["1647"]={"_multarum rerum cognitione imbutum esse_ (opp. _litterarum_ or _eruditionis expertem esse_ or _[rerum] rudem esse_)","to be well-informed, erudite."},["1656"]={"_omnis cultus et humanitatis expertem esse_[1]","to be quite uncivilised."},["1665"]={"_litteras discere ab aliquo_","to be educated by some one."},["1674"]={"_scholam frequentare_","to go to a school."},["1683"]={"_crassa_ or _pingui Minerva_ (proverb.)","with no intelligence or skill."},["1692"]={"_adulescens bonae (egregiae) spei_","a promising youth."},["1719"]={"_sibi exemplum alicuius proponere ad imitandum_ or simply _sibi aliquem ad imitandum proponere_","to set up some one as one's ideal, model."},["1728"]={"_ad praecipiendi rationem delābi_ (Q. Fr. 1. 1. 6. 18)","to adopt a didactic tone."},["1737"]={"_in sinum philosophiae compelli_","to be driven into the arms of philosophy."},["1746"]={"_schola, disciplina, familia; secta_","a sect, school of thought."},["1755"]={"_audire Platonem, auditorem esse Platonis_","to attend Plato's lectures."},["1764"]={"_disserendi artem nullam habere_","to know nothing of logic."},["1773"]={"_ad artem redigere aliquid_","to systematise."},["1782"]={"_novam rationem ingredi_","to enter on a new method."},["1791"]={"_rem (res) definire_","to define a thing."},["1809"]={"_argumento huic rei est, quod_","a proof of this is that..."},["1818"]={"_concludere, colligere, efficere, cogere ex aliqua re_","to draw a conclusion from a thing."},["1827"]={"_sequitur_ (not _ex quo seq._) _ut_","it follows from this that..."},["1836"]={"_opponere alicui aliquid_","to object, to adduce in contradiction."},["1845"]={"_in controversia relinquere aliquid_","to leave a point undecided."},["1854"]={"_hoc est a (pro) me_","this goes to prove what I say."},["1863"]={"_uno, communi, summo_ or _omnium consensu_ (Tusc. 1. 15. 35)","unanimously."},["1872"]={"_a se dissidere_ or _sibi non constare_ (of persons)","to contradict oneself, be inconsistent."},["1881"]={"_res populi Romani perscribere_","to write a history of Rome."},["1890"]={"_duplex est memoria de aliqua re_","a twofold tradition prevails on this subject."},["1908"]={"_narrare aliquid ad fidem historiae_","to give a veracious and historic account of a thing."},["1917"]={"_servare et notare tempora_","to observe the chronological order of events."},["1926"]={"_mathematicorum ratione concludere aliquid_","to draw a mathematical conclusion."},["1935"]={"_opus summo artificio[TR1] factum_","a master-piece of classical work."},["1944"]={"_in existimantium arbitrium venire_ (Brut. 24. 92)","to come before the tribunal of the critics."},["1953"]={"_aliquid ad verum exprimere_","to make a copy true to nature."},["1962"]={"_poeta scaenicus_","a dramatic poet."},["1971"]={"_se conferre ad poesis studium_","to devote oneself to poetry."},["1980"]={"_nervorum et tibiarum cantus_","instrumental music."},["2079"]={"_oratio accurata_[2] _et polita_","a carefully prepared speech."},["2088"]={"_accommodate ad persuadendum dicere_","to be a persuasive speaker."},["2097"]={"_animos tenere_","to rivet the attention of..."},["2169"]={"_rem paucis absolvere_ (Sall. Iug. 17. 2)","to explain a matter briefly, in a few words (not _paucis verbis_)."},["2178"]={"_significatione appellare aliquem_","to allude to a person or thing (not _alludere_)."},["2187"]={"_inserere orationi aliquid_","to interpolate, insert something."},["2196"]={"_accedere ad cotidiani sermonis genus_","to adopt the language of everyday life."},["2259"]={"_facete dicere_","to be witty."},["2268"]={"_(homo) ridiculus_ (Plaut. Stich. 1. 3. 21)","a wit; a joker."},["2277"]={"_nimium diligentem esse_[1]","to be pedantic."},["2286"]={"_consuetudo sermonis, loquendi_","to usage of language."},["2295"]={"_graece_ or _graeca lingua loqui_","to speak the Greek language."},["2349"]={"_verba parere, fingere, facere_","to invent, form words."},["2358"]={"_quae est vis huius verbi?_","what is the meaning, the original sense of this word?"},["2367"]={"_vocabulum latius patet_","the word has a more extended signification."},["2376"]={"_verbum translatum_ (Or. 27. 92)","a figurative expression; a word used metaphorically."},["2385"]={"_ut_ or _quod_ or _quomodo aiunt, ut_ or _quemadmodum dicitur_","as the proverb says."},["2394"]={"_oriri a longa_ (De Or. 1. 55. 236)","to begin with a long syllable."},["2439"]={"_librum annotare, interpolare, distinguere_","to furnish a book with notes, additional extracts, marks of punctuation."},["2448"]={"_in Platonis Phaedone scriptum est_","in Plato's 'Phaedo' we read."},["2457"]={"_mendosum esse_ (Verr. 2. 4. 77)","(1) to make frequent mistakes in writing; (2) to be full of mistakes (speaking of a passage)."},["2466"]={"_litteras inter se dare et accipere_","to be in correspondence with..."},["2475"]={"_Kalendis Ianuariis Romā (dabam)_","Rome, January 1st."},["2484"]={"_aliqua re moveri, commoveri_","to be moved by a thing."},["2493"]={"_afferre alicui laetitiam_","to give pleasure to some one."},["2529"]={"_nihil omnino curare_","not to trouble oneself about a thing."},["2538"]={"_rebus suis, sorte sua contentum esse_","to be contented."},["2547"]={"_magnum luctum haurire_ (without _ex-_)","to undergo severe trouble, trials."},["2556"]={"_metus aliquem exanimat_ (Mil. 24. 65)","a man is paralysed with fear."},["2565"]={"_in terrorem conicere aliquem_","to overwhelm some one with terror."},["2574"]={"_animum recipere_ (Liv. 2. 50)","to take courage again."},["2583"]={"_animos militum accendere_","to fire with courage."},["2592"]={"_magnos spiritus sibi sumere_ (B. G. 1. 33)","to be haughty."},["2619"]={"_quid (de) me fiet?_ (Ter. Heaut. 4. 3. 37)","what will become of me?"},["2628"]={"_spem redintegrare_ (B. G. 7. 25)","to revive a hope."},["2637"]={"_spem praecīdere, incidere_ (Liv. 2. 15)","to cut off all hope."},["2646"]={"_spem alicui_ or _alicuius minuere_","to weaken, diminish a person's hope."},["2655"]={"_exspectationi satisfacere, respondere_","to respond to expectations."},["2664"]={"_misericordiam implorare_","to implore a person's sympathy, pity."},["2673"]={"_crudelitatem exercere in aliquo_","to exercise one's cruelty on some one."},["2682"]={"_aliquem toto pectore,_[1] _ut dicitur, amare_ (Leg. 18. 49)","to love some one very dearly, with all one's heart."},["2691"]={"_curae habere aliquid_","to have laid something to heart; to take an interest in a thing."},["2709"]={"_fidem tribuere, adiungere alicui rei_","to believe in, trust in a thing."},["2718"]={"_fidem colere, servare_","to preserve one's loyalty."},["2727"]={"_in fidem recipere aliquem_ (B. G. 2. 15. 1)","to take a person under one's protection."},["2736"]={"_fidem prodere_","to break one's word."},["2745"]={"_suspicionem habere de aliquo_","to suspect a person."},["2754"]={"_suspicio ei penitus inhaeret_","he is in a suspicious mood."},["2763"]={"_invidia flagrare, premi_","to be detested."},["2772"]={"_capitali odio dissidere ab aliquo_ (De Am. 1. 2)","to be separated by a deadly hatred."},["2781"]={"_indignitas, atrocitas rei_ (Mur. 25. 51)","the revolting nature of an action."},["2790"]={"_iram in aliquem effundere_","to vent one's anger, spite on some one."},["2808"]={"_indignationes_ (Liv. 25. 1. 9)","signs of irritation, of discontent."},["2817"]={"_nihil ex pristina virtute remittere_","to live as scrupulously moral a life as ever."},["2826"]={"_bonitas_ (Fin. 5. 29. 65)","kindheartedness."},["2835"]={"_vita omnibus flagitiis,_[1] _vitiis dedita_","a life defiled by every crime."},["2844"]={"_scelus scelere cumulare_ (Catil. 1. 6. 14)","to heap crime on crime."},["2853"]={"_se (totum) libidinibus dedere_","to abandon oneself (entirely) to debauchery."},["2862"]={"_coercere, cohibere, continere, domitas habere cupiditates_","to overcome one's passions."},["2871"]={"_animi perturbationes exstirpare_","to eradicate passion from the mind."},["2880"]={"_ab iniuria aliquem defendere_","to protect any one from wrong."},["2907"]={"_denuntiare_[1] _bellum, caedem_ (Sest. 20. 46)","to threaten war, carnage."},["2916"]={"_per simulationem, simulatione alicuius rei_","under pretext, pretence of..."},["2925"]={"_mendacium dicere_","to tell lies."},["2934"]={"_officio suo satisfacere_ (Div. in Caec. 14. 47)","to do one's duty."},["2943"]={"_ad officium redire_","to return to one's duties."},["2952"]={"_litterae officii_ or _humanitatis plenae_","a most courteous letter."},["2961"]={"_sapere_ (Off. 2. 14. 48)","to be a man of sense, judgment."},["2970"]={"_conscientia mala_ or _peccatorum, culpae, sceleris, delicti_","a guilty conscience."},["3069"]={"_opinio dei_","belief in god."},["3078"]={"_superstitione imbutum esse_","to be tinged with superstition."},["3087"]={"_praeire verba (carmen)_ (Liv. 31. 17)","to read prayers for the congregation to repeat."},["3096"]={"_quod di immortales omen avertant!_ (Phil. 44. 11)","and may heaven avert the omen! heaven preserve us from this!"},["3159"]={"_domi se tenere_","to never appear in public."},["3168"]={"_rem domesticam, familiarem administrare, regere, curare_","to keep house."},["3177"]={"_severum imperium in suis exercere, tenere_ (De Sen. 11. 37)","to be a strict disciplinarian in one's household."},["3186"]={"_fundi_","property in land; real property."},["3195"]={"_induere vestem_ (without _sibi_)","to dress oneself."},["3249"]={"_in luxuriam effundi_","to plunge into excesses, a career of excess."},["3258"]={"_ab ovo usque ad mala_ (proverb.)[1]","from beginning to end."},["3267"]={"_accipere aliquem (bene, copiose, laute, eleganter, regio apparatu, apparatis epulis)_","to entertain, regale a person."},["3276"]={"_invitare aliquem tecto ac domo_ or _domum suam_ (Liv. 3. 14. 5)","to invite some one to one's house."},["3285"]={"_alicuius familiaritate uti_","to be on intimate terms with some one."},["3294"]={"_in simultate cum aliquo sum_","relations are strained between us."},["3339"]={"_nuntia fratri tuo salutem verbis meis_ (Fam. 7. 14)","remember me to your brother."},["3348"]={"_gratulari alicui aliquid_ or _de aliqua re_","to congratulate a person on something."},["3357"]={"_nuptam esse cum aliquo_ or _alicui_","to be married to some one."},["3366"]={"_aliquam suas res sibi habere_[1] _iubere_ (Phil. 2. 28. 69)","to separate from, divorce (of the man)."},["3375"]={"_pecuniam alicui legare_","to leave money to a person in one's will."},["3384"]={"_hereditatem adire, cernere_","to take possession of an inheritance."},["3393"]={"_a vetere consuetudine discedere_","to give up old customs."},["3429"]={"_argentum (factum)_ (Verr. 5. 25. 63)","silver plate."},["3438"]={"_pecuniam fenore occupare_ (Flacc. 21. 54)","to put out money at interest."},["3447"]={"_nummus iactatur_ (Off. 3. 20. 80)","the bank-rate varies."},["3456"]={"_pecunia in nominibus_[1] _est_","money is outstanding, unpaid."},["3465"]={"_ratio acceptorum et datorum (accepti et expensi)_ (Amic. 16. 58)","the account of receipts and expenditure."},["3474"]={"_ternae centesimae_","36 per cent per annum."},["3483"]={"_quincunces usurae_","5 per cent."},["3492"]={"_in lucro ponere aliquid_ (Flacc. 17. 40)","to consider a thing as profit."},["3519"]={"_opus locare_","to contract for the building of something."},["3528"]={"_inicere pontem_","to build a bridge over a river."},["3537"]={"_in agris esse, habitare_","to live in the country."},["3546"]={"_frumenta in agris matura non sunt_ (B. G. 1. 16. 2)","the corn is not yet ripe."},["3555"]={"_annona ingravescit, crescit_","the price of corn is going up."},["3564"]={"_pascere gregem_","to feed a flock (of goats)."},["3573"]={"_civitati leges, iudicia, iura describere_","to give the state a constitution."},["3582"]={"_clavum rei publicae tenere_","to hold the reins of government."},["3591"]={"_rei publicae deesse_ (opp. _adesse_)","to take no part in politics."},["3609"]={"_omnes curas et cogitationes in rem publicam conferre_","to devote one's every thought to the state's welfare."},["3618"]={"_prudentia (civilis)_ (De Or. 1. 19. 85)","statesmanship; political wisdom."},["3627"]={"_in civitatem recipere, ascribere, asciscere aliquem_","to enroll as a citizen, burgess."},["3636"]={"_summo loco natus_","of high rank."},["3645"]={"_homo plebeius, de plebe_","one of the people."},["3654"]={"_dignitati suae servire, consulere_","to be careful of one's dignity."},["3663"]={"_amplissimos honorum gradus assequi, adipisci_","to reach the highest grade of office."},["3672"]={"_agere cum populo_[1] (Leg. 3. 4. 10)","to submit a formal proposition to the people."},["3681"]={"_legem ferre_ or simply _ferre ad populum, ut..._","to propose a law in the popular assembly."},["3690"]={"_legem sancire_","to let a bill become law (of the people and senate)."},["3708"]={"_qui leges scribit_ (not _legum lator_)[5]","a legislator."},["3717"]={"_populi favor, gratia popularis_","popular favour; popularity."},["3726"]={"_gratiam inire apud aliquem, ab aliquo_ (cf. sect. V. 12)","to gain some one's favour."},["3735"]={"_invidia dictatoria_ (Liv. 22. 26)","the feeling against the dictator."},["3744"]={"_consiliorum in re publica socius_","a political ally."},["3753"]={"_medium esse_","to be neutral."},["3762"]={"_imperium singulare, unius dominatus, regium imperium_","monarchy."},["3771"]={"_homines graves_ (opp. _leves_)","men of sound opinions."},["3780"]={"_plebis dux, vulgi turbator, civis turbulentus, civis rerum novarum cupidus_","a demagogue, agitator."},["3807"]={"_leges nullae_","lawlessness; anarchy."},["3816"]={"_in proscriptorum numerum referre aliquem_ (Rosc. Am. 11. 32)","to place a person's name on the list of the proscribed."},["3825"]={"_patria carere_","to be in exile."},["3834"]={"_in patriam redire_","to return from exile."},["3843"]={"_cum imperio esse_ (cf. XVI. 3)","to have unlimited power; to be invested with _imperium_."},["3852"]={"_potestas immoderata, infinita_","despotic, tyrannous rule."},["3861"]={"_aliquem regno spoliare_ or _expellere_ (Div. 1. 22. 74)","to depose a king."},["3870"]={"_aliquem in servitutem abducere, abstrahere_","to carry off into slavery."},["3906"]={"_provincias sortiri_ (Liv. 38. 35)","to draw lots for the provinces."},["3915"]={"_nomen profiteri_ or simply _profiteri_","to become a candidate."},["3924"]={"_sufficere aliquem in alicuius locum_ or _alicui_","to elect a man to fill the place of another who has died whilst in office."},["3933"]={"_munus administrare, gerere_","to perform official duties."},["3942"]={"_res ad interregnum venit_ or _adducitur_","an interregnum ensues."},["3951"]={"_bis consul_","twice consul."},["3960"]={"_dictaturam gerere_","to be dictator."},["4059"]={"_testibus teneri, convictum esse_","to be convicted by some one's evidence."},["4068"]={"_causam dicere, orare_ (Brut. 12. 47)","to address the court (of the advocate)."},["4077"]={"_indicta causa_ (opp. _cognita causa_)","without going to law."},["4086"]={"_accusatio_ (Cael. 3. 6)","a criminal accusation."},["4095"]={"_caput alicuius agitur_ (_vid._ sect. V. 8)","a person's life is in jeopardy."},["4149"]={"_in carcerem conicere aliquem_","to throw some one into prison."},["4158"]={"_virgis caedere_","to beat with rods."},["4167"]={"_qui per aetatem arma ferre non possunt_ or _aetate ad bellum inutiles_","men exempt from service owing to age."},["4176"]={"_excusare morbum, valetudinem_","to plead ill-health as an excuse for absence."},["4185"]={"_complere legiones_ (B. C. 1. 25)","to fill up the numbers of the legions."},["4194"]={"_dimittere exercitum_","to disband an army."},["4239"]={"_milites coercere et in officio continere_ (B. C. 1. 67. 4)","to keep good discipline amongst one's men."},["4248"]={"_extorquere arma e manibus_","to wrest weapons from some one's hands."},["4257"]={"_gladium stringere, destringere_","to draw one's sword."},["4266"]={"_res repetere (ab aliquo)_ (Off. 1. 11. 36)","to demand satisfaction, restitution."},["4275"]={"_bello implicari_","to be involved in a war."},["4284"]={"_bellum inferre alicui_ (Att. 9. 1. 3)","to invade."},["4293"]={"_bellum componere_ (Fam. 10. 33)","to terminate a war (by a treaty, etc.)"},["4329"]={"_novissimos premere_","to press the rearguard."},["4338"]={"_praeoccupare locum_ (Liv. 35. 27)","to occupy a place beforehand."},["4347"]={"_castra hiberna, aestiva_","winter-quarters, summer-quarters."},["4356"]={"_castra praesidiis firmare_","to strengthen the camp by outposts."},["4365"]={"_tesseram dare_ (Liv. 28. 14)","to give the watchword, countersign."},["4374"]={"_pabulatione premi_ (B. C. 1. 78)","to suffer from want of forage."},["4383"]={"_oppidum manu (opere) munitum_","a town artificially fortified."},["4392"]={"_turres instituere, exstruere_","to raise towers."},["4419"]={"_oppidum incendere_","to fire a town."},["4428"]={"_se permittere in fidem atque in potestatem alicuius_ (B. G. 2. 3)","to surrender oneself to the discretion of some one."},["4437"]={"_supersedere proelio_","to refrain from fighting."},["4446"]={"_ad vim et arma descendere_ (_vid._ sect. V. 9, note _Similarly..._)","to have recourse to force of arms."},["4455"]={"_contionari apud milites_ (B. C. 1. 7)","to harangue the soldiers."},["4464"]={"_proelium facere secundum_","to fight successfully."},["4473"]={"_acie (armis, ferro) decernere_","to fight a pitched battle."},["4482"]={"_gradum inferre in hostem_","to march on the enemy."},["4491"]={"_signa conferre cum hoste_[3]","to come to close quarters."},["4509"]={"_res gladiis geri coepta est_","swords must now decide the day."},["4518"]={"_equitatu superiorem esse_","to have the advantage in cavalry."},["4527"]={"_rari dispersique pugnare_ (B. C. 1. 44)","to fight in skirmishing order."},["4536"]={"_signa receptui canunt_","the retreat is sounded."},["4545"]={"_caedere et fundere hostem_","to utterly rout the enemy."},["4554"]={"_se conicere, se conferre in fugam_","to take to flight."},["4563"]={"_hostes assequi, consequi_","to overtake the enemy."},["4572"]={"_eripere aliquem e manibus hostium_","to rescue some one from the hands of the enemy."},["4581"]={"_hostes ad internecionem caedere, delere_ (Liv. 9. 26)","to absolutely annihilate the enemy."},["4590"]={"_refricare_[1] _vulnus, cicatricem obductam_","to open an old wound."},["4608"]={"_triumphum_[1] _agere de_ or _ex aliquo_ or c. Gen. (_victoriae, pugnae_)","to triumph over some one."},["4617"]={"_pacem dirimere, frangere_","to break the peace."},["4626"]={"_captivos sine pretio reddere_","to restore prisoners without ransom."},["4635"]={"_a senatu amicus_[1] _appellatus est_ (B. G. 1. 3)","he received from the senate the title of friend."},["4644"]={"_in deditionem venire_ (without _alicui_)","to make one's submission to some one."},["4653"]={"_Asiam in provinciae formam (in provinciam) redigere_ (B. G. 1. 45)","to make Asia into a Roman province."},["4662"]={"_rebus maritimis multum valere_","to have a powerful navy."},["4671"]={"_classiarii_[1] (B. C. 3. 100)","marines."},["4680"]={"_vela in altum dare_ (Liv. 25. 27)","to put to sea."},["4707"]={"_appelli (ad oram)_ (Att. 13. 21)","to land (of ships)."},["4716"]={"_exire, egredi in terram_","to land, disembark."},["4725"]={"_navem rostro percutere_","to charge, ram a boat."},["4734"]={"_navigia speculatoria_","reconnoitring-vessels."},["4743"]={"_denique_","in short; to be brief."},["4752"]={"_ne diutius vos demorer_","not to be prolix."},["4761"]={"_tantum_ or _unum illud_ or _hoc dico_","I will only say this much..."},["4770"]={"_incredibile dictu est_","it sounds incredible."},["4806"]={"_hoc sua sponte appāret_","that is self-evident, goes without saying."},["4815"]={"_quod maius est_","what is more important."},["4824"]={"_quorsum haec (dicis)?_","what do you mean?"},["4833"]={"_res ita (aliter) se habet_","the matter stands so (otherwise)."},["4842"]={"_iusto iure_","with perfect right."}} local grc_RWoodhouse_lemma_to_infinitives = { ["ἀνακαλέω"]={"ἀγκάλην","ἀνακαλέσασθαι","ἀνακαλεῖν","ἀνακαλεῖσθαι","ἀνακληθῆναι"},["ἀποπρίασθαι"]={"ἀποπρίασθαι"},["εϝερτο"]={"ευερτερε","ευερτισσε","εϝερτερε","εϝερτι","εϝερτισσε"},["συνεπακολουθέω"]={"συνεπακολουθῆσαι"}} local la_NLW_headwords_to_path = { ["abstersiuus"]={"2/006578"},["anniusculus"]={"3/018767"},["aspersorium"]={"0/018440"},["auctorculus"]={"2/006434"},["circumsulto"]={"1/015757"},["complurimum"]={"3/014003"},["constrepito"]={"3/005947"},["contribulus"]={"0/000344"},["desuctorius"]={"0/004524"},["exorcizator"]={"1/005073"},["exspoliator"]={"3/011759"},["frondisonus"]={"1/016081"},["gustamentum"]={"0/012788"},["hedyglossus"]={"1/013689"},["immultiplex"]={"2/007702"},["immuneratus"]={"0/005976"},["insuauitudo"]={"1/007329"},["intermixtim"]={"1/007849"},["intermorior"]={"1/000749"},["narratorius"]={"2/005210"},["oculatorius"]={"2/019794"},["omnigerulus"]={"0/005092"},["oristergium"]={"0/016720"},["pectusculum"]={"3/000979"},["perdisertus"]={"3/006431"},["peropposite"]={"3/010323"},["perturbator"]={"1/003449"},["peruulgator"]={"2/015722"},["philargyrus"]={"2/004642"},["plantatiuus"]={"1/016589"},["postergator"]={"0/021508"},["pseudologus"]={"3/001583"},["quakerismus"]={"3/014751"},["recommissus"]={"3/001179"},["semiperitus"]={"2/014278"},["semiulnatus"]={"1/004101"},["subhorridus"]={"1/019005"},["subinsimulo"]={"0/005732"},["subtrepidus"]={"3/013567"},["sycophantor"]={"1/014213"},["sympathicus"]={"1/019773"},["syncriticos"]={"2/002954"},["titillatrix"]={"1/009085"},["transuector"]={"2/016198"},["uaporositas"]={"0/014052"},["unitrinitas"]={"2/007658"},["uoluminitas"]={"3/007567"}} local grc_RLBG_lemma_to_index = { ["ἀνεβαίνω"]={"4459"},["δυσπαρακολουθήτως"]={"19034"},["δυσωπικός"]={"19215"},["ἐκτόκιον"]={"21471"},["ἔξομπλος"]={"24554"},["ἐπίβαλμα"]={"25406"},["εὔμουσον"]={"28308"},["ἡδύανθος"]={"29609"},["ἱππίδιον"]={"32382"},["κασσωρεύω"]={"34778"},["κυπρισμός"]={"40224"},["μεταχαρακτηρισμός"]={"44914"},["μετόπωρις"]={"45042"},["μιονῖτις"]={"45520"},["οὔλτιμος"]={"51127"},["παγκλεῶς"]={"51576"},["παντρόφος"]={"52851"},["πηρωτικός"]={"56896"},["προϊσχάνω"]={"60795"},["προρριζόω"]={"61508"},["προσιδρόω"]={"62498"},["αἱρεσίαρχος"]={"1613"},["αἰσχροπαθής"]={"1659"},["ἁμαξοτροχός"]={"2929"},["ἀναγραπτέος"]={"3531"},["ἀποψυχόομαι"]={"8452"},["Ἀρμενόσυροι"]={"9038"},["ἀρχαιοπαγής"]={"9358"},["αὐτοδώρητος"]={"10665"},["αὐτόμεμπτος"]={"10795"},["εἰσκαρτερέω"]={"20372"},["εἰσσφραγίζω"]={"20446"},["ἐνασχόλησις"]={"22822"},["ἐνδιαστόλως"]={"22939"},["ἐνθαυμαστόω"]={"23177"},["ἐντύμβευσις"]={"23707"},["ἐξωκουρίτις"]={"24752"},["Θεοδοσιανοί"]={"30569"},["ἰχθυόμορφος"]={"32816"},["καπνολόγιον"]={"34446"},["κουκονάριον"]={"39003"},["μελανδόχιον"]={"43984"},["παλμολόγιον"]={"52019"},["πλαγιούνιον"]={"57224"},["ἀκατευστόχητος"]={"1938"},["ἀνθρωπόπλαστος"]={"5051"},["ἀπεριφρούρητος"]={"7142"},["βρονταντίπνοος"]={"13302"},["γρηγορόφθαλμος"]={"14686"},["ζυμώνω"]={"29406"},["καλοπολίτευτος"]={"34007"},["καπρία"]={"34478"},["κατακρημνισμός"]={"35247"},["κυρμανουηλάτος"]={"40294"},["λουτροκάνθαρος"]={"42283"},["λόχμος"]={"42314"},["μεταχειροτονέω"]={"44921"},["μορόξυ"]={"46219"},["μόχλος"]={"46456"},["νοτεύω"]={"47962"},["παιδοποιητικός"]={"51723"},["πέραμα"]={"55405"},["πολιορκητήριος"]={"58127"},["προσεπινοητέον"]={"62287"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["em"]={"1232"},["inveteratus"]={"1389","2776"},["trientarius"]={"3481"}} local grc_RCunliffe_lemma_to_index = { ["σκόλοψ"]={"8478"},["μοχλός"]={"6543"},["πέπηγε"]={"7562"}} local grc_RWoodhouse_lemma_to_headwords = { ["Καδμεῖος"]={"cadmus","thebes (in boeotia)"},["βαρύψυχος"]={"dejected","spiritless"},["διαπερᾶν"]={"cross","ford","go","pass","penetrate","pierce","plough","surmount","thread","through","transfix","traverse"},["κουρεῖον"]={"barber's shop"},["σφοδρότης"]={"acuteness","boisterousness","demonstrativeness","energy","excitability","fervour","fire","glow","heat","impatience","impetuosity","impulsiveness","intensity","irascibility","lustiness","passion","passionateness","poignancy","strenuousness","vehemence","violence","warmth"},["ὀλίσθημα"]={"slip"},["ὀφείλημα"]={"claim","debt"},["Οὐολοῦσκοι"]={"volsci"},["καταδείδειν"]={"dread","fear"},["ψυχορραγεῖν"]={"dying","gasp"},["ἀνωνόμαστος"]={"indescribable","ineffable","nameless","unspeakable","unutterable"},["Ἀτραμύττιον"]={"adramyttium"},["Κολχίς"]={"colchis"},["Λυκάων"]={"lycaon"},["βράχεα"]={"shoals"},["κομψός"]={"clever","coxcomb","dainty","dandified","dandy","deft","delicate","elegant","exquisite","fanciful","finical","laboured","mincing","neat","nice","pretty","refined","smart","subtle","trim"},["μοχλός"]={"bar","bolt","catch","crow-bar","fastening","lever","lock"},["νύχιος"]={"nightly"},["παρειά"]={"cheek"},["σκόλοψ"]={"cross","gibbet","pale","pile","post","stake"},["συμβουλεύεσθαι"]={"consult"},["φραδαί"]={"clue","hint","warning"},["Ῥῆσος"]={"rhesus"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} r279wtiplht7r2dk26h0ep6yqn4pakm Module:data tables/dataM203 828 38995 178505 2026-10-27T06:03:31Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1019"]={"_iacturam_[3] _alicuius rei facere_","to throw away, sacrifice."},["1028"]={"_benevolo animo esse in aliquem_","to be well-disposed towards..."},["1037"]={"_gratiam inire ab aliquo_or _apud aliquem_","to gain a person's esteem, friendship."},["1046"]={"_se conformare, se accommodare ad alicuius voluntatem_","to accomodate oneself to another's wishes."},["1055"]={"_beneficium remunerari_ or _reddere...' 178505 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1019"]={"_iacturam_[3] _alicuius rei facere_","to throw away, sacrifice."},["1028"]={"_benevolo animo esse in aliquem_","to be well-disposed towards..."},["1037"]={"_gratiam inire ab aliquo_or _apud aliquem_","to gain a person's esteem, friendship."},["1046"]={"_se conformare, se accommodare ad alicuius voluntatem_","to accomodate oneself to another's wishes."},["1055"]={"_beneficium remunerari_ or _reddere (cumulate)_","to (richly) recompense a kindness or service."},["1064"]={"_paria paribus respondere_","to return like for like."},["1073"]={"_ex, pro merito_","according to a man's deserts."},["1082"]={"_pacta merces alicuius rei_","the stipulated reward for anything."},["1091"]={"_negare_, more strongly _denegare alicui aliquid_","to refuse, reject a request."},["1109"]={"_sunt_ or _intercedunt mihi cum aliquo inimicitiae_[1]","I am on bad terms with a person."},["1118"]={"_amicitiam dissuere, dissolvere, praecīdere_","to renounce, give up a friendship."},["1127"]={"_in gratiam aliquem cum aliquo reducere_","to reconcile two people; to be a mediator."},["1136"]={"_auctoritatem_ or _dignitatem sibi conciliare, parare_","to gain dignity; to make oneself a person of consequence."},["1145"]={"_laude afficere aliquem_","to praise, extol, commend a person."},["1154"]={"_aliquid laudi alicui ducere, dare_","to consider a thing creditable to a man."},["1163"]={"_aliquid alicui crimini dare, vertere_","to reproach a person with..."},["1172"]={"_auditione et fama accepisse aliquid_","to know from hearsay."},["1181"]={"_in sermonem hominum venire_","to be a subject for gossip."},["1190"]={"_mentio alicuius rei incidit_","to mention a thing incidentally, casually."},["1208"]={"_alicuius gloriae_ or simply _alicui obtrectare_","to detract from a person's reputation, wilfully underestimate a person."},["1217"]={"_infamem facere aliquem_","to damage a person's character, bring him into bad odour."},["1226"]={"_honoris causa aliquem nominare_ or _appellare_","to speak of some one respectfully."},["1235"]={"_maculam (conceptam) delere, eluere_","to blot out a reproach."},["1244"]={"_opus aggredi_","to take a task in hand, engage upon it."},["1253"]={"_operam (et oleum) perdere_ or _frustra consumere_","to lose one's labour."},["1262"]={"_omnibus viribus_or _nervis contendere, ut_","to strain every nerve, do one's utmost in a matter."},["1271"]={"_negotiis vacare_","to be free from business."},["1280"]={"_otio frui_","to be at leisure."},["1307"]={"_animum attendere ad aliquid_","to turn one's attention to a thing."},["1316"]={"_ingenium acuere_","to sharpen the wits."},["1325"]={"_ad intellegentiam communem_ or _popularem accommodare aliquid_","to accommodate something to the standard of the popular intelligence."},["1334"]={"_opinionum commenta, ineptiae, monstra, portenta_","extravagant fictions of fancy."},["1343"]={"_cogitationem, animum in aliquid intendere_ (Acad. 4. 46)","to direct one's attention..."},["1352"]={"_omnibus numeris absolutus_ (N. D. 2. 13)","perfect in every detail."},["1361"]={"_singularem quandam perfectionis imaginem animo concipere_","to conceive an ideal."},["1370"]={"_(de) sententia desistere_","to give up one's opinion."},["1406"]={"_veri videndi, investigandi cupiditas_","love of truth."},["1415"]={"_veritas_","veracity."},["1424"]={"_errorem animo imbibere_","to get a mistaken notion into the mind."},["1433"]={"_nisi (animus) me fallit_","if I am not mistaken."},["1442"]={"_dubitationem alicui tollere_","to relieve a person of his doubts."},["1451"]={"_non sum ignarus, nescius_ (not _non sum inscius_)","I know very well."},["1460"]={"_mihi persuasum est_[2]","I am persuaded, convinced."},["1505"]={"_propositum est mihi_ c. Inf.","I intend, propose to..."},["1514"]={"_a me impetrare non possum, ut_","I cannot bring myself to..."},["1523"]={"_ad id quod voluit pervenit_","he attained his object."},["1532"]={"_in mora alicui esse_","to detain a person."},["1541"]={"_memoria tanta fuit, ut_","he had such an extraordinary memory that..."},["1550"]={"_in memoriam alicuius redigere, reducere aliquid_ (not _revocare_)","to recall a thing to a person's mind."},["1604"]={"_summo studio in litteris versari_","to be an ardent student of..."},["1613"]={"_litterarum studio trahi_","to feel an attraction for study."},["1622"]={"_graecis litteris studere_","to study Greek literature."},["1631"]={"_nemo mediocriter doctus_","no one with any pretence to education."},["1640"]={"_vita umbratilis_ (_vid._ sect. VII. 4)","the contemplative life of a student."},["1703"]={"_exemplum magnum, grande_","a weighty example, precedent."},["1712"]={"_ex infinita exemplorum copia unum (pauca) sumere, decerpere (eligere)_","to choose one from a large number of instances."},["1721"]={"_ad exemplum alicuius se conformare_","to shape one's conduct after another's model."},["1730"]={"_aliquid animo mentique penitus mandare_ (Catil. 1. 11. 27)","to impress a thing on one's memory, mind."},["1802"]={"_diffusum, dissipatum esse_","to have no coherence, connection."},["1811"]={"_aliquid alicui probare_ (or c. Acc. c. Inf.)","to prove one's point to a person's satisfaction."},["1820"]={"_ratio_ or _rationis conclusio efficit_","the conclusion proves that..."},["1901"]={"_aetas heroica_[5] (Tusc. 5. 3. 7)","the mythical period, the heroic age."},["1910"]={"_incorrupta rerum fides_","genuine historical truth."},["2009"]={"_fabulam dare_","to produce a play (of the writer)."},["2018"]={"_theatra reclamant_","the spectators protest."},["2027"]={"_histrioni acclamare_[2]","to interrupt an actor by hooting him."},["2036"]={"_diverbium_","stage dialogue."},["2045"]={"_ludus gladiatorius_","a school for gladiators."},["2054"]={"_stadium currere_ (Off. 3. 10. 42)","to run a foot-race."},["2063"]={"_disertum esse_ (De Or. 1. 21. 94)","to be fluent."},["2072"]={"_oratorum principem esse_","to be considered the foremost orator."},["2081"]={"_contentio_ (opp. _sermo_) (Off. 2. 48)","pathetic address; emotional language."},["2090"]={"_verba facere apud_[4] _populum, in contione_","to address a meeting of the people."},["2108"]={"_inflatum orationis genus_","a bombastic style."},["2117"]={"_flumen_[3] _orationis_ (De Or. 2. 15. 62)","flow of oratory."},["2126"]={"_orationes Catonis antiquitatem redolent_ (Brut. 21. 82)","Cato's speeches sound archaic."},["2135"]={"_crebritas_ or _copia_ (opp. _inopia_) _sententiarum_ or simply _copia_","richness of ideas."},["2144"]={"_ratio, qua sententiae inter se excipiunt._","the connection of thought."},["2153"]={"_sic exponere aliquid, quasi agatur res (non quasi narretur)_","to represent a thing dramatically."},["2162"]={"_res summas attingere_","to dwell only on the main points."},["2171"]={"_rebus verba respondent_","the circumstances are described in language worthy of them."},["2180"]={"_leviter significare aliquid_","to hint vaguely at a thing."},["2207"]={"_vox canōra_ (Brut. 63. 234)","a melodious, ringing voice."},["2216"]={"_gestum_ (always in the sing.) _agere_","to gesticulate."},["2225"]={"_infinita et immensa materia_","abundance of material."},["2234"]={"_sed redeat, unde aberravit oratio_","but to return from the digression we have been making."},["2243"]={"_hoc loco exsistit quaestio, quaeritur_","at this point the question arises."},["2252"]={"_percontanti non deesse_ (De Or. 1. 21. 97)","to answer every question."},["2261"]={"_facete et commode dicere_ ","to indulge in apt witticisms."},["2270"]={"_iucunde esse_ (Deiot. 7. 19)","to be in a good temper."},["2306"]={"_verbum pro verbo reddere_","to translate literally, word for word (not _verbo tenus_)."},["2315"]={"_emendate scribere_","to write correctly, in faultless style."},["2324"]={"_inopia verborum_","poverty of expression."},["2333"]={"_inanium verborum flumen_","senseless rant."},["2342"]={"_pauca dicere_ (_pauca verba dicere_ only of the orator)","to say only a few words."},["2351"]={"_vocabulum,_[1] _verbum, nomen ducere ab, ex..._","to form, derive a word from... (used of the man who first creates the word)."},["2360"]={"_vis et notio verbi, vocabuli_","the fundamental meaning of a word."},["2405"]={"_scribere_","to take to writing, become an author."},["2414"]={"_index, inscriptio_[1] _libri_","the title of a book."},["2423"]={"_nescio quis_","an anonymous writer."},["2432"]={"_librum in manus sumere_","to take up a book in one's hands."},["2441"]={"_Platonem legere, lectitare_","to read Plato."},["2450"]={"_legentes, ii qui legunt_[5]","the reader."},["2504"]={"_animum alicuius ad laetitiam excitare_","to put a man in a pleasurable frame of mind."},["2513"]={"_acerbum dolorem alicui inurere_","to cause any one very acute pain."},["2522"]={"_animus meus ad dolorem obduruit_ (Fam. 2. 16. 1)","I have become callous to all pain."},["2531"]={"_aliquid me sollicitat, me sollicitum habet, mihi sollicitudini est, mihi sollicitudinem affert_","something harasses me, makes me anxious."},["2540"]={"_paucis, parvo contentum esse_","to be satisfied with a little."},["2603"]={"_omnia perpeti paratum esse_","to be ready to endure anything."},["2612"]={"_animo adesse_ (Sull. 11. 33)","to be quite unconcerned."},["2621"]={"_spem habere_","to cherish a hope."},["2630"]={"_ad spem aliquem excitare, erigere_","to awaken new hope in some one."},["2702"]={"_studio ardere alicuius_ or _alicuius rei_ (De Or. 2. 1. 1)","to have enthusiasm for a person or thing."},["2711"]={"_fidem alicuius imminuere, infirmare_ (opp. _confirmare_)","to weaken, destroy a man's credit."},["2720"]={"_in fide manere_ (B. G. 7. 4. 5)","to remain loyal."},["2801"]={"_ulcisci aliquem pro aliquo_ or _pro aliqua re_","to revenge oneself on another for a thing or on some one's behalf."},["2810"]={"_honesta expetere; turpia fugere_","to follow virtue; to flee from vice."},["2900"]={"_insidias collocare, locare_ (Mil. 10. 27)","to set an ambuscade."},["3008"]={"_consilia et facta_ (cf. sect. X. 1, note _For 'thoughts and deeds'..._)","thought and deed."},["3017"]={"_vir constans, gravis_ (opp. _homo inconstans, levis_)","a man of character, with a strong personality."},["3026"]={"_ad inferos descendere_","to descend to the world below."},["3035"]={"_sacris initiari_ (Quintil. 12. 10. 14)","to be initiated into the mysteries of a cult."},["3044"]={"_divinitus_ (De Or. 1. 46. 202)","by divine inspiration (often = marvellously, excellently)."},["3053"]={"_aliquid religioni habere_ or _in religionem vertere_","to make a thing a matter of conscience, be scrupulous about a thing."},["3062"]={"_iureiurando aliquem astringere_","to bind some one by an oath."},["3071"]={"_deos esse negare_","to deny the existence of the gods."},["3080"]={"_superstitionem funditus tollere_","to absolutely annihilate superstition."},["3107"]={"_rebus divinis (rite) perpetratis_","after having performed the sacrifice (with due ritual)."},["3116"]={"_diem festum agere_ (of an individual)","to keep, celebrate a festival."},["3125"]={"_oraculum dare, edere_","to give an oracular response."},["3134"]={"_augures obnuntiant (consuli)_ (Phil. 2. 33. 83)","the augurs announce an unfavourable sign."},["3143"]={"_domus subita ruina collapsa est_","the house suddenly fell in ruins."},["3152"]={"_domo pedem non efferre_","to never set foot out of doors."},["3161"]={"_pro aris_[4] _et focis pugnare, certare, dimicare_","to fight for hearth and home."},["3170"]={"_opibus, divitiis, bonis, facultatibus abundare_","to be very rich."},["3206"]={"_cibum concoquere, conficere_","to digest food."},["3215"]={"_panis cibarius_","ordinary bread."},["3224"]={"_victus cotidianus_","daily bread."},["3233"]={"_victum aliqua re quaerere_","to earn a livelihood by something."},["3242"]={"_sumptibus modum statuere_","to limit one's expenditure."},["3251"]={"_dissipare rem familiarem (suam)_","to squander all one's property."},["3260"]={"_promittere (ad cenam)_ (Off. 3. 14. 58)","to accept an invitiation to dinner."},["3305"]={"_sermo ortus est ab aliqua re_","the conversation began with..."},["3314"]={"_narratiuncula, fabella_ (Fin. 5. 15)","an anecdote."},["3323"]={"_in congressum alicuius venire_","to obtain an audience of some one."},["3332"]={"_intra parietes_ (Brut. 8. 32)","within four walls."},["3341"]={"_salute data (accepta) redditaque_","after mutual greeting."},["3350"]={"_sibi (aliquam) despondere_ (of the man)","to betroth oneself, get engaged."},["3404"]={"_more institutoque maiorum_ (Mur. 1. 1)","according to the custom and tradition of my fathers."},["3413"]={"_contrahere rem_ or _negotium cum aliquo_ (Cluent. 14. 41)","to have business relations with some one."},["3422"]={"_aliquid magno, parvo stat, constat_","a thing costs much, little."},["3431"]={"_pecuniam erogare (in classem)_","to spend money."},["3440"]={"_pecunia iacet otiosa_","the money is bringing in no interest, lies idle."},["3503"]={"_in summa difficultate nummaria versari_ (Verr. 2. 28. 69)","to be in severe pecuniary straits."},["3512"]={"_aere alieno oppressum esse_","to have pressing debts."},["3521"]={"_domum aedificandam locare, conducere_","to give, undertake a contract for building a house."},["3530"]={"_pons est in flumine_","there is a bridge over the river."},["3602"]={"_rei publicae_[2] _causa_ (Sest. 47. 101)","for political reasons."},["3611"]={"_totum et animo et corpore in salutem rei publicae se conferre_","to devote oneself body and soul to the good of the state."},["3620"]={"_res civiles_","political questions."},["3701"]={"_a lege discedere_","to transgress a law."},["3710"]={"_lege teneri_","to be bound by a law."},["3800"]={"_statum rei publicae convellere_","to endanger the existence of the state."},["4007"]={"_ius dicere_","to administer justice (said of the praetor)."},["4016"]={"_diem dicere alicui_","to summon some one to appear on a given day; to accuse a person."},["4025"]={"_ex aequo et bono_ (Caecin. 23. 65)","justly and equitably."},["4034"]={"_ius ac fas omne delere_","to trample all law under foot."},["4043"]={"_quaesītor_","the examining judge."},["4052"]={"_aliquem testem adhibere_","to use some one's evidence."},["4061"]={"_quaerere tormentis de aliquo_","to have a person tortured."},["4070"]={"_causam dicere pro aliquo_","to defend a person."},["4106"]={"_iudicare causam (de aliqua re)_","to decide on the conduct of the case."},["4115"]={"_abesse a culpa_","to be free from blame."},["4124"]={"_culpam alicuius rei sustinere_","to bear the blame of a thing."},["4133"]={"_poenas expetere ab aliquo_","to exact a penalty from some one."},["4142"]={"_luere_[1] _aliquid aliqua re_ (De Sen. 20)","to atone for something by..."},["4151"]={"_capitis absolvere aliquem_","to repeal a death-sentence passed on a person."},["4160"]={"_in crucem agere, tollere aliquem_","to crucify."},["4205"]={"_milites tumultuarii_[2] (opp. _exercitus iustus_) (Liv. 35. 2)","soldiers collected in haste; irregulars."},["4214"]={"_rei frumentariae prospicere_ (B. G. 1. 23)","to look after the commissariat."},["4223"]={"_rei militaris rudem esse_","to have had no experience in war."},["4232"]={"_imperii summae praeesse_","to be commander-in-chief."},["4241"]={"_arma expedire_ (Tusc. 2. 16. 37)","to make ready for battle."},["4250"]={"_tela iacere, conicere, mittere_","to discharge missiles."},["4304"]={"_procedere cum exercitu_","to advance with the army."},["4313"]={"_iter maturare, accelerare_","to quicken the pace of marching."},["4322"]={"_signa sequi_ (opp. _a signis discedere, signa relinquere_)","to follow the standards."},["4331"]={"_novissimos carpere_","to harass the rear."},["4340"]={"_consistere in monte_","to take up one's position on a mountain."},["4403"]={"_eruptionem facere ex oppido_","to make a sally, sortie from the town."},["4412"]={"_portas obstruere_ (B. G. 5. 50)","to barricade the gates."},["4421"]={"_oppidum evertere, excīdere_","to completely destroy a town."},["4430"]={"_libera corpora sub corona (hasta) veneunt_ (B. G. 3. 16. 4)","the free men are sold as slaves."},["4502"]={"_res ad triarios_[4] _redit_ (Liv. 8. 8)","the triarii must now fight (proverbially = we are reduced to extremities)."},["4511"]={"_res ad manus venit_","the fighting is now at close quarters."},["4520"]={"_orbem_[1] _facere_ (Sall. Iug. 97. 5)","to form a square."},["4601"]={"_victoriam praecipere (animo)_ (Liv. 10. 26)","to consider oneself already victor."},["4610"]={"_triumphum senatus Africano decernit_ (Fin. 4. 9. 22)","the senate decrees to Africanus the honours of a triumph."},["4700"]={"_vento se dare_","to run before the wind."}} local grc_RWoodhouse_lemma_to_infinitives = { ["καθοσιόομαι"]={"καθοσιωθῆναι","προκαθωσιῶσθαι"},["αϝερρο"]={"αϝερρερε"},["λευκόω"]={"λευκοῦσθαι"},["μυθεύω"]={"μεμυθεῦσθαι","μυθεύειν","μυθεύεσθαι","μυθεῦσαι"},["τρυνξο"]={"τρυνξαρε"},["ἐξελαύνω"]={"ἐξελάσαι","ἐξελάσασθαι","ἐξελᾶν","ἐξελαθῆναι","ἐξελαύνειν","ἐξεληλάσθαι","κἀξελαύνειν"}} local la_NLW_headwords_to_path = { ["acriusculus"]={"3/008723"},["adiuuatiuus"]={"0/018000"},["aequatorius"]={"0/007420"},["alteratiuus"]={"0/017612"},["antitogatus"]={"0/009372"},["apolyonista"]={"3/013775"},["apotropicos"]={"3/002951"},["cariusculus"]={"2/016998"},["circumquiro"]={"1/005869"},["circumsurgo"]={"3/004727"},["columnellus"]={"1/010053"},["compatratus"]={"0/019596"},["concursator"]={"0/015136"},["confedustus"]={"1/005341"},["confutarius"]={"1/018553"},["conquinator"]={"2/005314"},["consortoria"]={"2/017878"},["conturbator"]={"1/003457"},["dentisculus"]={"3/000403"},["deruislarus"]={"1/015293"},["discursator"]={"2/010710"},["disturbator"]={"3/003455"},["epistolutia"]={"1/006857"},["exorcisator"]={"1/005073"},["expurgatiue"]={"3/014407"},["exsufflator"]={"2/008034"},["frondestris"]={"3/018775"},["fulminatrix"]={"1/011257"},["gaudiloquus"]={"2/012370"},["immorigerus"]={"1/000645"},["indemutatus"]={"3/007715"},["inexauditus"]={"0/020172"},["introspicio"]={"2/000762"},["iuniperanus"]={"2/019246"},["logogriphus"]={"2/001530"},["lusciositas"]={"1/018229"},["mediusculus"]={"0/007112"},["nondumtaxat"]={"3/013127"},["pereloquens"]={"0/014112"},["perexcelsus"]={"0/007988"},["perexhorreo"]={"2/016558"},["praeternoto"]={"0/009920"},["pyramidatus"]={"0/013556"},["pyrostatica"]={"3/012047"},["quarantanus"]={"0/015312"},["semiauratus"]={"1/010829"},["semiuolumen"]={"2/021238"},["solutibilis"]={"3/016671"},["sublasciuus"]={"0/008820"},["subtervallo"]={"2/019886"},["sufferrator"]={"0/017736"},["superaduolo"]={"2/009730"},["superingero"]={"1/001353"},["tautacismus"]={"1/017729"},["terminarius"]={"3/011555"},["thalmuticus"]={"0/014580"},["usurpabilis"]={"1/010745"}} local grc_RLBG_lemma_to_index = { ["ἀλευροδόχος"]={"2480"},["ἀντιλόχησις"]={"5891"},["ἀποκοπτικός"]={"7627"},["ἀπολεύκωσις"]={"7705"},["ἀρτοποιικός"]={"9309"},["γονυκλιτέον"]={"14527"},["ἐξαμφοτέρως"]={"23945"},["ἐπικαύχησις"]={"25779"},["ἐπισαλτικός"]={"26276"},["ἐπιστοιχίζω"]={"26389"},["ἐποίκτιστος"]={"26800"},["ἑτεροκλίτως"]={"27592"},["καθοσιόομαι"]={"33125"},["λεκανοπούλα"]={"41154"},["μειρακύλλιν"]={"43948"},["μιγαρούδιον"]={"45345"},["μνημονάριος"]={"45712"},["νεροσέλινον"]={"47513"},["ὀφιόπληκτος"]={"51356"},["ἀναγγελίζομαι"]={"3501"},["ζουμός"]={"29332"},["θεοκαταγνώστης"]={"30622"},["καταπραγματεία"]={"35669"},["κισσών"]={"37478"},["κορμός"]={"38735"},["λώριος"]={"42555"},["παρακαταβιβάζω"]={"53268"},["πούντη"]={"59367"},["προβατοθρέμμων"]={"60048"},["ἀμπελοπεριβόλιον"]={"3186"},["ἀπείλημα"]={"6915"},["δύστρατος"]={"19147"},["ἐνλαξεύω"]={"23266"},["ἔντεκνος"]={"23609"},["ἐντεροεπιπλοκήλη"]={"23627"},["ἐξοδικός"]={"24507"},["ζαρναβᾶς"]={"29195"},["ἰθυγενής"]={"32060"},["μεσόπαχυς"]={"44499"},["μπαρπότος"]={"46466"},["μυσαρότης"]={"46918"},["οἰκαρχία"]={"48807"},["πρασινοτρίβλαττος"]={"59520"},["πρόρρηξις"]={"61503"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["intervallum"]={"180","182","183","360"},["laetissimus"]={"3542"}} local grc_RCunliffe_lemma_to_index = { ["ἐξελαύνω"]={"3359"},["δοχμός"]={"2411"},["κορμός"]={"5714"},["ἐμπνύνθη"]={"3135"},["ὠμοφάγος"]={"9772"},["πρόρριζος"]={"8120"}} local grc_RWoodhouse_lemma_to_headwords = { ["δημοσιεύειν"]={"confiscate","public","sequestrate"},["ἀνδροφθόρος"]={"destroying","homicidal","murderous","sanguinary"},["ἀνδροφόντης"]={"murderer"},["ἀνεπιφθόνως"]={"commendably","innocently","inoffensively","laudably","odium"},["ἐκπολεμεῖν"]={"set"},["Θαύμας"]={"thaumas"},["Θύμβρα"]={"thymbra"},["κορμός"]={"billet","block","bole","log","stump","trunk"},["μύριος"]={"innumerable"},["προμαντεύεσθαι"]={"forebode","foretell","predict","prophesy"},["συναποστέλλειν"]={"send"},["ὀρθῶς"]={"accurately","correctly","dispassionately","equitably","fairly","honestly","impartially","justly","lawfully","morally","righteously","rightly","soundly","straightforwardly","truly","uprightly","veraciously","well"},["μεταῦθις"]={"afterwards","hereafter"},["πρόρριζος"]={"branch","root","utterly"},["σπανιστός"]={"frugal","infrequent","meagre","niggardly","penurious","scant","slender","spare","stinted","thrifty"},["ἀγείρειν"]={"amass","assemble","begging","collect","convene","gather","mobilise","muster"},["ἀδυναμία"]={"badness","helplessness","impotence","inability","inaptitude","incapacity","incompetence","ineptitude","powerlessness"},["ὠμοφάγος"]={"carnivorous","raw"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} a28erx5s96ihf8ft7jghlmm4k5gqux6 Module:data tables/dataM204 828 38996 178506 2026-10-27T06:04:39Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1029"]={"_benevolentiam habere erga aliquem_","to be well-disposed towards..."},["1038"]={"_in gratiam alicuius venire_","to gain a person's esteem, friendship."},["1047"]={"_alicuius voluntati morem gerere_","to accomodate oneself to another's wishes."},["1056"]={"_gratus_ (opp. _ingratus_) _animus_[1]","gratitude."},["1065"]={"_bonam (praeclaram) gratiam referre_","to reward amply; to give manifold recomp...' 178506 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1029"]={"_benevolentiam habere erga aliquem_","to be well-disposed towards..."},["1038"]={"_in gratiam alicuius venire_","to gain a person's esteem, friendship."},["1047"]={"_alicuius voluntati morem gerere_","to accomodate oneself to another's wishes."},["1056"]={"_gratus_ (opp. _ingratus_) _animus_[1]","gratitude."},["1065"]={"_bonam (praeclaram) gratiam referre_","to reward amply; to give manifold recompense for."},["1074"]={"_multum (aliquid) alicui rei tribuere_","to consider of importance; to set much (some) store by a thing."},["1083"]={"_mercede conductum esse_","to be hired, suborned."},["1092"]={"_petenti alicui negare aliquid_","to refuse, reject a request."},["1119"]={"_amicissimus meus_ or _mihi_","my best friend."},["1128"]={"_in gratiam cum aliquo redire_","to be reconciled; to make up a quarrel."},["1137"]={"_ad summam auctoritatem pervenire_","to attain to the highest eminence."},["1146"]={"_(maximis, summis) laudibus efferre aliquem_ or _aliquid_","to praise, extol, commend a person."},["1155"]={"_aliquem coram, in os_ or _praesentem laudare_","to praise a man to his face."},["1164"]={"_conqueri, expostulare cum aliquo de aliqua re_","to expostulate with a person about a thing."},["1173"]={"_fando aliquid audivisse_","to know from hearsay."},["1182"]={"_in ora vulgi abire_","to be a subject for gossip."},["1191"]={"_gloriam, famam sibi comparare_","to gain distinction."},["1209"]={"_alicuius famam, laudem imminuere_","to detract from a person's reputation, wilfully underestimate a person."},["1218"]={"_magnam sui famam relinquere_","to leave a great reputation behind one."},["1227"]={"_statuam alicui ponere, constituere_","to set up a statue in some one's honour."},["1236"]={"_studiose (diligenter, enixe, sedulo, maxime) dare operam, ut..._","to take great pains in order to..."},["1245"]={"_ad opus faciendum accedere_","to take a task in hand, engage upon it."},["1254"]={"_rem actam_ or simply _actum agere_ (proverb.)","to have all one's trouble for nothing."},["1263"]={"_omni ope atque opera_ or _omni virium contentione eniti, ut_","to strain every nerve, do one's utmost in a matter."},["1272"]={"_occupatum esse in aliqua re_","to be engaged upon a matter."},["1281"]={"_otio abundare_","to have abundance of leisure."},["1290"]={"_voluptatem ex aliqua re capere_ or _percipere_","to derive pleasure from a thing."},["1308"]={"_diligenter attendere (aliquid)_","to attend carefully."},["1317"]={"_ingenii acumen_","penetration; sagacity."},["1326"]={"_animo, cogitatione aliquid fingere_ (or simply _fingere_, but without _sibi_), _informare_","to form an idea of a thing, imagine, conceive."},["1335"]={"_animo, mente, cogitatione aliquid comprehendere, complecti_","to grasp a thing mentally."},["1344"]={"_omnes cogitationes ad aliquid conferre_","to give all one's attention to a thing."},["1353"]={"_ad summum perducere_","to bring to the highest perfection."},["1362"]={"_imaginem perfecti oratoris adumbrare_","to sketch the ideal of an orator."},["1371"]={"_de sententia deici, depelli, deterreri_","to be forced to change one's mind."},["1380"]={"_plura in eam sententiam disputare_","to discuss a subject more fully on the same lines."},["1407"]={"_veri inquisitio atque investigatio_","zealous pursuit of truth."},["1416"]={"_re (vera), reapse_ (opp. _specie_)","in truth; really."},["1425"]={"_errorem cum lacte nutricis sugere_ (Tusc. 3. 1. 2)","to imbibe error from one's mother's breasts."},["1434"]={"_nisi omnia me fallunt_","unless I'm greatly mistaken."},["1443"]={"_aliquid in medio, in dubio relinquere_ (Cael. 20. 48)","to leave a thing undecided."},["1452"]={"_me non fugit, praeterit_","I am not unaware."},["1461"]={"_mihi persuasi_","I am persuaded, convinced."},["1470"]={"_consilium capere, inire_ (_de aliqua re_, with Gen. gerund., with Inf., more rarely _ut_)","to form a plan, make a resolution."},["1506"]={"_propositum, consilium tenere_ (opp. _a proposito deterreri_)","to abide by one's resolution."},["1515"]={"_descendere ad aliquid, ad omnia_ (_vid._ sect. V. 9, note _Similarly descendere..._)","to consent to..., lend oneself to..."},["1524"]={"_quid tibi vis?_","what do you mean to do?"},["1533"]={"_nullam moram interponere, quin_ (Phil. 10. 1. 1)","to make all possible haste to..."},["1542"]={"_memoriā labi_","to make a slip of the memory."},["1551"]={"_memoria et recordatio_","vivid recollection."},["1560"]={"_memoriam eius nulla umquam delebit (obscurabit) oblivio_ (Fam. 2. 1)","nothing will ever make me forgetful of him."},["1605"]={"_se totum litteris tradere, dedere_","to devote oneself entirely to literature."},["1614"]={"_trahi, ferri ad litteras_","to feel an attraction for study."},["1623"]={"_multum (mediocriter) in graecis litteris versari_","to be well (slightly) acquainted with Greek literature."},["1632"]={"_latinis litteris_ or _latine doctus_","acquainted with the Latin language."},["1641"]={"_litterarum scientiam_ (only in sing.) _habere_","to possess literary knowledge."},["1650"]={"_optimis studiis_ or _artibus, optimarum artium studiis eruditum esse_","to have received a liberal education."},["1704"]={"_exemplum afferre_","to quote an example."},["1713"]={"_a Socrate exemplum virtutis petere, repetere_","to quote Socrates as a model of virtue."},["1722"]={"_exemplum edere, prodere_","to set an example."},["1731"]={"_demittere aliquid in pectus_ or _in pectus animumque suum_","to take a thing to heart."},["1740"]={"_Ciceronis de philosophia libri_","Cicero's philosophical writings."},["1803"]={"_confusum, perturbatum esse_","to be confused."},["1812"]={"_argumentis confirmare, comprobare, evincere aliquid_ (or c. Acc. c. Inf.)","to prove a thing indisputably."},["1821"]={"_ratiocinatio, ratio_","the syllogism; reasoning."},["1830"]={"_disputare_[1] (_de aliqua re, ad aliquid_)","to discuss, investigate a subject scientifically."},["1902"]={"_tempora heroica_ (N. D. 3. 21. 54)","the mythical period, the heroic age."},["1911"]={"_ad historiam (scribendam) se conferre_ or _se applicare_","to devote oneself to writing history."},["1920"]={"_ad temporum rationem aliquid revocare_","to calculate the date of an event."},["2019"]={"_populum facilem, aequum habere_","to have an appreciative audience."},["2028"]={"_partes agere alicuius_[3]","to play the part of some one."},["2037"]={"_canticum_","a choric ode."},["2046"]={"_gladiatoribus_ (Att. 2. 19. 3)","at the gladiatorial games."},["2055"]={"_ars dicendi_","the art of speaking; oratory."},["2064"]={"_eloquentem esse_ (De Or. 1. 21. 94)","to be a capable, finished speaker."},["2073"]={"_orationem conficere_","to compose a speech."},["2082"]={"_copiose dicere_","to speak very fluently."},["2091"]={"_in contionem (in rostra) escendere_[5] (only of Romans)","to mount the rostra."},["2109"]={"_oratio altius exaggerata_","a bombastic style."},["2118"]={"_siccitas, sanitas orationis_","the plain style."},["2127"]={"_ex illius orationibus ipsae Athenae redolent_","there is a flavour of Atticism about his discourse."},["2136"]={"_sententiis abundans_[5] or _creber_ (opp. _sententiis inanis_)","rich in ideas."},["2145"]={"_vitam alicuius exponere_","to give an account of a man's life."},["2154"]={"_aliquem disputantem facere, inducere, fingere (est aliquid apud aliquem disputans)_","to introduce a person (into a dialogue) discoursing on..."},["2163"]={"_summatim aliquid exponere_","to dwell only on the main points."},["2172"]={"_copiam quam potui persecutus sum_","I have exhausted all my material."},["2181"]={"_ordine narrare, quomodo res gesta sit_","to detail the whole history of an affair."},["2190"]={"_in maius ferre, in maius extollere aliquid_","to exaggerate a thing."},["2208"]={"_vox lenis, suppressa, summissa_","a gentle, subdued voice."},["2217"]={"_non habeo argumentum scribendi_","I have nothing to write about."},["2226"]={"_materiem ad ornatum praebere_","to afford matter for elaboration, embellishment."},["2235"]={"_sed ad id, unde digressi sumus, revertamur_","but to return from the digression we have been making."},["2244"]={"_nunc id quaeritur, agitur_","the question now is..."},["2253"]={"_responsum ab aliquo ferre, auferre_","to extract an answer from some one."},["2262"]={"_breviter et commode dictum_","a short, pointed witticism."},["2271"]={"_se dare iucunditati_","to let oneself be jovial."},["2280"]={"_volubilitas, solutio linguae_","volubility."},["2307"]={"_totidem verbis transferre_","to translate literally, word for word (not _verbo tenus_)."},["2316"]={"_latine scribere_[4] (Opt. Gen. Or. 2. 4)","to write good Latin."},["2325"]={"_lectissimis verbis uti_ (De Or. 3. 37)","to employ carefully chosen expressions."},["2334"]={"_flosculi, rhetorum pompa_","fine, rhetorical phrases."},["2343"]={"_omnia verba huc redeunt_","all this means to say."},["2352"]={"_verbum ductum esse a...putare_","to derive a word from... (used of an etymologist)."},["2361"]={"_vox, nomen carendi_ or simply _carere hoc significat_ (Tusc. 1. 36. 88)","the word _carere_ means..."},["2370"]={"_in bonam (malam) partem accipere aliquid_","to take a thing in good (bad) part."},["2406"]={"_ad scribendum_ or _ad scribendi studium se conferre_","to become a writer, embrace a literary career."},["2415"]={"_liber inscribitur_[2] _Laelius_ (Off. 2. 9. 30)","the book is entitled 'Laelius'."},["2424"]={"_liber refertur ad nescio quem auctorem_","the book is attributed to an unknown writer."},["2433"]={"_librum de manibus ponere_[3]","to lay down a book (_vid._ sect. XII. 3, note _vestem deponere..._)."},["2442"]={"_locum Platonis afferre, proferre_ (not _citare_)","to quote a passage of Plato."},["2451"]={"_languorem, molestiam legentium animis afferre_","to weary, bore the reader."},["2460"]={"_epistula ad Atticum data, scripta, missa_ or _quae ad A. scripta est_","a letter to Atticus."},["2505"]={"_nimio gaudio paene desipere_","to almost lose one's reason from excess of joy."},["2514"]={"_acer morsus doloris est_ (Tusc. 2. 22. 53)","the pain is very severe."},["2523"]={"_dolorem abicere, deponere, depellere_","to banish grief."},["2532"]={"_aegritudo exest animum planeque conficit_ (Tusc. 3. 13. 27)","anxiety gnaws at the heart and incapacitates it."},["2541"]={"_fortunae meae me paenitet_[1]","I am discontented with my lot."},["2550"]={"_luctum deponere_ (Phil. 14. 13. 34)","to lay aside one's grief."},["2604"]={"_ad omnes casus se comparare_","to prepare oneself for all contingencies."},["2613"]={"_ad se redire_","to regain one's self-possession."},["2622"]={"_spe duci, niti, teneri_","to cherish a hope."},["2631"]={"_in maximam spem aliquem adducere_ (Att. 2. 22. 3)","to inspire some one with the most brilliant hopes."},["2640"]={"_spes ad irritum cadit, ad irritum redigitur_","expectation is overthrown."},["2703"]={"_studio alicuius rei aliquem incendere_","to make some one enthusiastic for a thing."},["2712"]={"_fiduciam in aliquo ponere, collocare_","to put confidence in some one."},["2721"]={"_fidem laedere, violare, frangere_","to break one's word."},["2730"]={"_fidem publicam dare, interponere_ (Sall. Iug. 32. 1)","to guarantee the protection of the state; to promise a safe-conduct."},["2802"]={"_poenas alicuius_ or _alicuius rei repetere ab aliquo_","to revenge oneself on another for a thing or on some one's behalf."},["2811"]={"_virtute praeditum, ornatum esse_ (opp. _vitiis obrutum esse_)","to be virtuous."},["2820"]={"_a virtute discedere_ or _deficere_","to deviate from the path of virtue."},["2901"]={"_insidias alicui parare, facere, struere, instruere, tendere_","to waylay a person."},["2910"]={"_speciem alicuius rei habere_","to have the appearance of something."},["3009"]={"_institutum tenere_","to remain true to one's principles."},["3018"]={"_sibi constare, constantem esse_","to be consistent."},["3027"]={"_apud inferos esse_","to be in the lower world."},["3036"]={"_templa deorum adire_","to make a pilgrimage to the shrines of the gods."},["3045"]={"_divinitus accidit_","it happened miraculously."},["3054"]={"_aliquid in religionem alicui venit_","to make a thing a matter of conscience, be scrupulous about a thing."},["3063"]={"_iureiurando aliquem adigere_","to make some one take an oath."},["3072"]={"_insitas (innatas) dei cognitiones habere_ (N. D. 1. 17. 44)","to have innate ideas of the Godhead; to believe in the Deity by intuition."},["3081"]={"_superstitionem radicitus_ or _penitus evellere_","to destroy superstition root and branch."},["3090"]={"_preces facere_","to pray."},["3108"]={"_sacrificium statum (solemne)_ (Tusc. 1. 47. 113)","a periodically recurring (annual) sacrifice."},["3117"]={"_diem festum celebrare_ (of a larger number)","to keep, celebrate a festival."},["3126"]={"_responsum dare_ (_vid._ sect. VIII. 5, note _Note to answer..._), _respondere_","to give an oracular response."},["3135"]={"_auspicato (rem gerere, urbem condere)_","after having duly taken the auspices."},["3144"]={"_domum demoliri_ (Top. 4. 22)","to demolish, raze a house."},["3153"]={"_pedem limine efferre_","to cross the threshold."},["3162"]={"_domi_ (opp. _foris_)","at home; in one's native country."},["3171"]={"_rem bene (male) gerere_[1] (_vid._ sect. XVI. 10a)","to manage one's affairs, household, property well or ill."},["3180"]={"_expellere aliquem domo, possessionibus pellere_","to turn a person out of his house, his property."},["3207"]={"_multi cibi esse, edacem esse_","to be a great eater."},["3216"]={"_vino deditum esse, indulgere_","to be given to drink."},["3225"]={"_victus tenuis_ (Fin. 2. 28. 90)","meagre diet."},["3234"]={"_vivere carne, piscibus, rapto_ (Liv. 7. 25)","to live on meat, fish, by plunder."},["3243"]={"_sumptum minuere_","to retrench."},["3252"]={"_lacerare bona sua_ (Verr. 3. 70. 164)","to squander all one's property."},["3261"]={"_inter cenam, inter epulas_","during dinner; at table."},["3270"]={"_mihi cum illo hospitium est, intercedit_","my relations with him are most hospitable."},["3306"]={"_sermonem alio transferre_","to turn the conversation to another topic."},["3315"]={"_haec fabula docet_","this fable teaches us (without _nos_)."},["3324"]={"_velle aliquem_ (Plaut. Capt. 5. 2. 24)","to wish to speak to some one."},["3333"]={"_salutem alicui dicere, impertire, nuntiare_","to greet a person."},["3342"]={"_inter se consalutare_ (De Or. 2. 3. 13)","to exchange greetings."},["3351"]={"_nuptias conciliare_ (Nep. Att. 5. 3)","to arrange a marriage."},["3360"]={"_filiam alicui in matrimonio_ or _in matrimonium collocare_ or simply _filiam alicui collocare_","to give one's daughter in marriage to some-one."},["3405"]={"_ex instituto_ (Liv. 6. 10. 6)","according to traditional usage."},["3414"]={"_transigere aliquid (de aliqua re) cum aliquo_ or _inter se_","to transact, settle a matter with some one."},["3423"]={"_aliquid nihilo_ or _gratis constat_","a thing costs nothing."},["3432"]={"_pecuniam insumere in aliquid_ or _consumere in aliqua re_","to devote money to a purpose."},["3441"]={"_pecuniam mutuari_ or _sumere mutuam ab aliquo_","to borrow money from some one."},["3450"]={"_res nummaria_ or _pecuniaria_","finance; money-matters."},["3504"]={"_in maximas angustias (pecuniae) adduci_","to be reduced to extreme financial embarrassment."},["3513"]={"_aes alienum dissolvere, exsolvere_","to pay one's debts."},["3522"]={"_aedificatorem esse_ (Nep. Att. 13. 1)","to be fond of building."},["3531"]={"_pontem dissolvere, rescindere, interscindere_ (B. G. 2. 9. 4)","to break down a bridge."},["3540"]={"_ut sementem feceris, ita metes_ (proverb.) (De Or. 2. 65)","as you sow, so will you reap."},["3603"]={"_e re publica_ (opp. _contra rem p._)","for the advantage of the state; in the interests of the state."},["3612"]={"_bene, optime sentire de re publica_","to have the good of the state at heart."},["3621"]={"_plus in re publica videre_","to possess great political insight."},["3630"]={"_generis antiquitate florere_","to be of noble family."},["3702"]={"_salvis legibus_ (_vid._ sect. X. 7, note _Notice..._)","without breaking the law."},["3711"]={"_legibus solvere_","to free from legal obligations."},["3720"]={"_gratiam populi quaerere_","to court popularity."},["3801"]={"_rem publicam vexare_","to damage the state."},["3810"]={"_non nullus odor est dictaturae_ (Att. 4. 18)","there are whispers of the appointment of a dictator."},["3900"]={"_peculatum facere_ (Rab. Perd. 3. 8)","to embezzle money."},["4008"]={"_ius reddere_ (Liv. 3. 33)","to administer justice (said of the praetor)."},["4017"]={"_in iudicium venire, in iudicio adesse_","to appear in court."},["4026"]={"_iudex incorruptus_","an impartial judge."},["4035"]={"_omnia iura pervertere_","to trample all law under foot."},["4044"]={"_incognita causa_ (cf. sect. XV. 3, _indicta causa_)","without any examination."},["4053"]={"_aliquo teste uti_","to use some one's evidence."},["4062"]={"_de servis quaerere (in dominum)_","to examine slaves by torture."},["4071"]={"_causam alicuius defendere_","to conduct some one's defence in a case."},["4080"]={"_lites componere_ (Verg. Ecl. 3. 108)","to arrange a dispute (by arbitration)."},["4107"]={"_iudicium rescindere_","to rescind a decision."},["4116"]={"_prope abesse a culpa_","to be almost culpable."},["4125"]={"_culpam a se amovere_[1]","to exonerate oneself from blame."},["4134"]={"_supplicium sumere de aliquo_","to exact a penalty from some one."},["4143"]={"_poenam subire_","to submit to a punishment."},["4152"]={"_supplicium alicui decernere, in aliquem constituere_","to decree the penalty of death."},["4161"]={"_cruci suffigere aliquem_","to crucify."},["4170"]={"_dilectum habere_","to hold a levy."},["4206"]={"_tirones_","recruits."},["4215"]={"_frumentum providere exercitui_","to provide corn-supplies for the troops."},["4224"]={"_vir fortissimus_","a hero."},["4233"]={"_imperii summam deferre alicui_ or _ad aliquem, tradere alicui_","to appoint some one commander-in-chief."},["4242"]={"_galeam induere_","to put on one's helmet."},["4251"]={"_extra teli iactum, coniectum esse_","to be out of range."},["4260"]={"_sicam, cultrum in corde alicuius defigere_[1] (Liv. 1. 58)","to plunge a dagger, knife in some one's heart."},["4305"]={"_magnis itineribus_ (Sall. Iug. 37)","by forced marches."},["4314"]={"_iter continuare_ (B. C. 3. 11)","to march without interruption."},["4323"]={"_ordines servare_ (B. G. 4. 26)","to keep the ranks."},["4332"]={"_novissimis praesidio esse_","to protect the troops in the rear."},["4341"]={"_considere sub monte (sub montis radicibus)_","to occupy the foot of a hill."},["4350"]={"_castra metari_ (B. C. 3. 13)","to mark out a camp."},["4404"]={"_crebras ex oppido excursiones facere_ (B. G. 2. 30)","to make a sally, sortie from the town."},["4413"]={"_portas refringere_","to break down the gates."},["4422"]={"_oppidum solo aequare_","to raze a town to the ground."},["4431"]={"_cum uxoribus et liberis_","with wife and child."},["4440"]={"_diem pugnae constituere_ (B. G. 3. 24)","to fix a day for the engagement."},["4503"]={"_collatis signis (viribus) pugnare_","to fight hand-to-hand, at close quarters."},["4512"]={"_laxatis_ (opp. _confertis_) _ordinibus pugnare_","to fight in open order."},["4521"]={"_in orbem consistere_","to form a square."},["4530"]={"_acies hostium impellitur_","the enemy's line is repulsed."},["4602"]={"_victoriam exploratam dimittere_","to let a sure victory slip through one's hands."},["4611"]={"_indutias facere_ (Phil. 8. 7)","to make a truce."},["4620"]={"_pacis condiciones dare, dicere alicui_ (Liv. 29. 12)","to dictate the terms of peace to some one."},["4701"]={"_in litus eici_ (B. G. 5. 10)","to be stranded."},["4710"]={"_naves ad ancoras deligare_ (B. G. 4. 29)","to make fast boats to anchors."},["4800"]={"_praeterquam quod_ or _nisi quod_","to except the fact that..."}} local grc_RWoodhouse_lemma_to_infinitives = { ["περισσεύω"]={"περισσεύειν","περισσεύσαι","περισσεῦσαι","περιττεύειν"},["ὠμοθετέω"]={"ὠμοθετεῖν","ὠμοθετῆσαι"},["καταμισθοφορέω"]={"καταμισθοφορῆσαι"},["καταχειροτονέω"]={"καταχειροτονεῖν"},["μισθόω"]={"μεμισθωκέναι","μίσθωσαι","μισθοῦσθαι","μισθώσασθαι","μισθῶσαι","μισθωθῆναι"},["πολεύω"]={"πολεύειν"},["τεκνόω"]={"τεκνοῦσθαι","τεκνῶσαι"}} local la_NLW_headwords_to_path = { ["alimentosus"]={"1/008529"},["anteloquium"]={"2/012358"},["ardiusculus"]={"1/015949"},["assurrectio"]={"3/003051"},["autonomista"]={"1/007173"},["boniloquium"]={"0/015300"},["coinsulanus"]={"3/013627"},["crispositas"]={"1/016265"},["cultellinus"]={"1/016533"},["deuersorium"]={"3/000415"},["frustilatim"]={"2/003018"},["fundatorius"]={"0/015388"},["gentilismus"]={"0/007228"},["hispanismus"]={"3/011055"},["inassuetudo"]={"0/011972"},["inscriptura"]={"0/000720"},["insiduosule"]={"3/008199"},["intermissim"]={"2/007066"},["intoxicator"]={"3/012467"},["manuductrix"]={"2/020926"},["masturbator"]={"0/010424"},["multiparens"]={"1/011593"},["musomanicus"]={"3/009895"},["nauistatium"]={"1/008537"},["nulliformis"]={"1/014749"},["omnimorbius"]={"2/005094"},["omnisanctus"]={"3/010339"},["onirocrisis"]={"1/002377"},["perincertus"]={"0/005300"},["perlongatus"]={"0/014836"},["plurimopere"]={"2/013694"},["polyandrium"]={"0/019408"},["postillatio"]={"3/018235"},["postmodicum"]={"1/021537"},["procriminor"]={"3/013339"},["prodimentum"]={"1/013045"},["prohibitrix"]={"1/018245"},["semiannulus"]={"1/008765"},["semiluxatio"]={"3/017947"},["sexilinguis"]={"0/014204"},["sexternatim"]={"1/021177"},["spatiositas"]={"2/007910"},["statuificus"]={"0/017360"},["supereuenio"]={"2/010366"},["superplaudo"]={"1/009201"},["terraemotor"]={"0/009352"},["uanigerulus"]={"1/013241"},["ubiquitista"]={"3/008239"},["uicissarius"]={"1/017929"},["uitaulianus"]={"2/017494"}} local grc_RLBG_lemma_to_index = { ["ἀγγελίζω"]={"242"},["ἀειθανής"]={"1098"},["ἀθυμηδία"]={"1393"},["αἱμουρία"]={"1560"},["ἁλίκραμα"]={"2529"},["ἀλίσγημα"]={"2546"},["γλυφεῖον"]={"14334"},["διασεβῶς"]={"16509"},["ἔλικτρον"]={"21830"},["ἡλιοακτινόμορφος"]={"29714"},["κερατωτός"]={"37037"},["κορβῖνος"]={"38693"},["ὀβέλισμα"]={"48621"},["ὁμόνομος"]={"49874"},["ὀξύζωμον"]={"50195"},["παρεμφύρω"]={"54165"},["περιδρύφω"]={"55647"},["περιτρύζω"]={"56401"},["πόμπευσις"]={"58980"},["πρηστικός"]={"59636"},["πρόκτησις"]={"61064"},["ἀδιαφοροδιχρονιστής"]={"922"},["ἀντικυριεύω"]={"5863"},["Ἀρειανόφρων"]={"8794"},["ἀρτοκοπικός"]={"9304"},["αὐτοδυνατός"]={"10662"},["ἐξαναστατόω"]={"23988"},["ἐξουσίαρχος"]={"24631"},["ἐξσκουβίτωρ"]={"24662"},["ἐπεντρύφημα"]={"25305"},["ἐπιφρικώδης"]={"26691"},["ἐπιφροντίζω"]={"26695"},["ἑπτάκρουνος"]={"26909"},["εὐαπόνιπτος"]={"27749"},["μεσηλιόομαι"]={"44400"},["μονοφθογγέω"]={"46164"},["νομοκάπηλος"]={"47895"},["ξυλοπέλεκον"]={"48542"},["ξυλοπίνακον"]={"48544"},["ὀπισθόψιλος"]={"50355"},["βατραχοβότανον"]={"12111"},["δρουγγαροκόμης"]={"18363"},["καταισχρεύομαι"]={"35099"},["κουροπαλατάτον"]={"39166"},["κρόνος"]={"39655"},["λιχμός"]={"42007"},["ματρικουλάριος"]={"43494"},["ματώνω"]={"43503"},["μινυός"]={"45506"},["μυλλός"]={"46586"},["Πάπιος"]={"52948"},["περιθρασύνομαι"]={"55732"},["πότιον"]={"59299"},["πότιον"]={"59300"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["disputandus"]={"1835"},["magistratus"]={"3675","3913","3923","3928","3929","3931","3932","3938","3939","3940"}} local grc_RCunliffe_lemma_to_index = { ["πολεύω"]={"7878"},["ἐπιπροϊάλλω"]={"3765"},["ὠμοθετέω"]={"9768"},["ὠμογέρων"]={"9767"},["ἀκριτόμυθος"]={"378"}} local grc_RWoodhouse_lemma_to_headwords = { ["Πηλιῶτις"]={"pelion (mt.)"},["Χαιρεφῶν"]={"chaerephon"},["εὐπαιδία"]={"child"},["εὔκοσμος"]={"adorned","caparisoned","circumspect","decent","decked","decorous","neat","orderly","proper","regular","respectable","respectful","seemly","spruce","systematic","tidy","trim","uniform"},["σταστικός"]={"sectarian"},["ἀσθένεια"]={"ailment","complaint","debility","decrepitude","delicacy","disease","enfeeblement","faintness","feebleness","frailty","ill health","illness","indisposition","infirmity","languor","malady","sickliness","sickness","tenderness","weakness"},["ἱκέτευμα"]={"supplication"},["σιιμβόλαιον"]={"engagement"},["Κάτλος"]={"catulus"},["Λοκρίς"]={"locris"},["Μέμφις"]={"memphis"},["Μαχάων"]={"machaon"},["Πάρθος"]={"parthia"},["νοητός"]={"abstract","conceivable","ideal","intellectual","mental","metaphysical","thinkable","transcendental"},["σκοπόν"]={"goal"},["σύνδυο"]={"two"},["τορύνη"]={"ladle","spoon"},["ἀπλῶς"]={"sincerely","unreservedly"},["ἀποπερκοῦσθαι"]={"mature","ripen"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} k1f3fiz19187w8skh2w6jy471loc5xl Module:data tables/dataM205 828 38997 178507 2026-10-27T06:05:12Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local freezer = { } local la_RMA_index_to_phrases = { ["1039"]={"_gratiam alicuius sibi quaerere, sequi_, more strongly _aucupari_","to court a person's favour; to ingratiate oneself with..."},["1048"]={"_se convertere, converti ad alicuius nutum_[2]","to take one's directions from another; to obey him in everything."},["1057"]={"_gratiam alicui debere_","to owe gratitude to; to be under an obligation to a person."},["1066"]={"_benefacta maleficiis pensare_","to...' 178507 Scribunto text/plain local freezer = { } local la_RMA_index_to_phrases = { ["1039"]={"_gratiam alicuius sibi quaerere, sequi_, more strongly _aucupari_","to court a person's favour; to ingratiate oneself with..."},["1048"]={"_se convertere, converti ad alicuius nutum_[2]","to take one's directions from another; to obey him in everything."},["1057"]={"_gratiam alicui debere_","to owe gratitude to; to be under an obligation to a person."},["1066"]={"_benefacta maleficiis pensare_","to return evil for good."},["1075"]={"_multum alicui tribuere_","to value, esteem a person."},["1084"]={"_orare et obsecrare aliquem_","to entreat earnestly; to make urgent requests."},["1093"]={"_repudiare, aspernari preces alicuius_","to refuse, reject a request."},["1129"]={"_sibi aliquem, alicuius animum reconciliare_ or _reconciliari alicui_","to be reconciled; to make up a quarrel."},["1138"]={"_auctoritatem alicuius amplificare_ (opp. _imminuere, minuere_)","to increase a person's dignity."},["1147"]={"_eximia laude ornare aliquem_","to praise, extol, commend a person."},["1156"]={"_recte, bene fecisti quod..._","you were right in...; you did right to..."},["1165"]={"_rumor, fama, sermo est_ or _manat_","report says; people say."},["1174"]={"_ex eo audivi, cum diceret_","I heard him say..."},["1183"]={"_fabulam fieri_","to be the talk of the town, a scandal."},["1192"]={"_gloriam (immortalem) consequi, adipisci_","to win (undying) fame."},["1219"]={"_opinionem virtutis habere_","to have the reputation of virtue."},["1228"]={"_aliquem colere et observare_ (Att. 2. 19)","to pay respect to, be courteous to a person."},["1237"]={"_egregiam operam_ (_multum, plus_ etc. _operae_) _dare alicui rei_","to expend great labour on a thing."},["1246"]={"_res est multi laboris et sudoris_","the matter involves much labour and fatigue."},["1255"]={"_labore supersedēre (itineris)_ (Fam. 4. 2. 4)","to spare oneself the trouble of the voyage."},["1264"]={"_contendere et laborare, ut_","to strain every nerve, do one's utmost in a matter."},["1273"]={"_intentum esse alicui rei_","to be engaged upon a matter."},["1282"]={"_otium sequi, amplexari_","to be a lover of ease, leisure."},["1291"]={"_voluptate perfundi_","to revel in pleasure, be blissfully happy."},["1309"]={"_alias res_ or _aliud agere_","to be inattentive."},["1318"]={"_ingenii tarditas_ (opp. _celeritas_)","dulness of intellect."},["1327"]={"_animo concipere aliquid_","to form an idea of a thing, imagine, conceive."},["1336"]={"_in eam cogitationem incidere_","to happen to think of..."},["1345"]={"_mentem in aliqua re defigere_","to fix all one's thoughts on an object."},["1354"]={"_perficere et absolvere_","to bring to the highest perfection."},["1363"]={"_civitas optima, perfecta Platonis_","Plato's ideal republic."},["1372"]={"_de sententia aliquem deducere, movere_","to make a man change his opinion."},["1381"]={"_ut mea fert opinio_","according to my opinion."},["1390"]={"_opinionum pravitate infici_","to be filled with absurd prejudices."},["1408"]={"_a vero abduci_","to be led away from the truth."},["1417"]={"_in errore versari_","to be mistaken."},["1426"]={"_error longe lateque diffusus_","a wide-spread error."},["1435"]={"_optionem alicui dare_ (Acad. 2. 7. 19)","to give a person his choice."},["1444"]={"_aliquid dubium, incertum relinquere_","to leave a thing undecided."},["1453"]={"_quantum scio_","as far as I know."},["1462"]={"_sic habeto_","convince yourself of this; rest assured on this point."},["1471"]={"_consilio desistere_","to give up a project, an intention."},["1480"]={"_aliquem in_ or _ad consilium adhibere_","to consult a person, take his advice."},["1507"]={"_propositum_[1] _assequi, peragere_","to carry out one's plan."},["1516"]={"_descendere ad extrema consilia_ (Fam. 10. 33. 4)","to have recourse to extreme measures."},["1525"]={"_quid hoc sibi vult?_","what is the meaning of this?"},["1534"]={"_sine mora_ or _nulla mora interposita_","without delay."},["1543"]={"_memoriae mandare aliquid_[1]","to impress on the memory."},["1552"]={"_grata memoria aliquem prosequi_[2]","to show a thankful appreciation of a person's kindness."},["1561"]={"_semper memoria eius in (omnium) mentibus haerebit_","nothing will ever make me forgetful of him."},["1570"]={"_memoria alicuius rei excidit, abiit, abolevit_","the recollection of a thing has been entirely lost."},["1606"]={"_se totum in litteras_ or _se litteris abdere_","to be quite engrossed in literary studies."},["1615"]={"_litterarum studia remittere_","to relax one's studies."},["1624"]={"_vir_ or _homo doctus, litteratus_","a man of learning; a scholar; a savant."},["1633"]={"_bene_[1] _latine doctus_ or _sciens_","a good Latin scholar."},["1642"]={"_scientiam alicuius rei consequi_","to acquire knowledge of a subject."},["1651"]={"_litteras scire_","to have received a liberal education."},["1660"]={"_severa disciplina contineri_","to be brought up under strict discipline."},["1705"]={"_exemplo uti_","to quote an example."},["1714"]={"_similitudines afferre_","to cite parallel cases."},["1723"]={"_exemplo esse_","to set an example."},["1732"]={"_hoc verbum alte descendit in pectus alicuius_","what he said made a deep impression on..."},["1741"]={"_decreta, inventa philosophorum_","the tenets, dogmas of philosophers."},["1750"]={"_Solo, unus de septem (illis)_","Solon, one of the seven sages."},["1804"]={"_rem dissolutam conglutinare, coagmentare_","to reunite disconnected elements."},["1813"]={"_argumentum ducere, sumere ex aliqua re_ or _petere ab aliqua re_","to derive an argument from a thing."},["1822"]={"_prima_[1] (_superiora_); _consequentia_ (Fin. 4. 19. 54)","premises; consequences."},["1831"]={"_subtiliter disputare_","to thoroughly discuss."},["1840"]={"_obtinere aliquid_","to maintain one's assertion, prove oneself right."},["1903"]={"_fabulae, historia fabularis_","mythology."},["1912"]={"_homo in historia diligens_","a conscientious historian."},["1921"]={"_diligentem esse in exquirendis temporibus_","to be exact in calculating dates."},["1930"]={"_spectator siderum, rerum caelestium_ or _astrologus_[6]","an astronomer."},["2029"]={"_agere servum, lenonem_","to act the rôle of a slave, pander."},["2038"]={"_ludi circenses, scaenici_","performances in the circus; theatrical perfomances."},["2047"]={"_celebritas ludorum_","crowded games."},["2056"]={"_ad dicendum se conferre_","to devote oneself to oratory."},["2065"]={"_eloquentia valere_","to be very eloquent."},["2074"]={"_orationem commentari_ (Fam. 16. 26)","to prepare, get up a speech."},["2083"]={"_ornate dicere_","to speak well, elegantly."},["2092"]={"_orationem habere_ (Tusc. 5. 33. 94)","to make a speech."},["2119"]={"_verborum tenuitias, oratio subtilis_","the plain style."},["2128"]={"_oratio soluta_ (not _prosa_) or simply _oratio_","prose."},["2137"]={"_adumbrare aliquid_ (Or. 14. 43)","to roughly sketch a thing."},["2146"]={"_vitam alicuius depingere_","to make a sketch of a man's life."},["2155"]={"_in uno conspectu ponere aliquid_","to give a general idea of a thing."},["2164"]={"_multa verba facere_","to go deeply into a matter, discuss it fully."},["2173"]={"_verbis non omnia exsequi posse_","to be unable to say all one wants."},["2182"]={"_dicendo ornare aliquid_","to embellish a narrative."},["2191"]={"_in maius accipere aliquid_","to overestimate a thing."},["2209"]={"_vocem mittere_ (_sonitum reddere_ of things)","to speak, utter a sound."},["2218"]={"_deest mihi argumentum ad scribendum_ (Att. 9. 7. 7)","I have nothing to write about."},["2227"]={"_id quod (mihi) propositum est_","a theme, subject proposed for discussion."},["2236"]={"_verum ut ad id, unde digressa est oratio, revertamur_","but to return from the digression we have been making."},["2245"]={"_res, de qua nunc quaerimus, quaeritur_","the question at issue."},["2254"]={"_respondere in hanc sententiam_[2]","to answer to this effect."},["2263"]={"_facete dictum_","a witticism, bon mot."},["2272"]={"_sibi displicere_ (opp. _sibi placere_)","to be in a bad temper."},["2281"]={"_vitium orationis, sermonis_ or simply _vitium_","a mistake, solecism."},["2290"]={"_aliquid a consuetudine sermonis latini abhorret, alienum est_","the expression is not in accordance with Latin usage."},["2308"]={"_his fere verbis, hoc fere modo convertere, transferre_","to translate freely."},["2317"]={"_enuntiatio, enuntiatum, sententia_","the sentence, proposition."},["2326"]={"_prisca, obsoleta_ (opp. _usitata_), _ambigua verba_","obsolete, ambiguous expressions."},["2335"]={"_voces iacere_ (Sall. Iug. 11)","to let fall an expression."},["2344"]={"_nullum verbum ex ore eius excidit_ (or simply _ei_)","no word escaped him."},["2353"]={"_originem verbi repetere a..._","to derive a word from... (used of an etymologist)."},["2362"]={"_quem intellegimus sapientem?_","what do we understand by 'a wise man'?"},["2371"]={"_aemulatio dupliciter dicitur, ut et in laude et in vitio hoc nomen sit_","the word _aemulatio_ is employed with two meanings, in a good and a bad sense."},["2380"]={"_continua translatio_ (Or. 27. 94)","an allegory; continuous metaphor."},["2407"]={"_animum ad scribendum appellere, applicare_","to become a writer, embrace a literary career."},["2416"]={"_Cicero dicit in Laelio (suo)_ or _in eo_ (not _suo_) _libro, qui inscribitur Laelius_","Cicero says in his 'Laelius.'"},["2425"]={"_hic liber est de amicitia_ (not _agit_) or _hoc libro agitur de am._","the book treats of friendship."},["2434"]={"_perpolire, limare diligenter librum, opus_","to polish, finish a work with the greatest care."},["2443"]={"_scriptor hoc loco dicit_","our (not _noster_) author tells us at this point."},["2452"]={"_liber plenus delectationis_","a very charming book."},["2461"]={"_epistulam dare alicui ad aliquem_","to charge some one with a letter for some one else."},["2470"]={"_epistulam intercipere_ (Att. 1. 13. 2)","to intercept a letter."},["2506"]={"_doleo aliquid, aliqua re, de_ and _ex aliqua re_","I am pained, vexed, sorry."},["2515"]={"_dolorem in lacrimas effundere_","to find relief in tears."},["2524"]={"_dolorem alicui eripere_ (Att. 9. 6. 4)","to free a person from his pain."},["2533"]={"_aegritudine, curis confici_","to be wasting away with grief."},["2542"]={"_non me paenitet, quantum profecerim_","I am not dissatisfied with my progress."},["2551"]={"_vel maximos luctus vetustate tollit diuturnitas_ (Fam. 5. 16. 5)","time assuages the most violent grief."},["2560"]={"_a metu respirare_ (Cluent. 70. 200)","to recover from one's fright."},["2605"]={"_animum alicuius de statu, de gradu demovere_ (more strongly _depellere, deturbare_)","to disconcert a person."},["2614"]={"_constantiam servare_","to be calm, self-possessed."},["2623"]={"_magna me spes tenet_ (with Acc. c. Inf.) (Tusc. 1. 41. 97)","I have great hopes that..."},["2632"]={"_in meliorem spem, cogitationem aliquem inducere_ (Off. 2. 15. 53)","to induce some one to take a brighter view of things."},["2641"]={"_spem abicere, deponere_","to give up hoping."},["2650"]={"_spem suam ponere, collocare in aliquo_","to set one's hope on some one."},["2704"]={"_ardor, inflammatio animi, incitatio mentis, mentis vis incitatior_","enthusiasm."},["2713"]={"_confidere alicui_ (but _aliqua re_)","to put confidence in some one."},["2722"]={"_fidem alicuius labefactare_ (Cluent. 60. 194)","to make a person waver in his loyalty."},["2731"]={"_fidem dare alicui_ (opp. _accipere_) (c. Acc. c. Inf.)","to give one's word that..."},["2740"]={"_fidem facere, afferre alicui rei_ (opp. _demere, de-, abrogare fidem_)","to make a thing credible."},["2803"]={"_iniurias persequi_ (Verr. 2. 3. 9)","to avenge an insult."},["2812"]={"_viam virtutis ingredi_ (Off. 1. 32. 118)","to walk in the ways of virtue."},["2821"]={"_honestatem deserere_","to deviate from the path of virtue."},["2830"]={"_vitia erumpunt (in aliquem)_ (De Amic. 21. 76)","his vices betray themselves."},["2902"]={"_aliquem in insidiis locare, collocare, ponere_","to place some one in ambush."},["2911"]={"_speciem alicuius rei praebere_","to give the impression of...; have the outward aspect of..."},["2920"]={"_aliter sentire ac loqui (aliud sentire, aliud loqui)_","to think one thing, say another; to conceal one's opinions."},["3019"]={"_animo mobili esse_ (Fam. 5. 2. 10)","to be inconsistent, changeable."},["3028"]={"_aliquem ab inferis_ or _a mortuis evocare, excitare_ (passive _ab inferis exsistere_)","to summon some one from the dead."},["3037"]={"_numerum deorum obtinere_ (N. D. 3. 20)","to be regarded as a god."},["3046"]={"_imbuere_ (_vid._ sect. VII. 7, note _imbuere..._) _pectora religione_[1]","to inspire with religious feeling, with the fear of God."},["3055"]={"_nulla religio_","absence of scruples, unconscientiousness."},["3064"]={"_iureiurando ac fide se obstringere, ut_","to promise an oath to..."},["3073"]={"_omnibus innatum est et in animo quasi insculptum esse deum_","belief in God is part of every one's nature."},["3082"]={"_formidines_","superstitious fears; phantoms."},["3091"]={"_grates, laudes agere dis immortalibus_","to thank, glorify the immortal gods."},["3109"]={"_sacra polluere et violare_","to profane sacred rites."},["3118"]={"_supplicationem indicere ad omnia pulvinaria_ (Liv. 27. 4)","to proclaim a public thanksgiving at all the street-shrines of the gods."},["3127"]={"_oraculum Pythium (Pythicum)_","an oracle given by the Delphian Apollo (Apollo Pythius)."},["3136"]={"_omen accipere_ (opp. _improbare_)","to accept as a happy omen."},["3145"]={"_domus non omnes capit_[2] (χωρειν)","the house is not large enough for all."},["3154"]={"_foras exire_ (Plaut. Amph. 1. 2. 35)","to go out of the house."},["3163"]={"_ostium, fores pulsare_","to knock at the door."},["3172"]={"_rem familiarem tueri_","to manage one's affairs, household, property well or ill."},["3181"]={"_demovere, deicere aliquem de possessione_","to dispossess a person."},["3190"]={"_sedem ac domicilium (fortunas suas) constituere alicubi_","to take up one's abode in a place, settle down somewhere."},["3208"]={"_cibum apponere, ponere alicui_","to set food before a person."},["3217"]={"_potare_","to drink to excess; to be a drunkard."},["3226"]={"_res ad vitam necessariae_","the necessaries of life."},["3235"]={"_de suo_ (opp. _alieno_) _vivere_","to live on one's means."},["3244"]={"_sumptus perpetui_ (Off. 2. 12. 42)","current expenses."},["3253"]={"_convivium instruere, apparare, ornare (magnifice, splendide)_","to prepare, give a feast, dinner."},["3262"]={"_promittere ad aliquem_","to promise to dine with a person."},["3271"]={"_hospitio alicuius uti_","to enjoy a person's hospitality."},["3280"]={"_dissipatos homines in (ad) societatem vitae convocare_ (Tusc. 1. 25. 62)","to unite isolated individuals into a society."},["3307"]={"_medium sermonem abrumpere_ (Verg. Aen. 4. 388)","to break off in the middle of the conversation."},["3316"]={"_convenire aliquem_","to meet a person (accidentally or intentionally) and talk with him."},["3325"]={"_paucis te volo_","a word with you."},["3334"]={"_aliquem salvere iubere_ (Att. 4. 14)","to greet a person."},["3343"]={"_dextram alicui porrigere, dare_","to give one's right hand to some one."},["3352"]={"_nuptias parare_","to make preparations for a marriage."},["3361"]={"_filiam alicui in matrimonium dare_","to give one's daughter in marriage to some-one."},["3370"]={"_testamentum resignare_","to open a will."},["3406"]={"_negotiatores_[1] (Verr. 2. 69. 168)","business-men."},["3415"]={"_nihil cum aliquo contrahere_","to do no business with a man."},["3424"]={"_pretium alicui rei statuere, constituere_ (Att. 13. 22)","to fix a price for a thing."},["3433"]={"_pecuniam numerare alicui_ (Att. 16. 16)","to pay cash."},["3442"]={"_pecuniam alicui mutuam dare_","to lend money to some one."},["3451"]={"_ratio pecuniarum_","finance; money-matters."},["3460"]={"_rationem alicuius rei inire, subducere_","to go through accounts, make a valuation of a thing."},["3505"]={"_aes alienum_ (always in sing.) _facere, contrahere_","to incur debts."},["3514"]={"_nomina_ (cf. sect. XIII. 3) _solvere, dissolvere, exsolvere_","to pay one's debts."},["3523"]={"_exstruere aedificium, monumentum_","to erect a building, a monument."},["3532"]={"_luminibus alicuius obstruere, officere_[1]","to obstruct a person's view, shut out his light by building."},["3541"]={"_laetae segetes_","the laughing cornfields."},["3550"]={"_messis opīma_ (opp. _ingrata_)","a good harvest."},["3604"]={"_summa res publica_ (or _summa rei publicae_)","the welfare of the state."},["3613"]={"_omnia de re publica praeclara atque egregia sentire_","to have the good of the state at heart."},["3622"]={"_longe prospicere futuros casus rei publicae_ (De Amic. 12. 40)","to foresee political events long before."},["3631"]={"_nobilitati favere_ (Sest. 9. 21)","to be a friend of the aristocracy."},["3640"]={"_infimo loco natus_","from the lowest classes."},["3703"]={"_lex_[4] _iubet, vetat (dilucide, planissime)_","the law orders, forbids (expressly, distinctly)."},["3712"]={"_ea lege, ut_","on condition of..."},["3721"]={"_aurae popularis homo_ (Liv. 42. 30)","a popular man."},["3730"]={"_existimatio populi, hominum_","public opinion."},["3802"]={"_rem publicam funditus evertere_","to completely overthrow the government, the state."},["3811"]={"_tumultum sedare_ (B. C. 3. 18. 3)","to quell an outbreak."},["3820"]={"_in exsilium eicere_ or _expellere aliquem_","to banish a person, send him into exile."},["3901"]={"_rem publicam quaestui habere_","to enrich oneself at the expense of the state."},["3910"]={"_provincias permutare_","to exchange provinces."},["4009"]={"_ius suum persequi_","to assert one's right."},["4018"]={"_iudicia administrare_","to have charge of the administration of justice."},["4027"]={"_ratio iudiciorum_","judicial organisation."},["4036"]={"_contra ius fasque_","against all law, human and divine."},["4045"]={"_in tabulas publicas referre aliquid_","to enter a thing in the public records."},["4054"]={"_aliquem testem dare, edere, proferre_","to produce as a witness."},["4063"]={"_cruciatūs tormentorum_","the pains of torture."},["4072"]={"_causam optimam habere_ (Lig. 4. 10)","to have a good case."},["4081"]={"_causam_ or _litem obtinere_","to win a case."},["4090"]={"_eximere de reis aliquem_","to strike a person's name off the list of the accused."},["4108"]={"_res iudicatas rescindere_ (Cic. Sull. 22. 63)","to rescind a decision."},["4117"]={"_affinem esse culpae_","to be almost culpable."},["4126"]={"_veniam dare alicui_","to pardon a person."},["4135"]={"_hanc poenam constituere in aliquem, ut..._","to ordain as punishment that..."},["4144"]={"_pecunia multare aliquem_","to condemn some one to a fine."},["4153"]={"_Solo capite sanxit, si quis..._ (Att. 10. 1)","Solon made it a capital offence to..."},["4162"]={"_impune fecisse, tulisse aliquid_","to go unpunished."},["4171"]={"_imperare milites civitatibus_","to compel communities to provide troops."},["4180"]={"_milites sacramento rogare, adigere_","to make soldiers take the military oath."},["4207"]={"_stipendium_[1] _dare, numerare, persolvere militibus_","to pay the troops."},["4216"]={"_frumenti vim maximam comparare_","to procure a very large supply of corn."},["4225"]={"_magnas res gerere_","to perform heroic exploits."},["4234"]={"_imperium transfertur ad aliquem_ (not _transit_)","the command is transferred, passes to some one."},["4243"]={"_armis (castris) exuere aliquem_","to disarm a person."},["4252"]={"_ad teli coniectum venire_ (Liv. 2. 31)","to come within javelin-range."},["4261"]={"_decurrere (in armis)_","to manœuvre."},["4270"]={"_bellum facere, movere, excitare_","to cause a war."},["4306"]={"_quam maximis itineribus (potest)_","by the longest possible forced marches."},["4315"]={"_iter non intermittere_","not to interrupt the march."},["4324"]={"_confertis, solutis ordinibus_","with close ranks; with ranks in disorder."},["4333"]={"_opprimere hostes (imprudentes, incautos, inopinantes)_","to surprise and defeat the enemy."},["4342"]={"_praesidiis firmare urbem_","to garrison a town."},["4351"]={"_milites in hibernis collocare, in hiberna deducere_","to take the troops to their winter-quarters."},["4360"]={"_cohors, quae in statione est_","the cohort on guard-duty."},["4405"]={"_ignem inferre operibus_ (B. C. 2. 14)","to set fire to the siege-works."},["4414"]={"_claustra portarum revellere_","to break down the gates."},["4423"]={"_deditione facta_ (Sall. Iug. 26)","after capitulation."},["4432"]={"_aliquem (incolumem) conservare_","to grant a man his life."},["4441"]={"_signum proelii (committendi) exposcere_ (B. G. 7. 19)","to demand loudly the signal to engage."},["4450"]={"_aciem triplicem instruere_ (B. G. 1. 24)","to draw up the army in three lines."},["4504"]={"_tum pes cum pede collatus est_ (Liv. 28. 2)","a hand-to-hand engagement ensued."},["4513"]={"_ferarum_[1] _ritu pugnare_","to fight like lions."},["4522"]={"_cuneum facere_ (Liv. 22. 47)","to draw up troops in a wedge-formation."},["4531"]={"_loco movere, depellere, deicere hostem_ (B. G. 7. 51)","to drive the enemy from his position."},["4540"]={"_se recipere_ (B. G. 7. 20)","to withdraw one's forces."},["4603"]={"_sicut parta iam atque explorata victoria_","as if the victory were already won."},["4612"]={"_indutias violare_","to break a truce."},["4621"]={"_pacis condiciones accipere, subire_ (opp. _repudiare, respuere_)","to accept the terms of the peace."},["4630"]={"_ex pacto, ex foedere_","according to treaty."},["4702"]={"_deferri, deici aliquo_","to be driven out of one's course; to drift."},["4711"]={"_naves (classem) constituere (in alto)_","to make fast boats to anchors."},["4720"]={"_deperire_","to founder, go down."},["4801"]={"_hoc in promptu est_","it is clear, evident."},["4810"]={"_apparet et exstat_","it is quite manifest."}} local grc_RWoodhouse_lemma_to_infinitives = { ["γυμνόω"]={"γεγυμνῶσθαι","γυμνοῦσθαι","γυμνῶσαι","γυμνωθῆναι"},["εἰσκαλέω"]={"ἐσκληθήσεσθαι","εἰσκαλέσαι","εἰσκαλέσασθαι","εἰσκαλεῖν"}} local la_NLW_headwords_to_path = { ["abstrusitas"]={"0/014312"},["astromantis"]={"0/004820"},["bullettinum"]={"3/010911"},["certatorius"]={"0/010912"},["chymisticus"]={"2/016758"},["consepultio"]={"2/017890"},["contramutio"]={"0/015268"},["cunctipotis"]={"3/014687"},["dolioriolus"]={"2/004802"},["floripotens"]={"0/012112"},["fortiuscule"]={"3/013463"},["gymnasiolum"]={"2/011770"},["improperose"]={"3/020215"},["inanunculus"]={"2/008426"},["intermistim"]={"1/007849"},["intertentio"]={"2/003982"},["iubariuomus"]={"3/010511"},["iugigerulus"]={"1/015769"},["lectorculus"]={"2/007902"},["magniloquus"]={"1/017941"},["obsequiolum"]={"3/007899"},["occupatiuus"]={"1/010953"},["oculipotens"]={"2/010510"},["omnisciolus"]={"2/008126"},["onomasticus"]={"1/000941"},["peringenuus"]={"2/020022"},["praeminulus"]={"3/017923"},["propraetura"]={"3/006335"},["prothomater"]={"3/008143"},["quadratulum"]={"2/005634"},["quaquerista"]={"1/014753"},["semitogatus"]={"2/004086"},["sexcentenus"]={"1/003857"},["subiectiuus"]={"0/018740"},["subinfensus"]={"3/009051"},["sublimentum"]={"3/011731"},["subsaluator"]={"0/009424"},["subtersilio"]={"3/012227"},["suggimentum"]={"2/011730"},["superdomino"]={"1/019921"},["superexcubo"]={"3/010375"},["superimpleo"]={"0/003920"},["superintego"]={"2/001354"},["teligerulus"]={"2/009758"},["tuberositas"]={"1/013081"},["tutelariter"]={"3/004563"},["uaneloquium"]={"3/012407"},["uernatiolum"]={"2/003042"},["zunftalitas"]={"1/017689"}} local grc_RLBG_lemma_to_index = { ["ἀρῆνα"]={"8820"},["ἐμμεθοδεύομαι"]={"22060"},["ἑτεροχρονικῶς"]={"27656"},["ζοφόζω"]={"29347"},["κηρώνω"]={"37321"},["κομποφοιβαστής"]={"38405"},["κρούζω"]={"39693"},["μυελόω"]={"46509"},["μυστικοπορνεία"]={"46960"},["παίδας"]={"51684"},["περαία"]={"55402"},["περιοδευομένως"]={"55993"},["προσενωτίζομαι"]={"62103"},["ἀναβίωμα"]={"3466"},["διαχρύσως"]={"16821"},["δροῦγγος"]={"18365"},["δυσκρατόω"]={"18924"},["ἑκαεργία"]={"20477"},["ἔμφλογος"]={"22446"},["ἐξικανόω"]={"24419"},["ἐπινόμιν"]={"26111"},["ἐφόλβιον"]={"29006"},["ἱέραθλος"]={"31857"},["ἰσομερία"]={"32572"},["καρηφόρως"]={"34579"},["κραύρωσις"]={"39429"},["ὀρνιθεία"]={"50769"},["παγγενῶς"]={"51529"},["παλιρωτός"]={"51983"},["πληθοῦρα"]={"57489"},["πρόπεμψις"]={"61403"},["πρόσδοσις"]={"61937"},["προσεπαΐω"]={"62137"},["πρόσξεσις"]={"62756"},["ἀκαρτερησία"]={"1848"},["ἀρκτοπόλιος"]={"8967"},["αὐτουργικός"]={"10956"},["δικαιόσιμον"]={"17226"},["ἐγκυβιστεύω"]={"19818"},["ἐγχειρισμός"]={"19896"},["ἐμβρυοφορέω"]={"22033"},["ἐμπεριβόλως"]={"22189"},["ἐπιστοίχιος"]={"26390"},["ἐπιτελεσμός"]={"26544"},["ἐρυθριδανόω"]={"27275"},["ζευγολόγιον"]={"29252"},["καλοδύναμος"]={"33956"},["κηνσουάλιον"]={"37223"},["κοσμοκτονία"]={"38862"},["μυοκεφάλιον"]={"46630"},["ὀψαροτόπιον"]={"51453"},["παγχρυσομουσόστικτος"]={"51621"}} local la_RMA_lemmas_no_collision_to_ix_phrase = { ["id"]={"575","1100","1518","1522","1523","1529","1848","2227","2229","2230","2235","2236","2244","3484","4794","4813","4834","4835","4838","4840"},["lectissimus"]={"2325"},["patrimonium"]={"3250"}} local grc_RCunliffe_lemma_to_index = { ["φονεύς"]={"9484"},["ἀναθήσει"]={"723"},["ἐδήδαται"]={"2601"},["ἐλεόθρεπτος"]={"3029"},["ἀναδέσμη"]={"716"},["γυμνόω"]={"1976"},["κόσμος"]={"5732"}} local grc_RWoodhouse_lemma_to_headwords = { ["Πάριος"]={"paros"},["Ταρσοί"]={"tarsus"},["κόσμος"]={"adornment","array","attire","constitution","costume","creation","decoration","discipline","dress","embellishment","finely","firmament","garb","government","gown","habit","honour","insignia","millinery","nature","order","ornament","polity","raiment","regime","robe","system","tinsel","trappings","trimming","trinket","universe","world"},["λιχνός"]={"curious","inquisitive"},["φονεύς"]={"assassin","butcher","homicide","murderer","murdress","slaughterer","slayer"},["ἁπλῶς"]={"absolutely","artlessly","candidly","credulously","directly","disinterestedly","fine","formality","frankly","freely","generally","genuinely","grossly","guilelessly","honestly","ingenuously","naively","naturally","openly","outspokenly","plain","plainly","reservation","short","simply","straightforwardly","transparently","unaffectedly","unfeignedly","word"},["Χαλκιδῆς"]={"chalcidice"},["ὀργίζειν"]={"anger","enrage","exasperate","incense","madden","provoke","ruffle"},["ὀρνίθεια"]={"capon","chicked"},["ὑπολύειν"]={"shoe","take","undo","unharness","unyoke"},["ῥητορική"]={"eloquence","oratory","public speaking","rhetoric","speaking"},["φρουρεῖσθαι"]={"beware","guard","mind"},["ἀνυπεύθυνος"]={"arbitrary","irresponsible","unamenable","unauthorised"},["ἀπασπαίρειν"]={"palpitate","pant","quiver","throb"}} return {["freezer"]=freezer,["la_RMA_index_to_phrases"]=la_RMA_index_to_phrases,["grc_RWoodhouse_lemma_to_infinitives"]=grc_RWoodhouse_lemma_to_infinitives,["la_NLW_headwords_to_path"]=la_NLW_headwords_to_path,["grc_RLBG_lemma_to_index"]=grc_RLBG_lemma_to_index,["la_RMA_lemmas_no_collision_to_ix_phrase"]=la_RMA_lemmas_no_collision_to_ix_phrase,["grc_RCunliffe_lemma_to_index"]=grc_RCunliffe_lemma_to_index,["grc_RWoodhouse_lemma_to_headwords"]=grc_RWoodhouse_lemma_to_headwords} a03eujb4k3npimwiuofkcqv4rro781i Padron:R:la:Peck 10 38998 178512 2026-10-27T06:11:35Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=Harry Thurston Peck<!-- -->|title=Harper’s Dictionary of Classical Antiquities<!-- -->|publisher=Harper & Brothers<!-- -->|location=New York<!-- -->|year=1898<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178512 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=Harry Thurston Peck<!-- -->|title=Harper’s Dictionary of Classical Antiquities<!-- -->|publisher=Harper & Brothers<!-- -->|location=New York<!-- -->|year=1898<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> 67qsiz3ai6nmxkwzezw1vgco1v1f4qx Padron:R:la:Platner 10 38999 178513 2026-10-27T06:12:26Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Samuel Ball Platner<!-- -->|editor=Thomas Ashby<!-- -->|title=A Topographical Dictionary of Ancient Rome <!-- -->|publisher=Oxford University Press<!-- -->|location=London<!-- -->|year=1929<!-- -->}}<!-- --><noinclude>{{documentation}}[[Category:English reference templates|Platner]]</noinclude>' 178513 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|author=Samuel Ball Platner<!-- -->|editor=Thomas Ashby<!-- -->|title=A Topographical Dictionary of Ancient Rome <!-- -->|publisher=Oxford University Press<!-- -->|location=London<!-- -->|year=1929<!-- -->}}<!-- --><noinclude>{{documentation}}[[Category:English reference templates|Platner]]</noinclude> dlxj3u62073264v56s3uivj0olk8ujh Module:R:Perseus/collision-data/TDAR 828 39000 178514 2026-10-27T06:12:50Z GinawaSaHapon 3989 Nilikha ang pahina na may 'local t = true local data = { ["anicii-domus"]=t,["arcus-domitiani"]=t,["arcus-drusi"]=t,["arcus-titi"]=t,["arcus-traiani"]=t,["augustus-domus"]=t,["columna-rostrata-c-duilii"]=t,["concordia-aedes"]=t,["diana"]=t,["diana-aedes"]=t,["fortuna"]=t,["fortuna-aedes"]=t,["fortuna-respiciens"]=t,["hercules-templum"]=t,["honos-et-virtus-aedes"]=t,["horti-caesaris"]=t,["horti-lamiani"]=t,["inter-duos-lucos"]=t,["iuno-sospita"]=t,["iuno-sospita-aedes"]=t,["iuppiter-dolich...' 178514 Scribunto text/plain local t = true local data = { ["anicii-domus"]=t,["arcus-domitiani"]=t,["arcus-drusi"]=t,["arcus-titi"]=t,["arcus-traiani"]=t,["augustus-domus"]=t,["columna-rostrata-c-duilii"]=t,["concordia-aedes"]=t,["diana"]=t,["diana-aedes"]=t,["fortuna"]=t,["fortuna-aedes"]=t,["fortuna-respiciens"]=t,["hercules-templum"]=t,["honos-et-virtus-aedes"]=t,["horti-caesaris"]=t,["horti-lamiani"]=t,["inter-duos-lucos"]=t,["iuno-sospita"]=t,["iuno-sospita-aedes"]=t,["iuppiter-dolichenus"]=t,["iuppiter-stator-aedes"]=t,["libertas"]=t,["m-antonius-domus"]=t,["mars-aedes"]=t,["minerva-aedes"]=t,["nymphaeum"]=t,["pietas-aedes"]=t,["porta-aurelia"]=t,["roma-quadrata"]=t,["sep-romuli"]=t,["septizonium"]=t,["thermae-severianae"]=t,["urbis-fanum"]=t,["veiovis-aedes"]=t,["venus-erucina-aedes"]=t,["via-nova"]=t,["via-tecta"]=t,["via-triumphalis"]=t} return data 1cih4c5kifs75k6mprnkddhp1yube6i Padron:R:Smith's Persons 10 39001 178522 2026-10-27T06:41:43Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=William Smith<!-- -->|title=A Dictionary of Greek and Roman Biography and Mythology<!-- -->|publisher=John Murray<!-- -->|location=London<!-- -->|year=1848<!-- -->|others={{#if:{{{author|}}}|entry contributed by {{{author}}}|}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178522 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=William Smith<!-- -->|title=A Dictionary of Greek and Roman Biography and Mythology<!-- -->|publisher=John Murray<!-- -->|location=London<!-- -->|year=1848<!-- -->|others={{#if:{{{author|}}}|entry contributed by {{{author}}}|}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> h5zjqgdpzxb4oasmwk8850qyw1ua15s Padron:R:Smith's Antiquities 10 39002 178523 2026-10-27T06:42:07Z GinawaSaHapon 3989 Nilikha ang pahina na may '{{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=William Smith et al.<!-- -->|title=A Dictionary of Greek and Roman Antiquities<!-- -->|publisher=William Wayte. G. E. Marindin<!-- -->|location=London<!-- -->|year=1890<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude>' 178523 wikitext text/x-wiki {{#invoke:R:Perseus|create}}<!-- -->{{cite-book<!-- -->|editor=William Smith et al.<!-- -->|title=A Dictionary of Greek and Roman Antiquities<!-- -->|publisher=William Wayte. G. E. Marindin<!-- -->|location=London<!-- -->|year=1890<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> 5op52bo6f9ooyyyzoqetcvn5lhkrqej