Wiksiyonaryo tlwiktionary https://tl.wiktionary.org/wiki/Wiksiyonaryo:Unang_Pahina MediaWiki 1.48.0-wmf.1 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 Apendise:Glosaryo 0 35981 178535 178533 2026-10-28T04:09:08Z GinawaSaHapon 3989 178535 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|aktibong tinig|tahasang tinig|active voice}} aktibong tinig, active voice : [[#tinig|tinig]] na nagpapakita sa anyo ng pandiwa kung saan ang simuno mismo ang siyang nagsasagawa sa kilos. Ikumpara sa ''[[#pasibong tinig|pasibong tinig]]'' ; {{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== ; balintiyak na tinig : ''tingnan ang '''{{lg|pasibong tinig}}''''' ; {{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''). ; basal na pangngalan : ''tingnan ang '''{{lg|pangngalang basal}}''''' ; {{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}}''''' ; {{anchor|pasibong tinig|balintiyak na tinig|passive voice}} pasibong tinig, passive voice : [[#tinig|tinig]] na nagpapakita sa anyo ng pandiwa kung saan hindi simuno ang nagsasagawa sa kilos, at minsan ay ito mismo ang tumatanggap ng kilos. Ikumpara sa [[#aktibong tinig|aktibong tinig]]. ; 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== ; tahasang tinig : ''tingnan ang '''{{lg|aktibong tinig}}''''' ; tahas na pangngalan : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; tense : ''tingnan ang '''{{lg|panahon}}''''' ; third person, third-person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ; {{anchor|tinig|voice}} tinig : katangian ng pandiwa na nagpapahiwatig ng kaugnayan nito sa simuno. Ilan sa mga halimbawa ang [[#aktibong tinig|aktibo]] at [[#pasibong tinig|pasibo]]. ; 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}}''''' ; voice : ''tingnan ang '''{{lg|tinig}}''''' ==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}}. kesohclhe6msdfnvi01modjeh6iwtgy 178536 178535 2026-10-28T06:04:22Z GinawaSaHapon 3989 178536 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|aktibong tinig|tahasang tinig|active voice}} aktibong tinig, active voice : [[#tinig|tinig]] na nagpapakita sa anyo ng pandiwa kung saan ang simuno mismo ang siyang nagsasagawa sa kilos. Ikumpara sa ''[[#pasibong tinig|pasibong tinig]]''. ; {{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== ; balintiyak na tinig : ''tingnan ang '''{{lg|pasibong tinig}}''''' ; {{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''). ; basal na pangngalan : ''tingnan ang '''{{lg|pangngalang basal}}''''' ; {{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}}''''' ; indicative : ''tingnan ang '''{{lg|paturol}}''''' ; 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"). ; mood : ''tingnan ang '''{{lg|panagano}}''''' ==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|grammatical mood|mood|panagano}} panagano : anyo ng pandiwa na nagpapahiwatig sa paano sinabi ng nagsasalita ang isang bagay, gaya halimbawa ng ''[[#pasakali|pasakali]]'', na nagpapahiwatig na ang sinabi ay maaaring mangyari. ; {{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}}''''' ; {{anchor|subjunctive|subjunctive mood|pasakali|panaganong pasakali}} pasakali : [[#panagano|panagano]] na nagpapahiwatig na ang sinabi ng nagsasalita ay maaaring mangyari. Ikumpara sa ''[[#paturol|paturol]]'', na naglalarawan sa isang tunay na pangyayari. ; {{anchor|pasibong tinig|balintiyak na tinig|passive voice}} pasibong tinig, passive voice : [[#tinig|tinig]] na nagpapakita sa anyo ng pandiwa kung saan hindi simuno ang nagsasagawa sa kilos, at minsan ay ito mismo ang tumatanggap ng kilos. Ikumpara sa [[#aktibong tinig|aktibong tinig]]. ; 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]]. ; {{anchor|indicative mood|indicative|paturol|panaganong paturol}} paturol : [[papagayo|panagano]] na nagpapahiwatig na ang sinabi ng nagsasalita ay naganap o naglalarawan sa isang tunay na pangyayari o bagay. Ikumpara sa ''[[#pasakali|pasakali]]'', na naglalarawan ng mga pangyayaring maaaring mangyari. ; 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}}''''' ; subjunctive : ''tingnan ang '''{{lg|pasakali}}''''' ; superlatibo, superlative : ''tingnan ang '''{{lg|pasukdol}}''''' ==T== ; tahas na pangngalan : ''tingnan ang '''{{lg|pangngalang tahas}}''''' ; tahasang tinig : ''tingnan ang '''{{lg|aktibong tinig}}''''' ; tense : ''tingnan ang '''{{lg|panahon}}''''' ; third person, third-person : ''tingnan ang '''{{lg|ikatlong panauhan}}''''' ; {{anchor|tinig|voice}} tinig : katangian ng pandiwa na nagpapahiwatig ng kaugnayan nito sa simuno. Ilan sa mga halimbawa ang [[#aktibong tinig|aktibo]] at [[#pasibong tinig|pasibo]]. ; 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}}''''' ; voice : ''tingnan ang '''{{lg|tinig}}''''' ==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}}. 7egexile3qbity7b61a6usbz7g9r9qm Module:etymon 828 38867 178534 178291 2026-10-28T00:20:14Z GinawaSaHapon 3989 178534 Scribunto text/plain --[=[ This module implements the {{etymon}} template for structured etymology data on Wiktionary. It enables the creation of etymology trees and text by parsing etymon chains, scraping linked pages for their own {{etymon}} data, and recursively building a tree of derivational relationships. Authors: - Original implementation: [[en:User:Ioaxxere]] - Full refactor (September 2025): [[en:User:Fenakhay]] ([[en:Special:Diff/86717746]]) Modules: - [[Module:etymon]]: main module handling parsing, validation, tree building, and page scraping - [[Module:etymon/data]]: keyword definitions, configuration, and status constants - [[Module:etymon/tree]]: etymology tree rendering - [[Module:etymon/text]]: etymology text generation - [[Module:etymon/categories]]: category generation logic - [[Module:etymon/tracking]]: tracking ]=] local export = {} local __state = { cached_etymon_args = {}, cached_etymon_pages = {}, cached_descendants_checks = {}, senseid_parent_etymon = {}, available_etymon_ids = {}, single_etymons = {}, entry_title = nil, entry_lang_code = nil, current_page_has_inline_etymology = false, current_page_has_redundant_etymology = false, used_idless_etymon = false, toplevel_has_inline_etymology = false, toplevel_redundant_etymology = false, toplevel_idless_etymon = false, has_mismatched_id = false, linked_page_multiple_etymons_idless = false, linked_page_partial_etymology_sections = false, partial_etymology_targets = {}, skip_partial_etymology_category = false, max_depth_reached = 0, total_nodes = 0, language_count = {}, toplevel_keyword_stats = {}, id_stats = nil, warnings = {}, } local function reset_invocation_state() __state.current_page_has_inline_etymology = false __state.current_page_has_redundant_etymology = false __state.used_idless_etymon = false __state.toplevel_has_inline_etymology = false __state.toplevel_redundant_etymology = false __state.toplevel_idless_etymon = false __state.has_mismatched_id = false __state.linked_page_multiple_etymons_idless = false __state.linked_page_partial_etymology_sections = false __state.max_depth_reached = 0 __state.total_nodes = 0 __state.language_count = {} __state.toplevel_keyword_stats = {} __state.warnings = {} end local M = require("Module:module loader").init({ require = { data = "Module:etymon/data", tree = "Module:etymon/tree", text = "Module:etymon/text", categories = "Module:etymon/categories", tracking = "Module:etymon/tracking", descendants = "Module:etymon/descendants", affix = "Module:affix", anchors = "Module:anchors", etydate = "Module:etydate", etymology = "Module:etymology", families = "Module:families", languages = "Module:languages", languages_errorgetby = "Module:languages/errorGetBy", links = "Module:links", pages = "Module:pages", parameters = "Module:parameters", roots = "Module:roots", string_utilities = "Module:string utilities", template_parser = "Module:template parser", utilities = "Module:utilities", debug = "Module:debug", en_utilities = "Module:en-utilities", parameter_utilities = "Module:parameter utilities", parse_utilities = "Module:parse utilities", template_styles = "Module:TemplateStyles", script_utilities = "Module:script utilities", JSON = "Module:JSON", yesno = "Module:yesno", }, loadData = { headword_data = "Module:headword/data", parameters_data = "Module:parameters/data", text_allowed = "Module:etymon/data/text_allowed", }, }) local Util = {} function Util.format_error(message, preview_only) if preview_only and not M.pages.is_preview() then return nil end return '<span class="error">' .. message .. '</span>' end function Util.add_warning(message, preview_only) local formatted = Util.format_error(message, preview_only) if formatted then table.insert(__state.warnings, formatted) end end function Util.is_text_param_allowed_for_lang(lang) if not lang or type(lang) ~= "table" then return false end local types = lang.getTypes and lang:getTypes() if types and types.family then local code = lang.getCode and lang:getCode() return code and M.text_allowed.families[code] == true end local full_code = lang.getFullCode and lang:getFullCode() if full_code and M.text_allowed.langs[full_code] then return true end if lang.inFamily then for family_code in pairs(M.text_allowed.families) do if lang:inFamily(family_code) then return true end end end return false end function Util.get_lang(code, no_error) if no_error then return M.languages.getByCode(code, nil, true) end return M.languages.getByCode(code, nil, true) or M.languages_errorgetby.code(code, true, true) end -- Match a term language against a text=:lang stop target (supports etymology-only codes). function Util.lang_matches_stop_code(term_lang, stop_code) if not term_lang or not stop_code or stop_code == "" then return false end local stop_lang = Util.get_lang(stop_code, true) if not stop_lang then return false end if term_lang:getCode() == stop_lang:getCode() then return true end if stop_lang:getFullCode() == stop_lang:getCode() then return term_lang:getFullCode() == stop_lang:getCode() end return false end function Util.get_family(code) return M.families.getByCode(code) end function Util.get_lang_exception(lang) -- Families have no language-specific exceptions if lang.getTypes and lang:getTypes().family then return nil end local code = lang:getCode() local lang_exceptions = M.data.config.lang_exceptions if lang_exceptions[code] then return lang_exceptions[code] end for norm_code, exc in pairs(lang_exceptions) do if exc.normalize_to and code == exc.normalize_to then return exc end if exc.normalize_from_families then local should_normalize = false for _, family in ipairs(exc.normalize_from_families) do if lang:inFamily(family) then should_normalize = true break end end if should_normalize and exc.normalize_exclude_families then for _, family in ipairs(exc.normalize_exclude_families) do if lang:inFamily(family) then should_normalize = false break end end end if should_normalize then local ret = {} for k, v in pairs(exc) do ret[k] = v end ret.suppress_tr = nil return ret end end end return nil end function Util.get_norm_lang(lang) local exc = Util.get_lang_exception(lang) if exc and exc.normalize_to then return M.languages.getByCode(exc.normalize_to) end return lang end function Util.resolve_context_lang(lang, node_args) if type(node_args) ~= "table" then return lang end if node_args.status == M.data.STATUS.INLINE then return lang end if not (lang.hasType and lang:hasType("etymology-only")) then return lang end local full = lang.getFull and lang:getFull() if not full or full:getCode() == lang:getCode() then return lang end if full.hasAncestor and full:hasAncestor(lang) then return lang end return full end -- Add default values for boolean modifiers (e.g., <unc> becomes <unc:1>) -- This is needed because Module:parse utilities expects boolean modifiers to have explicit values function Util.add_boolean_defaults(str, param_mods) local result = str for name, spec in pairs(param_mods) do if spec.type == "boolean" then -- Replace <name> with <name:1> (but not <name:...> which already has a value) result = result:gsub("<" .. name .. ">", "<" .. name .. ":1>") end end return result end local REQUEST_TEMPLATE_PARAM_MODS = { rfe = M.parameter_utilities.construct_param_mods { { param = { "sort", "y", "m", "fragment", "section" } }, { param = { "nocat", "box", "noes" }, type = "boolean" }, }, etystub = M.parameter_utilities.construct_param_mods { { param = "sort" }, { param = { "nocat", "nocap", "nodot" }, type = "boolean" }, }, } function Util.expand_request_template(frame, template_name, param_value, lang_code) local param_mods = REQUEST_TEMPLATE_PARAM_MODS[template_name] local with_defaults = Util.add_boolean_defaults(param_value, param_mods) local parsed = M.parse_utilities.parse_inline_modifiers(with_defaults, { param_mods = param_mods, generate_obj = function(text) if M.yesno(text, false) then return { is_boolean = true } end return { text = text } end, }) local template_args = { [1] = lang_code } for name in pairs(param_mods) do template_args[name] = parsed[name] end if not parsed.is_boolean then template_args[2] = parsed.text end return " " .. frame:expandTemplate({ title = template_name, args = template_args, }) end -- Centralized term formatting: handles suppress_term (-), unknown_term (empty/+), and regular terms function Util.format_term(term, is_toplevel, opts) opts = opts or {} -- suppress_term (-) returns nil if term.suppress_term then return nil end local lang = term.lang local exc = Util.get_lang_exception(lang) if is_toplevel then local display_text = term.alt or term.title or "" local sc = term.sc or lang:findBestScript(display_text) local bold_text = tostring(mw.html.create("strong") :addClass("selflink") :wikitext(display_text)) return M.script_utilities.tag_text(bold_text, lang, sc, "term") end local link_params = { lang = lang } link_params.term = not term.unknown_term and (term.link_page or term.title) or nil link_params.alt = term.alt or term.link_page and term.title or nil link_params.id = (not term.unknown_term and term.id and term.id ~= "") and term.id or nil if not (exc and exc.suppress_tr) then link_params.tr = term.tr link_params.ts = term.ts else link_params.suppress_tr = true end link_params.lit = (opts.lit ~= "suppress") and term.lit or nil if opts.gloss ~= "suppress" then link_params.gloss = term.gloss end link_params.genders = term.genders if opts.pos ~= "suppress" then link_params.pos = term.pos link_params.ng = term.ng link_params.infl = term.infl end if exc and exc.suppress_tr then link_params.lit = nil end if opts.tree_ql ~= "suppress" then if term.q then link_params.q = term.q end if term.qq then link_params.qq = term.qq end if term.l then link_params.l = term.l end if term.ll then link_params.ll = term.ll end link_params.show_decorations = term.q or term.qq or term.l or term.ll end return M.links.full_link(link_params, "term") end local __is_content_page_cached function Util.is_content_page() if __is_content_page_cached == nil then __is_content_page_cached = M.pages.is_content_page(mw.title.getCurrentTitle()) end return __is_content_page_cached end local __page_data_cached function Util.get_page_data() if not __page_data_cached then __page_data_cached = M.headword_data.page end return __page_data_cached end -- Extract base keyword from param (without modifiers) local function get_keyword_base(param) if type(param) ~= "string" then return nil end local base = param:match("^:?([^<]+)") or param:gsub("^:", "") return base end local function is_keyword(param, allow_colon_less) if type(param) ~= "string" then return false end local keywords = M.data.keywords if param:sub(1, 1) == ":" then local base = get_keyword_base(param) return keywords[base] ~= nil end if allow_colon_less then local base = get_keyword_base(param) return keywords[base] ~= nil end return false end local function get_keyword(param, allow_colon_less) if type(param) ~= "string" then return nil end local keywords = M.data.keywords if param:sub(1, 1) == ":" then return get_keyword_base(param) end if allow_colon_less then local base = get_keyword_base(param) if keywords[base] then return base end end return nil end local function normalize_keyword(keyword) if keyword:sub(1, 1) == ":" then return keyword end return ":" .. keyword end -- Resolve keyword (possibly an alias) to its canonical form. Used only at input boundaries local function get_canonical_keyword(keyword) if not keyword then return keyword end return M.data.keyword_canonical[keyword] or keyword end local function is_affix_group_keyword(keyword) local config = keyword and M.data.keywords[keyword] return config and config.affix_categories or false end local function reject_removed_surf_keyword(param) local base = get_keyword_base(param) if base == "surf" then error("The `:surf` keyword has been removed. Use `<surf>` on a formation keyword instead (e.g. `:af<surf>`, `:bor<surf>`).") end end local function copy_keyword_info(source) local copy = {} for k, v in pairs(source) do copy[k] = v end return copy end local function lowercase_glossary_display(text) return text:gsub("(%[%[Appendix:Glossary#[^|]+|)([^%]])([^%]]*)%]%]", function(prefix, first, rest) return prefix .. mw.ustring.lower(first) .. rest .. "]]" end) end local function surf_should_keep_formation_phrase(base) if not base.phrase then return false end if base.glossary then return true end return not (base.phrase == "from" and (base.text == "From" or base.text == "from")) end -- Runtime overrides when <surf> is present on a keyword. local function get_effective_keyword_info(keyword, modifiers) local base = M.data.keywords[keyword] if not base or not modifiers or not modifiers.surf then return base end local effective = copy_keyword_info(base) local surf_text = "Sa [[Apendise:Glosaryo#pagsusuri_sa_anyo|pagsusuri sa anyo]]," local surf_phrase = "sa pagsusuri sa anyo," effective.new_sentence = true effective.invisible = "tree" if surf_should_keep_formation_phrase(base) then effective.phrase = surf_phrase .. " " .. base.phrase if base.text then effective.text = surf_text .. " " .. lowercase_glossary_display(base.text) else effective.text = surf_text .. " " .. base.phrase end else effective.text = surf_text effective.phrase = surf_phrase end return effective end -- Build text/phrase for nominalization with <g:code> (uses data module for codes only). local function get_nominalization_label_for_g(code) if not code or code == "" then return nil end local codes = M.data.nominalization_g_codes local adj = codes[code] if not adj and #code == 2 then local gender_adj = codes[code:sub(1, 1)] local number_adj = codes[code:sub(2, 2)] if gender_adj and number_adj then adj = gender_adj .. " " .. number_adj end end if not adj then return nil end local text = adj:gsub("^%l", function(c) return string.upper(c) end) .. " [[Appendix:Glossary#nominalization|nominalization]] of" local phrase = M.en_utilities.add_indefinite_article(adj .. " [[Appendix:Glossary#nominalization|nominalization]] of", false) return { text = text, phrase = phrase } end local EtymonParser = {} -- Keyword modifier definitions EtymonParser.keyword_param_mods = M.parameter_utilities.construct_param_mods { { group = "ref" }, { param = "conj" }, -- conjunction for alternatives: "and", "or", "and/or", etc. { param = { "unc", "surf" }, type = "boolean" }, { param = "text", restrict = { keywords = { "from", "derived" } } }, { param = "lit", restrict = { affix_group = true } }, { param = "g", restrict = { keywords = { "nominalization" } } }, { param = "senseid", restrict = { keywords = { "semantic loan" } } }, } -- Term modifier definitions EtymonParser.etymon_param_mods = M.parameter_utilities.construct_param_mods { {group = {"link", "q", "l", "ref", "infl"}, exclude = {"sc"}}, {param = {"ety", "postype"}}, {param = "unc", type = "boolean"}, {param = "aftype", restrict = {affix_group = true}}, {param = {"bor", "slbor", "lbor"}, type = "boolean", restrict = {affix_group = true}}, } local function get_clean_param_mods(param_mods) local clean = {} for mod_name, mod_def in pairs(param_mods) do clean[mod_name] = {} for key, value in pairs(mod_def) do if key ~= "restrict" then clean[mod_name][key] = value end end end return clean end function EtymonParser.check_modifier_restrictions(modifiers, current_keyword, param_mods) for mod_name, mod_value in pairs(modifiers) do -- Only check restrictions if the modifier has a non-false/nil value if mod_value then local mod_def = param_mods[mod_name] if mod_def and mod_def.restrict then if mod_def.restrict.affix_group then if not is_affix_group_keyword(current_keyword) then local mod_display = mod_value == true and "<" .. mod_name .. ">" or "<" .. mod_name .. ":" .. tostring(mod_value) .. ">" error("The modifier `" .. mod_display .. "` is only allowed for affix-group keywords (e.g. `:af`, `:blend`, `:univ`).") end elseif mod_def.restrict.keywords then local allowed_keywords = mod_def.restrict.keywords local is_allowed = false for _, allowed_keyword in ipairs(allowed_keywords) do if current_keyword == allowed_keyword then is_allowed = true break end end if not is_allowed then local keyword_list = {} for _, kw in ipairs(allowed_keywords) do table.insert(keyword_list, ":" .. kw) end local keyword_str = table.concat(keyword_list, #keyword_list == 2 and " or " or ", ") if #keyword_list > 2 then -- Replace last comma with "or" keyword_str = keyword_str:gsub(", ([^,]+)$", " or %1") end local mod_display = mod_value == true and "<" .. mod_name .. ">" or "<" .. mod_name .. ":" .. tostring(mod_value) .. ">" error("The modifier `" .. mod_display .. "` is only allowed for the keyword" .. (#keyword_list > 1 and "s " or " ") .. keyword_str .. ".") end end end end end end local TERM_RULE_DISALLOW = { suppress = { field = "suppress_term", label = "suppressed" }, unknown = { field = "unknown_term", label = "unknown" }, family = { field = "is_family", label = "family" }, } function EtymonParser.check_etymon_limits(count, limits, label, opts) if not limits then return end opts = opts or {} local min_etymons = limits.min_etymons if min_etymons == nil and not opts.skip_default_min then min_etymons = 1 end if min_etymons and count < min_etymons then if min_etymons > 1 then error("Detected " .. label .. " group with fewer than " .. min_etymons .. " etymons.") else error("Detected " .. label .. " with no etymons.") end end if limits.max_etymons and count > limits.max_etymons then local unit = (limits.max_etymons == 1) and "etymon" or "etymons" error("Detected " .. label .. " with more than " .. limits.max_etymons .. " " .. unit .. ".") end end function EtymonParser.check_term_rules(etymon_data, entry_lang, rules, label) label = label or "term" if rules and rules.disallow then local disallowed = {} for _, typ in ipairs(rules.disallow) do local spec = TERM_RULE_DISALLOW[typ] if spec and etymon_data[spec.field] then table.insert(disallowed, spec.label) end end if #disallowed > 0 then error(label .. " does not support " .. mw.text.listToText(disallowed, "or") .. " etymons.") end end if etymon_data.is_family then if rules and rules.family == "disallowed" then error(label .. " does not support family codes" .. (rules.family_suffix or ".")) elseif not etymon_data.suppress_term then error("Family codes require suppressed term (use family:-).") end end if rules then if rules.require_term and (not etymon_data.term or etymon_data.term == "") then error(label .. " requires a term for each listed form.") end if rules.entry_lang then if Util.get_norm_lang(etymon_data.lang):getFullCode() ~= Util.get_norm_lang(entry_lang):getFullCode() then error(label .. " terms must be in the entry language (" .. entry_lang:getFullCode() .. "), got '" .. etymon_data.lang:getFullCode() .. "'.") end end if rules.ancestor_check then M.etymology.check_ancestor(entry_lang, etymon_data.lang) end elseif etymon_data.is_family and not etymon_data.suppress_term then error("Family codes require suppressed term (use family:-).") end end function EtymonParser.check_keyword_term(etymon_data, entry_lang, keyword) local config = M.data.keywords[keyword] EtymonParser.check_term_rules(etymon_data, entry_lang, config and config.term_rules, "`:" .. keyword .. "`") end function EtymonParser.check_supplement_term(etymon_data, entry_lang, supplement_type) local config = M.data.supplements[supplement_type] EtymonParser.check_term_rules(etymon_data, entry_lang, config and config.term_rules, "|" .. supplement_type .. "=") end -- Parse keyword with modifiers (e.g., ":bor<unc>" or ":bor<ref:{{R:example}}>") function EtymonParser.parse_keyword_modifiers(param) if type(param) ~= "string" then return nil, {} end local base_keyword = get_keyword_base(param) if not base_keyword then return nil, {} end local canonical_keyword = get_canonical_keyword(base_keyword) -- Check if there are any modifiers if not param:find("<", 1, true) then return canonical_keyword, {} end -- Parse modifiers using the same mechanism as etymon parsing local rest_with_defaults = Util.add_boolean_defaults(param, EtymonParser.keyword_param_mods) local function generate_obj(ignored) return {} end local parsed = M.parse_utilities.parse_inline_modifiers(rest_with_defaults:gsub("^:?[^<]+", ""), { param_mods = get_clean_param_mods(EtymonParser.keyword_param_mods), generate_obj = generate_obj }) local modifiers = { unc = parsed.unc or false, refs = parsed.refs, text = parsed.text, lit = parsed.lit, conj = parsed.conj, g = parsed.g, surf = parsed.surf or false, senseid = parsed.senseid, } -- Validate modifiers against restrictions EtymonParser.check_modifier_restrictions(modifiers, canonical_keyword, EtymonParser.keyword_param_mods) return canonical_keyword, modifiers end local function normalize_keyword_param(keyword_with_mods) local trimmed = M.string_utilities.trim(keyword_with_mods) reject_removed_surf_keyword(trimmed:match("^:") and trimmed or (":" .. trimmed)) local base = get_keyword_base(trimmed) if not base or not M.data.keywords[base] then error("Invalid keyword '" .. trimmed .. "' in inline etymology") end local canonical_base = get_canonical_keyword(base) local without_colon = trimmed:gsub("^:", "") local mods_part = without_colon:sub(#base + 1) local kw_param = normalize_keyword(canonical_base .. mods_part) EtymonParser.parse_keyword_modifiers(kw_param) return kw_param end local function get_keyword_mod_names() local names = {} for mod_name in pairs(EtymonParser.keyword_param_mods) do names[mod_name] = true end return names end local function parse_inline_ety_run(ety_string) local body = ety_string or "" if body == "" then error("Empty inline etymology") end local keyword_mod_names = get_keyword_mod_names() local pos = 1 local len = #body local function parse_err(msg) error(msg .. " in inline etymology: '" .. body .. "'") end local function peek_double() return body:sub(pos, pos + 1) == "<<" end local function mod_name_from_unwrapped(unwrapped) return unwrapped:match("^<([^:>]+)") end local function is_keyword_mod(unwrapped) local name = mod_name_from_unwrapped(unwrapped) return name and keyword_mod_names[name] or false end local function read_double_bracket() if not peek_double() then return nil end local start = pos pos = pos + 2 while pos <= len - 1 do if body:sub(pos, pos + 1) == ">>" then local token = body:sub(start, pos + 1) pos = pos + 2 return token, token:sub(2, -2) end pos = pos + 1 end parse_err("Unmatched <<") end local function read_angle_cell() if body:sub(pos, pos) ~= "<" or peek_double() then return nil end local open = pos pos = pos + 1 local depth = 1 local i = pos while i <= len do local ch = body:sub(i, i) if ch == "<" then depth = depth + 1 elseif ch == ">" then depth = depth - 1 if depth == 0 then local inner = body:sub(open + 1, i - 1) pos = i + 1 return inner end end i = i + 1 end parse_err("Unmatched <") end local function read_bare_run() local start = pos while pos <= len and body:sub(pos, pos) ~= "<" do pos = pos + 1 end return body:sub(start, pos - 1) end local function absorb_double_keyword_mods(keyword_str) while peek_double() do local saved = pos local _, unwrapped = read_double_bracket() if is_keyword_mod(unwrapped) then keyword_str = keyword_str .. unwrapped else pos = saved break end end return keyword_str end local kw_start = pos while pos <= len and body:sub(pos, pos) ~= "<" do pos = pos + 1 end local keyword = body:sub(kw_start, pos - 1) if keyword:match("^%s*$") then parse_err("Missing keyword") end keyword = absorb_double_keyword_mods(keyword) local cells = {} while pos <= len do if peek_double() then local _, unwrapped = read_double_bracket() if is_keyword_mod(unwrapped) then parse_err("Unexpected keyword modifier " .. unwrapped .. " outside of a keyword") end table.insert(cells, "+" .. unwrapped) elseif body:sub(pos, pos) == "<" then local inner = read_angle_cell() if inner ~= "" then table.insert(cells, inner) end else local bare = read_bare_run() if bare ~= "" then if bare:sub(1, 1) ~= ":" then parse_err("Unexpected bare text '" .. bare .. "' (use :keyword for nested keywords in inline etymology)") end if not is_keyword(bare, true) then parse_err("Invalid keyword '" .. bare .. "' in inline etymology") end table.insert(cells, absorb_double_keyword_mods(bare)) end end end return { keyword = keyword, cells = cells, } end function EtymonParser.inline_ety_to_pipe(ety_string) local run = parse_inline_ety_run(ety_string) if not run.keyword or run.keyword:match("^%s*$") then return "|" end local pipe_parts = { normalize_keyword_param(M.string_utilities.trim(run.keyword)) } for _, segment in ipairs(run.cells) do if is_keyword(segment, true) then table.insert(pipe_parts, normalize_keyword_param(segment)) else table.insert(pipe_parts, segment) end end return "|" .. table.concat(pipe_parts, "|") .. "|" end function EtymonParser.pipe_to_inline_ety(pipe_string) local cells = {} for cell in pipe_string:gmatch("([^|]+)") do if cell ~= "" then table.insert(cells, cell) end end if #cells == 0 then return "" end local inline_parts = {} for index, cell in ipairs(cells) do local base = get_keyword_base(cell) if base and M.data.keywords[base] then local without_colon = cell:gsub("^:", "") local kw_base, mods = without_colon:match("^([^<]+)(.*)$") local inline_kw = (kw_base or without_colon) .. (mods or ""):gsub("<([^>]+)>", "<<%1>>") if index > 1 then inline_kw = ":" .. inline_kw end table.insert(inline_parts, inline_kw) elseif cell:sub(1, 1) == "+" then local mod = cell:sub(2) if mod:match("^<.->$") then mod = mod:sub(2, -2) end table.insert(inline_parts, "<<" .. mod .. ">>") else table.insert(inline_parts, "<" .. cell .. ">") end end return table.concat(inline_parts, "") end function EtymonParser.parse_inline_ety(ety_string, context_lang) local run = parse_inline_ety_run(ety_string) local keyword = M.string_utilities.trim(run.keyword) reject_removed_surf_keyword(":" .. keyword) if not is_keyword(keyword, true) then error("Invalid keyword '" .. keyword .. "' in inline etymology <ety:" .. keyword .. "...>") end local args = { context_lang:getCode(), normalize_keyword_param(keyword) } for _, segment in ipairs(run.cells) do if is_keyword(segment, true) then table.insert(args, normalize_keyword_param(segment)) else table.insert(args, segment) end end return args end function EtymonParser.parse_etymon(param, context_lang) if is_keyword(param) then return nil end if type(param) ~= "string" then return nil end local lang, rest local is_family = false local before_bracket = param:match("^([^<]*)") or param local lang_code, rest_match = before_bracket:match("^([a-zA-Z][a-zA-Z0-9._-]*):(.*)$") if lang_code then local potential_lang = Util.get_lang(lang_code, true) if potential_lang then lang = potential_lang rest = param:sub(#lang_code + 2) else local potential_family = Util.get_family(lang_code) if potential_family then lang = potential_family rest = param:sub(#lang_code + 2) is_family = true else lang = context_lang rest = param end end else lang = context_lang rest = param end M.tracking.track_term(rest) if rest == "" or rest == "+" then return { lang = lang, term = nil, unknown_term = true, is_family = is_family, } end if rest == "-" then return { lang = lang, term = nil, suppress_term = true, is_family = is_family, } end if not rest:find("<", 1, true) then return { lang = lang, term = M.string_utilities.trim(rest), is_family = is_family, } end local term_text = rest:match("^([^<]*)") or "" local is_unknown = (term_text == "" or term_text == "+") local is_suppress = (term_text == "-") local function generate_obj(ignored_term) return { term = (is_unknown or is_suppress) and nil or M.string_utilities.trim(term_text) } end local rest_with_defaults = Util.add_boolean_defaults(rest, EtymonParser.etymon_param_mods) local parsed_obj = M.parse_utilities.parse_inline_modifiers(rest_with_defaults, { param_mods = get_clean_param_mods(EtymonParser.etymon_param_mods), generate_obj = generate_obj }) if parsed_obj.id and parsed_obj.id:match("^!") then parsed_obj.id = parsed_obj.id:sub(2) parsed_obj.override = true end parsed_obj.lang = lang parsed_obj.is_family = is_family if is_unknown then parsed_obj.unknown_term = true elseif is_suppress then parsed_obj.suppress_term = true end return parsed_obj end function EtymonParser.validate(lang, args, id, title, pos, starts_with_lang_code) -- id is now optional, so only validate if provided if id then if mw.ustring.len(id) < 2 then error("The `id` parameter must have at least two characters.") end if id == title or id == Util.get_page_data().pagename then error("The `id` parameter must not be the same as the page title.") end end local valid_pos = { prefix = true, suffix = true, interfix = true, infix = true, root = true, word = true } if pos and not valid_pos[pos] then error("Unknown value provided for `pos`. Valid values: " .. table.concat(require("Module:table").keysToList(valid_pos), ", ") .. ".") end local current_keyword = "from" local current_keyword_explicit = false local keyword_etymons = {} local keywords = M.data.keywords local function checkKeyword() local config = keywords[current_keyword] if current_keyword == "from" and not current_keyword_explicit and #keyword_etymons == 0 then keyword_etymons = {} return end EtymonParser.check_etymon_limits(#keyword_etymons, config, "`:" .. current_keyword .. "`") keyword_etymons = {} end local start_index = starts_with_lang_code and 2 or 1 for i = start_index, #args do local param = args[i] if type(param) ~= "string" then elseif param:sub(1, 1) == ":" and not is_keyword(param) then reject_removed_surf_keyword(param) error("Invalid keyword '" .. param .. "'. Did you mean a valid keyword like ':bor', ':inh', etc.?") elseif is_keyword(param) then checkKeyword() current_keyword = get_canonical_keyword(get_keyword(param)) current_keyword_explicit = true else local etymon_data = EtymonParser.parse_etymon(param, lang) if etymon_data then table.insert(keyword_etymons, param) EtymonParser.check_keyword_term(etymon_data, lang, current_keyword) -- Check modifier restrictions EtymonParser.check_modifier_restrictions(etymon_data, current_keyword, EtymonParser.etymon_param_mods) -- postype must be "root" or "word" local VALID_POSTYPES = { root = true, word = true } if etymon_data.postype and not VALID_POSTYPES[etymon_data.postype] then error("Invalid <postype:" .. etymon_data.postype .. ">; must be \"root\" or \"word\".") end if etymon_data.ety then local inline_args = EtymonParser.parse_inline_ety(etymon_data.ety, etymon_data.lang) EtymonParser.validate(etymon_data.lang, inline_args, nil, nil, nil, true) end else table.insert(keyword_etymons, param) end end end checkKeyword() end local DataRetriever = {} local function format_etymon_id_hint(id_data, idx) local id = type(id_data) == "table" and id_data.id or id_data local pos = type(id_data) == "table" and id_data.pos if id and id ~= "" and id ~= "*" then return '"' .. id .. '"' end if pos and pos ~= "" then return "unnamed (|pos=" .. pos .. "|)" end return "etymon #" .. idx .. " (no |id= on page)" end local function etymon_target_page_link(page, norm_lang) return M.links.full_link({ term = page, lang = norm_lang, no_generate_alternants = true, }, "term") end -- Summarize {{etymon}} id slots on a linked page for preview warnings. local function summarize_available_etymon_ids(ids) local id_list = {} local all_idless = true local target_has_idless = false local any_pos = false for i, id_data in ipairs(ids) do local id = type(id_data) == "table" and id_data.id or id_data local pos = type(id_data) == "table" and id_data.pos if id and id ~= "" and id ~= "*" then all_idless = false else target_has_idless = true end if pos and pos ~= "" then any_pos = true end table.insert(id_list, format_etymon_id_hint(id_data, i)) end return { id_list = id_list, all_idless = all_idless, target_has_idless = target_has_idless, any_pos = any_pos, count = #ids, options_text = mw.text.listToText(id_list), } end local function ambiguous_etymon_suggestion(page_link, summary) if summary.all_idless then if summary.any_pos then return " None set `|id=` yet; add a unique `|id=` to each on " .. page_link .. ", then `<id:identifier>` after the term here. Section order / hints: " .. summary.options_text .. "." end return " None set `|id=` yet; add a unique `|id=` to each {{etymon}} in that section from top to bottom, then `<id:identifier>` after the term here (same value as `|id=`)." end return " Specify which one with `<id:identifier>` after the term. Options: " .. summary.options_text .. "." end local function warn_ambiguous_etymon_link(page, norm_lang, ids, is_toplevel) local page_link = etymon_target_page_link(page, norm_lang) local summary = summarize_available_etymon_ids(ids) if is_toplevel and summary.target_has_idless then __state.linked_page_multiple_etymons_idless = true end local lang_name = norm_lang:getCanonicalName() local lead = "Etymology link to " .. page_link .. " is ambiguous (" .. summary.count .. " {{etymon}} templates for " .. lang_name .. ")." Util.add_warning(lead .. ambiguous_etymon_suggestion(page_link, summary), true) end local function is_mismatched_explicit_id(base_key, cached_args, parent_etymon) return cached_args == M.data.STATUS.MISSING and not parent_etymon and #(__state.available_etymon_ids[base_key] or {}) > 0 end local function maybe_flag_partial_etymology_reference(base_key, etymon_data, cached_args, is_toplevel) if not is_toplevel or __state.skip_partial_etymology_category then return end if not __state.partial_etymology_targets[base_key] then return end if etymon_data.id and type(cached_args) == "table" then return end __state.linked_page_partial_etymology_sections = true end local function is_nonlemma_etymon_template(template_args) return template_args and M.yesno(template_args.nl, false) end local function warn_mismatched_explicit_id(page, norm_lang, base_key, etymon_id) local page_link = etymon_target_page_link(page, norm_lang) local summary = summarize_available_etymon_ids(__state.available_etymon_ids[base_key] or {}) local lang_name = norm_lang:getCanonicalName() local lead = "Etymology link to " .. page_link .. " uses `<id:" .. etymon_id .. ">`, but no {{etymon}} on that page has `|id=" .. etymon_id .. "|` for " .. lang_name .. "." Util.add_warning(lead .. " Valid IDs: " .. summary.options_text .. ".", true) end -- Given an etymon data, scrape its page and cache the result in the global state object. function DataRetriever.cache_page_etymons(etymon_page, etymon_title, key, etymon_lang, etymon_id, redirected_from, descendants_is_toplevel) local content = etymon_title:getContent() if not content then __state.cached_etymon_args[key] = M.data.STATUS.REDLINK return end -- Check if the linked page is a redirect. If it is, the template parsing -- code below will be effectively skipped, and `scrape_page` will be called -- again on the redirect target (see the bottom of this function) local lang_section_for_descendants = nil local redirect_target = etymon_title.redirect_target if not redirect_target then content = M.pages.get_section(content, etymon_lang:getFullName(), 2) if not content then __state.cached_etymon_args[key] = M.data.STATUS.MISSING return end lang_section_for_descendants = content end local etymon_lang_code = etymon_lang:getFullCode() local lang_page_key = etymon_lang_code .. ":" .. etymon_page local found_templates_for_lang = {} local found_ids = {} local get_node_class = M.template_parser.class_else_type -- Look for all {{etymon}} templates within the page content using the template parser -- This way the same page is never parsed more than once -- Build a map from senseids to their parent etymonids. local active_etymon_args = nil local etymology_section_count = 0 local etymology_sections_with_etymon = 0 local current_etymology_has_etymon = false local current_etymology_has_nonlemma = false local function finalize_current_etymology_section() if etymology_section_count == 0 then return end if current_etymology_has_etymon or current_etymology_has_nonlemma then etymology_sections_with_etymon = etymology_sections_with_etymon + 1 end current_etymology_has_etymon = false current_etymology_has_nonlemma = false end for node in M.template_parser.parse(content):iterate_nodes() do local node_class = get_node_class(node) if node_class == "heading" then -- A new L2 or etymology section acts as a barrier: an {{etymon}} usage -- used previously cannot be the parent of any subsequent senseids. -- Note that we don't have to check for L2s due to the usage of `M.pages.get_section` above. if node:get_name():find("^Etymology") then finalize_current_etymology_section() etymology_section_count = etymology_section_count + 1 active_etymon_args = nil end elseif node_class == "template" then local template_name = node:get_name() if template_name == "etymon" then local template_args = node:get_arguments() -- Check if this etymon is for our language if template_args[1] == etymon_lang_code then if is_nonlemma_etymon_template(template_args) then if etymology_section_count > 0 then current_etymology_has_nonlemma = true end else if etymology_section_count > 0 then current_etymology_has_etymon = true end table.insert(found_templates_for_lang, template_args) if template_args.id then local etymon_key = lang_page_key .. ":" .. template_args.id __state.cached_etymon_args[etymon_key] = template_args __state.cached_etymon_pages[etymon_key] = tostring(etymon_page) table.insert(found_ids, template_args.id) active_etymon_args = template_args else -- Store idless etymon with default key local etymon_key = lang_page_key .. ":*" __state.cached_etymon_args[etymon_key] = template_args __state.cached_etymon_pages[etymon_key] = tostring(etymon_page) table.insert(found_ids, "*") active_etymon_args = template_args end end end elseif active_etymon_args and template_name == "senseid" then local template_args = node:get_arguments() -- This should always be true for proper usages of {{senseid}}. if template_args[1] == etymon_lang_code and template_args[2] then local sense_id_key = lang_page_key .. ":" .. template_args[2] __state.senseid_parent_etymon[sense_id_key] = active_etymon_args __state.cached_etymon_pages[sense_id_key] = tostring(etymon_page) end end end end finalize_current_etymology_section() if lang_section_for_descendants and etymology_section_count > 1 and etymology_sections_with_etymon > 0 and etymology_sections_with_etymon < etymology_section_count then __state.partial_etymology_targets[lang_page_key] = true end if descendants_is_toplevel and lang_section_for_descendants and #found_templates_for_lang > 0 then M.descendants.cache_page_checks({ lang_section = lang_section_for_descendants, etymon_lang_code = etymon_lang_code, found_templates_for_lang = found_templates_for_lang, entry_title = __state.entry_title, entry_lang_code = __state.entry_lang_code, entry_lang = __state.entry_lang_code and Util.get_lang(__state.entry_lang_code, true) or nil, cached_descendants_checks = __state.cached_descendants_checks, lang_page_key = lang_page_key, redirected_from = redirected_from, }) end local id_data_list = {} for _, args in ipairs(found_templates_for_lang) do local id = args.id or "*" table.insert(id_data_list, { id = id, pos = args.pos }) end __state.available_etymon_ids[lang_page_key] = id_data_list if #found_templates_for_lang == 1 then __state.single_etymons[lang_page_key] = found_templates_for_lang[1] end if redirected_from and __state.available_etymon_ids[lang_page_key] then __state.available_etymon_ids[redirected_from] = __state.available_etymon_ids[redirected_from] or {} for _, id_data in ipairs(__state.available_etymon_ids[lang_page_key]) do table.insert(__state.available_etymon_ids[redirected_from], id_data) end end if __state.cached_etymon_args[key] ~= nil or __state.senseid_parent_etymon[key] ~= nil then -- All done! return elseif redirect_target and not redirected_from then -- Try scraping the redirect. etymon_page = redirect_target.prefixedText DataRetriever.cache_page_etymons(etymon_page, redirect_target, lang_page_key .. ":" .. etymon_id, etymon_lang, etymon_id, lang_page_key, descendants_is_toplevel) __state.cached_etymon_args[key] = __state.cached_etymon_args[etymon_lang_code .. ":" .. etymon_page .. ":" .. etymon_id] else __state.cached_etymon_args[key] = M.data.STATUS.MISSING end end local function has_linkable_term(etymon_data) if etymon_data.is_family or etymon_data.suppress_term or etymon_data.unknown_term then return false end local term = etymon_data.term if term == nil or term == "" then return false end return M.string_utilities.trim(term) ~= "" end local function map_affix_part(etymon_data) if etymon_data.alt or not has_linkable_term(etymon_data) or etymon_data.term:find("^%^") then return end local affix_type = etymon_data.aftype and (M.data.aftype_aliases[etymon_data.aftype] or etymon_data.aftype) or nil local _, link_term, display_term = M.affix.parse_term_for_affixes(etymon_data.term, etymon_data.lang, nil, affix_type, true, nil, etymon_data.id) if link_term ~= display_term then etymon_data.term = link_term etymon_data.alt = display_term end end local function get_term_page(etymon_data) return etymon_data.link_page or M.links.get_link_page(etymon_data.term, etymon_data.lang) end local function is_root_term(etymon_data, keyword) if etymon_data.postype then return etymon_data.postype == "root" end local config = keyword and M.data.keywords[keyword] return config ~= nil and config.pos_override == "root" end local function record_term_id_tracking(etymon_data) if not has_linkable_term(etymon_data) then return end local term_page = get_term_page(etymon_data) M.tracking.record_term_id_usage(__state.id_stats, etymon_data, term_page) end -- Given an etymon object, scrape its page (if necessary) and return its own etymon arguments as well as the page name. function DataRetriever.get_etymon_args(etymon_data, is_toplevel) if not has_linkable_term(etymon_data) then return M.data.STATUS.MISSING, nil, nil, nil end local page = get_term_page(etymon_data) local norm_lang = Util.get_norm_lang(etymon_data.lang) local base_key = norm_lang:getFullCode() .. ":" .. page if etymon_data.id then local key = base_key .. ":" .. etymon_data.id local cached_args = __state.cached_etymon_args[key] or __state.senseid_parent_etymon[key] if cached_args == nil then local title = mw.title.new(page) if not title then error('Invalid page title "' .. page .. '" encountered.') end DataRetriever.cache_page_etymons(page, title, key, norm_lang, etymon_data.id, nil, is_toplevel) end cached_args = __state.cached_etymon_args[key] or __state.senseid_parent_etymon[key] -- refresh -- Get etymon_id from parent if this was resolved via senseid local parent_etymon = __state.senseid_parent_etymon[key] local resolved_etymon_id = parent_etymon and parent_etymon.id local descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = is_toplevel, base_key = base_key, lookup = { explicit_id = etymon_data.id, parent_etymon = parent_etymon, }, }) if is_toplevel and descendants_check == nil then local title = mw.title.new(page) if title then DataRetriever.cache_page_etymons(page, title, key, norm_lang, etymon_data.id, nil, true) descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = true, base_key = base_key, lookup = { explicit_id = etymon_data.id, parent_etymon = parent_etymon, }, }) end end local mismatched_id = is_mismatched_explicit_id(base_key, cached_args, parent_etymon) if mismatched_id and is_toplevel then __state.has_mismatched_id = true M.tracking.record_mismatched_id_usage(__state.id_stats, norm_lang, page, etymon_data.id) warn_mismatched_explicit_id(page, norm_lang, base_key, etymon_data.id) end maybe_flag_partial_etymology_reference(base_key, etymon_data, cached_args, is_toplevel) return cached_args, __state.cached_etymon_pages[key], resolved_etymon_id, descendants_check else __state.used_idless_etymon = true if is_toplevel then __state.toplevel_idless_etymon = true end if __state.available_etymon_ids[base_key] == nil then local title = mw.title.new(page) if not title then error('Invalid page title "' .. page .. '" encountered.') end DataRetriever.cache_page_etymons(page, title, base_key .. ":*", norm_lang, "*", nil, is_toplevel) end local ids = __state.available_etymon_ids[base_key] or {} local count = #ids -- Try to filter by postype if available and we have multiple candidates if count > 1 and etymon_data.postype then local matching_ids = {} for _, id_data in ipairs(ids) do if id_data.pos == etymon_data.postype then table.insert(matching_ids, id_data) end end if #matching_ids == 1 then local matched_id = matching_ids[1].id local matched_key = base_key .. ":" .. matched_id M.tracking.record_idless_resolution(__state.id_stats, norm_lang, page, "postype") local descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = is_toplevel, base_key = base_key, lookup = { id = matched_id }, }) if is_toplevel and descendants_check == nil then local title = mw.title.new(page) if title then DataRetriever.cache_page_etymons(page, title, base_key .. ":*", norm_lang, "*", nil, true) descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = true, base_key = base_key, lookup = { id = matched_id }, }) end end local matched_args = __state.cached_etymon_args[matched_key] maybe_flag_partial_etymology_reference(base_key, etymon_data, matched_args, is_toplevel) return matched_args, __state.cached_etymon_pages[matched_key], nil, descendants_check end end if count == 1 then local only_id_data = ids[1] local only_id = (type(only_id_data) == "table" and only_id_data.id) or only_id_data or "*" M.tracking.record_idless_resolution(__state.id_stats, norm_lang, page, "single") local descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = is_toplevel, base_key = base_key, lookup = { id_data = only_id_data }, }) if is_toplevel and descendants_check == nil then local title = mw.title.new(page) if title then DataRetriever.cache_page_etymons(page, title, base_key .. ":*", norm_lang, "*", nil, true) descendants_check = M.descendants.get_lookup_check({ cached_descendants_checks = __state.cached_descendants_checks, is_toplevel = true, base_key = base_key, lookup = { id_data = only_id_data }, }) end end local single_args = __state.single_etymons[base_key] maybe_flag_partial_etymology_reference(base_key, etymon_data, single_args, is_toplevel) return single_args, __state.cached_etymon_pages[base_key .. ":" .. only_id], nil, descendants_check elseif count > 1 then M.tracking.record_idless_resolution(__state.id_stats, norm_lang, page, "ambiguous") warn_ambiguous_etymon_link(page, norm_lang, ids, is_toplevel) maybe_flag_partial_etymology_reference(base_key, etymon_data, M.data.STATUS.AMBIGUOUS, is_toplevel) return M.data.STATUS.AMBIGUOUS, nil, nil, nil else M.tracking.record_idless_resolution(__state.id_stats, norm_lang, page, "missing") maybe_flag_partial_etymology_reference(base_key, etymon_data, M.data.STATUS.MISSING, is_toplevel) return M.data.STATUS.MISSING, nil, nil, nil end end end local function keyword_invisible_in_tree(keyword_info) if not keyword_info then return false end local inv = keyword_info.invisible return inv == "all" or inv == true or inv == "tree" end -- True when the node has at least one top-level child container visible in the tree. local function node_has_visible_tree_children(node) for _, container in ipairs(node.children or {}) do if not keyword_invisible_in_tree(container.keyword_info) then return true end end return false end -- Count visible term nodes in the tree. local function get_visible_tree_depth(node, skip_child_rendering) local max_depth = 1 if skip_child_rendering or not node then return max_depth end for _, container in ipairs(node.children or {}) do local keyword_info = container.keyword_info if not keyword_invisible_in_tree(keyword_info) then local skip_grandchildren = keyword_info and keyword_info.no_child_categories for _, term in ipairs(container.terms or {}) do if term.is_duplicate then if term.original_has_children then max_depth = math.max(max_depth, 2) end else max_depth = math.max(max_depth, 1 + get_visible_tree_depth(term, skip_grandchildren)) end end end end return max_depth end local function as_param_list(val) if val == nil then return {} end if type(val) == "table" then return val end if type(val) == "string" and val ~= "" then return { val } end return {} end local TreeBuilder = {} -- Build a unique key for deduplication in the seen table function TreeBuilder.build_key(lang, title, args) local norm_lang_code = Util.get_norm_lang(lang):getFullCode() local is_table = type(args) == "table" local id = (is_table and args.id) or "" if title then return norm_lang_code .. ":" .. M.links.get_link_page(title, lang) .. ":" .. id end if is_table and args.status == M.data.STATUS.INLINE then local content_parts = {} for i = 1, #args do content_parts[i] = tostring(args[i]) end return norm_lang_code .. ":*:" .. id .. "\0" .. table.concat(content_parts, "\0") end return norm_lang_code .. ":*:" .. id end -- Copy parsed etymon modifiers onto a tree/supplement term node. function TreeBuilder.apply_etymon_fields(term, etymon_data) term.id = etymon_data.id term.gloss = etymon_data.gloss term.tr = etymon_data.tr term.ts = etymon_data.ts term.alt = etymon_data.alt term.genders = etymon_data.genders term.pos = etymon_data.pos term.ng = etymon_data.ng term.infl = etymon_data.infl term.refs = etymon_data.refs term.is_uncertain = etymon_data.unc term.lit = etymon_data.lit term.q = etymon_data.q term.qq = etymon_data.qq term.l = etymon_data.l term.ll = etymon_data.ll term.suppress_term = etymon_data.suppress_term term.unknown_term = etymon_data.unknown_term term.is_family = etymon_data.is_family term.override = etymon_data.override term.aftype = etymon_data.aftype term.postype = etymon_data.postype term.bor = etymon_data.bor term.lbor = etymon_data.lbor term.slbor = etymon_data.slbor term.link_page = etymon_data.link_page end function TreeBuilder.build_supplement_term(etymon_data, entry_lang, supplement_type) EtymonParser.check_supplement_term(etymon_data, entry_lang, supplement_type) local term = { lang = etymon_data.lang, title = etymon_data.term, children = {}, status = M.data.STATUS.OK, } TreeBuilder.apply_etymon_fields(term, etymon_data) return term end function TreeBuilder.build_supplement_terms(entry_lang, supplement_type, param_value) local terms = {} for _, term_param in ipairs(as_param_list(param_value)) do if type(term_param) == "string" and term_param ~= "" then local etymon_data = EtymonParser.parse_etymon(term_param, entry_lang) if etymon_data then table.insert(terms, TreeBuilder.build_supplement_term(etymon_data, entry_lang, supplement_type)) end end end return terms end -- Attach a |param= supplement defined in etymon_data.supplements (e.g. doublet=). function TreeBuilder.append_term_supplement(data_tree, entry_lang, supplement_type, param_value) local config = M.data.supplements[supplement_type] if not config then error("Unknown supplement '" .. tostring(supplement_type) .. "'.") end local terms = TreeBuilder.build_supplement_terms(entry_lang, supplement_type, param_value) if #terms == 0 then return end data_tree.supplements = data_tree.supplements or {} table.insert(data_tree.supplements, { type = supplement_type, config = config, terms = terms, }) M.tracking.record_keyword_usage(__state.toplevel_keyword_stats, supplement_type, entry_lang, entry_lang, true) end function TreeBuilder.build(lang, title, args, seen, depth, stop_recursion) seen = seen or {} depth = depth or 0 local is_toplevel = (depth == 0) if depth > __state.max_depth_reached then __state.max_depth_reached = depth end __state.total_nodes = __state.total_nodes + 1 local lang_code = lang:getCode() __state.language_count[lang_code] = (__state.language_count[lang_code] or 0) + 1 local current_id = (type(args) == "table" and args.id) or "" local key = TreeBuilder.build_key(lang, title, args) local node = { lang = lang, title = title, id = current_id, args = args, children = {}, status = M.data.STATUS.OK } if type(args) ~= "table" or seen[key] then node.status = args or M.data.STATUS.MISSING -- Mark as duplicate if we've seen this node before if seen[key] then node.is_duplicate = true node.duplicate_key = key local original_node = seen[key] if type(original_node) == "table" and original_node.children and #original_node.children > 0 then node.original_has_children = true end end return node end node.status = args.status or M.data.STATUS.OK seen[key] = node -- If stop_recursion is set, skip parsing children but check for visible children if stop_recursion then local keywords = M.data.keywords local has_visible_children = false for i = 2, #args do local param = args[i] if type(param) == "string" then local keyword_base = get_keyword_base(param) if keyword_base and keywords[keyword_base] then local _, kw_modifiers = EtymonParser.parse_keyword_modifiers(param:sub(1, 1) == ":" and param or (":" .. param)) if not keyword_invisible_in_tree(get_effective_keyword_info(keyword_base, kw_modifiers)) then has_visible_children = true break end elseif param:sub(1, 1) ~= ":" then -- It's a term (not a keyword), so there are visible children has_visible_children = true break end end end node.has_visible_children = has_visible_children return node end -- Parse args into keyword containers local current_keyword = "from" local current_keyword_modifiers = {} local current_container = nil local function ensure_container() if not current_container or current_container.keyword ~= current_keyword then local keyword_info = get_effective_keyword_info(current_keyword, current_keyword_modifiers) current_container = { keyword = current_keyword, keyword_info = keyword_info, keyword_modifiers = current_keyword_modifiers, terms = {}, } table.insert(node.children, current_container) -- Override keyword text/phrase for nominalization with <g:code> if current_keyword_modifiers.g and current_keyword == "nominalization" then local labels = get_nominalization_label_for_g(current_keyword_modifiers.g) if not labels then local codes = {} for c in pairs(M.data.nominalization_g_codes) do table.insert(codes, c) end table.sort(codes) error("Invalid <g:" .. tostring(current_keyword_modifiers.g) .. ">. Supported codes for nominalization: " .. table.concat(codes, ", ")) end current_container.keyword_info = copy_keyword_info(keyword_info) current_container.keyword_info.text = labels.text current_container.keyword_info.phrase = labels.phrase end end return current_container end local parse_context_lang = Util.resolve_context_lang(lang, args) for i = 2, #args do local param = args[i] if is_keyword(param) then local keyword, modifiers = EtymonParser.parse_keyword_modifiers(param) if not keyword then error("Invalid keyword '" .. param .. "'.") end current_keyword = keyword current_keyword_modifiers = modifiers current_container = nil -- Force new container for new keyword elseif type(param) == "string" and param:sub(1, 1) == ":" then reject_removed_surf_keyword(param) error("Invalid keyword '" .. param .. "'. Did you mean a valid keyword like ':bor', ':inh', etc.?") elseif type(param) == "string" then local etymon_data = EtymonParser.parse_etymon(param, parse_context_lang) if etymon_data and is_affix_group_keyword(current_keyword) then map_affix_part(etymon_data) end if etymon_data and has_linkable_term(etymon_data) and is_root_term(etymon_data, current_keyword) then etymon_data.link_page = M.roots.get_link_page(etymon_data.lang, etymon_data.term) end if etymon_data then -- Track keyword usage at top level M.tracking.record_keyword_usage(__state.toplevel_keyword_stats, current_keyword, lang, etymon_data.lang, is_toplevel) local term_node = {} local container -- Handle suppress_term (-) and unknown_term (empty or +) directly if etymon_data.suppress_term or etymon_data.unknown_term then container = ensure_container() if etymon_data.ety then local inline_args = EtymonParser.parse_inline_ety(etymon_data.ety, etymon_data.lang) inline_args.id = etymon_data.id inline_args.status = M.data.STATUS.INLINE term_node = TreeBuilder.build(etymon_data.lang, nil, inline_args, seen, depth + 1) else term_node = { lang = etymon_data.lang, children = {}, status = M.data.STATUS.OK, } end TreeBuilder.apply_etymon_fields(term_node, etymon_data) else -- Regular term: fetch arguments from page record_term_id_tracking(etymon_data) local etymon_args, page_of, resolved_etymon_id, descendants_check = DataRetriever.get_etymon_args(etymon_data, is_toplevel) -- Check for <ety> inline parameter doesn't override the scraped arguments, unless the latter are missing if etymon_data.ety then if etymon_args == M.data.STATUS.REDLINK or etymon_args == M.data.STATUS.MISSING then __state.current_page_has_inline_etymology = true if is_toplevel then __state.toplevel_has_inline_etymology = true end local inline_args = EtymonParser.parse_inline_ety(etymon_data.ety, etymon_data.lang) -- Track inline ety keywords too local inline_keyword = get_keyword(inline_args[2], true) if inline_keyword and #inline_args >= 3 then local inline_etymon = EtymonParser.parse_etymon(inline_args[3], etymon_data.lang) if inline_etymon then M.tracking.record_keyword_usage(__state.toplevel_keyword_stats, inline_keyword, etymon_data.lang, inline_etymon.lang, is_toplevel) end end inline_args.id = etymon_data.id inline_args.status = M.data.STATUS.INLINE etymon_args = inline_args term_node.page_of = __state.cached_etymon_pages[key] -- term node is on the same page as the parent else -- Scraped arguments exist, <ety> is redundant and ignored __state.current_page_has_redundant_etymology = true if is_toplevel then __state.toplevel_redundant_etymology = true end end end -- Ensure container exists before checking keyword info container = ensure_container() -- Check if current keyword has no_child_categories - if so, stop recursion local keyword_info = container.keyword_info local should_stop_recursion = (stop_recursion or (keyword_info and keyword_info.no_child_categories)) term_node = TreeBuilder.build(etymon_data.lang, etymon_data.term, etymon_args, seen, depth + 1, should_stop_recursion) term_node.target_key = Util.get_norm_lang(etymon_data.lang):getFullCode() .. ":" .. get_term_page(etymon_data) term_node.etymon_id = resolved_etymon_id -- The actual etymon id when resolved via senseid term_node.page_of = page_of TreeBuilder.apply_etymon_fields(term_node, etymon_data) term_node.missing_descendants_header, term_node.missing_descendants_entry = M.descendants.get_term_sync_flags(current_keyword, term_node.status, descendants_check) end table.insert(container.terms, term_node) end end end return node end -- Convert etymology tree to JSON-serializable table local function tree_to_json(node) local obj = { term = node.title, lang = node.lang:getCode(), lang_name = node.lang:getCanonicalName(), id = (node.id and node.id ~= "") and node.id or nil, status = node.status, is_uncertain = node.is_uncertain or nil, is_duplicate = node.is_duplicate or nil, gloss = node.gloss, transliteration = node.tr, transcription = node.ts, alt = node.alt, g = node.genders, pos = node.pos, ng = node.ng, infl = node.infl, children = {}, } for _, container in ipairs(node.children or {}) do local keyword_info = container.keyword_info if keyword_info then local container_obj = { keyword = container.keyword, keyword_label = keyword_info.text, keyword_abbrev = keyword_info.abbrev, is_group = keyword_info.is_group or nil, is_invisible = keyword_info.invisible or nil, is_uncertain = (container.keyword_modifiers and container.keyword_modifiers.unc) or nil, terms = {}, } for _, term in ipairs(container.terms or {}) do table.insert(container_obj.terms, tree_to_json(term)) end table.insert(obj.children, container_obj) end end return obj end -- Build and return the etymology data tree for a given term. function export.get_tree(lang, title, args, options) options = options or {} __state.entry_title = title __state.entry_lang_code = lang:getCode() __state.id_stats = M.tracking.new_id_stats() __state.skip_partial_etymology_category = options.skip_partial_etymology_category == true if options.validate then EtymonParser.validate(lang, args, options.id, title, options.pos, false) end local lang_code = lang:getCode() local start_index = (args[1] == lang_code) and 2 or 1 local tree_args = { [1] = lang_code, id = options.id or args.id } for i = start_index, #args do table.insert(tree_args, args[i]) end __state.cached_etymon_args[lang_code .. ":" .. title .. ":" .. (tree_args.id or "")] = tree_args local ety_data_tree = TreeBuilder.build(lang, title, tree_args) if options.json then return M.JSON.toJSON(tree_to_json(ety_data_tree)) end return ety_data_tree end -- Given a language code, page name and optionally the id= parameter, -- render the tree and only the etymology tree for the relevant page. -- Fetches and parses the corresponding {{etymon}} from the requested page, -- and any further pages needed to render the tree. -- Parameters can be passed either through the #invoke or as -- template parameters *through* an #invoke. function export.render_tree_for_etymon_on_page(frame) local frame_args = frame.args local parent_args = frame:getParent().args local langcode = frame_args[1] or parent_args[1] local pagename = frame_args[2] or parent_args[2] local id = frame_args["id"] or parent_args["id"] local display_title = frame_args["title"] or parent_args["title"] local parsed_title = mw.title.new(pagename, 0) local title if parsed_title.namespace == 0 then title = M.pages.safe_page_name(parsed_title) elseif parsed_title.namespace == 118 then title = "*" .. M.pages.safe_page_name(parsed_title) else error("Unsupported namespace for render_tree_for_etymon_on_page: " .. parsed_title.namespace) end local lang = Util.get_lang(langcode) __state.entry_title = title __state.entry_lang_code = lang:getCode() __state.id_stats = M.tracking.new_id_stats() -- Construct etymon_data for DataRetriever.get_args. local etymon_data = { lang = lang, term = title, id = id } local args, pagename = DataRetriever.get_etymon_args(etymon_data, true) if args == M.data.STATUS.MISSING then error("The etymon template was not found (language " .. langcode .. ", title '" .. title .. "'" .. (id and ", ID '" .. id .. "'" or ", no ID given") .. "). Page contents may have changed in the interim.") end local tree_title = display_title or title if lang:stripDiacritics(M.links.remove_links(tree_title)) ~= lang:stripDiacritics(M.links.remove_links(title)) then M.tracking.track_title_pagename_mismatch(lang) end reset_invocation_state() local ety_data_tree = export.get_tree(lang, tree_title, args, { validate = true, id = id, }) local output = {} table.insert(output, M.template_styles("Module:etymon/styles.css")) table.insert(output, M.tree.render({ data_tree = ety_data_tree, format_term_func = function(term, is_toplevel) return Util.format_term(term, is_toplevel, { gloss = "suppress", pos = "suppress", lit = "suppress", tree_ql = "suppress", }) end, })) return table.concat(output) end function export.main(frame) local parent_args = frame:getParent().args local args = M.parameters.process(parent_args, M.parameters_data.etymon) local lang = args[1] local etymon_args = args[2] local id = args.id local title = args.title local text = args.text local tree = args.tree local etydate = args.etydate local doublet = args.doublet local rfe = args.rfe local etystub = args.etystub local is_nonlemma = M.yesno(args.nl, false) local page_data = Util.get_page_data() if not title then title = page_data.pagename if page_data.namespace == "Reconstruction" then title = "*" .. title end end local entry_pagename = page_data.pagename if page_data.namespace == "Reconstruction" then entry_pagename = "*" .. entry_pagename end if lang:stripDiacritics(M.links.remove_links(title)) ~= lang:stripDiacritics(M.links.remove_links(entry_pagename)) then M.tracking.track_title_pagename_mismatch(lang) end local current_L2 = M.pages.get_current_L2() if current_L2 then local norm_lang = Util.get_norm_lang(lang) local norm_name = norm_lang:getCanonicalName() if current_L2 ~= norm_name then local lang_desc = lang:getCode() .. " (" .. lang:getCanonicalName() .. ")" if norm_lang:getCode() ~= lang:getCode() then lang_desc = lang_desc .. ", normalized to " .. norm_lang:getCode() .. " (" .. norm_name .. ")" end error("Language '" .. lang_desc .. "' does not match the L2 header (" .. current_L2 .. ").") end end reset_invocation_state() local ety_data_tree = export.get_tree(lang, title, etymon_args, { validate = true, pos = args.pos, id = id, json = args.json, skip_partial_etymology_category = is_nonlemma, }) if args.json then return ety_data_tree end local output = {} local text_allowlist_mode = M.text_allowed.default_mode or "off" if text and text_allowlist_mode ~= "off" and not Util.is_text_param_allowed_for_lang(lang) then local msg = "Etymology texts (parameter <code>text=</code>) are not allowed for " .. lang:getFullName() .. "; see [[Template:etymon#Text allowlist|Template:etymon § Text allowlist]] for the list of languages that may use the <code>text=</code> parameter." if text_allowlist_mode == "error" then error(msg) else Util.add_warning(msg, true) end end local lang_exc = Util.get_lang_exception(lang) if lang_exc and lang_exc.disallow then local disallow = lang_exc.disallow local error_text = " for " .. lang:getFullName() if disallow.ref then error_text = error_text .. "; see " .. disallow.ref else error_text = error_text .. "." end if tree and disallow.tree then error("Etymology trees are not allowed" .. error_text) end if text and disallow.text then error("Etymology texts are not allowed" .. error_text) end end if etydate then local etydate_param_mods = M.parameter_utilities.construct_param_mods { { group = "ref" }, { param = "refn" }, { param = "nocap", type = "boolean" }, } local function generate_etydate_obj(etydate_text) local etydate_specs = {} for spec in etydate_text:gmatch("[^,]+") do table.insert(etydate_specs, mw.text.trim(spec)) end return { [1] = etydate_specs } end local parsed_etydate = M.parse_utilities.parse_inline_modifiers(etydate, { param_mods = etydate_param_mods, generate_obj = generate_etydate_obj }) local etydate_args = { [1] = parsed_etydate[1], nocap = parsed_etydate.nocap or false, } ety_data_tree.supplements = ety_data_tree.supplements or {} table.insert(ety_data_tree.supplements, { type = "etydate", etydate_text = M.etydate.format_etydate(etydate_args, { omit_refs = true }), etydate_refs = (parsed_etydate.refs and #parsed_etydate.refs > 0) and parsed_etydate.refs or nil, }) end TreeBuilder.append_term_supplement(ety_data_tree, lang, "doublet", doublet) local has_visible_children = node_has_visible_tree_children(ety_data_tree) -- Suppress trees for multiword entries and one-step chains local visible_tree_depth = get_visible_tree_depth(ety_data_tree) local is_trivial_tree = visible_tree_depth <= 2 local is_multiword = title:find("%s") ~= nil or title:find("_") ~= nil if tree and (is_multiword or is_trivial_tree) then tree = false end if tree then table.insert(output, M.template_styles("Module:etymon/styles.css")) table.insert(output, M.tree.render({ data_tree = ety_data_tree, format_term_func = function(term, is_toplevel) return Util.format_term(term, is_toplevel, { gloss = "suppress", pos = "suppress", lit = "suppress", tree_ql = "suppress", }) end, })) end local tree_disallowed = lang_exc and lang_exc.disallow and lang_exc.disallow.tree local ety_tree_json = M.JSON.toJSON(tree_to_json(ety_data_tree)) local anchor = M.anchors.etymonid(lang, id, { no_tree = args.notree, title = title, empty_tree = (not has_visible_children) or tree_disallowed, ety_tree_json = ety_tree_json, }) table.insert(output, anchor) local text_stop_lang_missing = nil if text then local max_depth, stop_at_blue_link, stop_at_lang, stop_at_lang_or_bluelink if text == "++" then max_depth, stop_at_blue_link = false, false elseif text == "+" then max_depth, stop_at_blue_link = 1, false elseif text == "*" then max_depth, stop_at_blue_link = false, true elseif text:match("^:[^*]+%*$") then -- Stop at a specific language OR first bluelink after it, e.g., ":ota*" -- If the target language is a redlink, continue to the first bluelink local lang_code = text:match("^:([^*]+)%*$") if lang_code and lang_code ~= "" then local lang_obj = Util.get_lang(lang_code, true) if lang_obj then stop_at_lang_or_bluelink = lang_code else Util.add_warning('Invalid language code "' .. lang_code .. '" in text parameter. Showing full chain instead.') max_depth, stop_at_blue_link = false, false end else Util.add_warning('Empty language code in text parameter. Showing full chain instead.') max_depth, stop_at_blue_link = false, false end elseif text:sub(1, 1) == ":" then -- Stop at a specific language, e.g., ":ar" stops at first Arabic term local lang_code = text:sub(2) if lang_code ~= "" then -- Validate the language code local lang_obj = Util.get_lang(lang_code, true) if lang_obj then stop_at_lang = lang_code else Util.add_warning('Invalid language code "' .. lang_code .. '" in text parameter. Showing full chain instead.') max_depth, stop_at_blue_link = false, false -- default to ++ end else Util.add_warning('Empty language code in text parameter. Showing full chain instead.') max_depth, stop_at_blue_link = false, false -- default to ++ end else local num = tonumber(text) if num and num >= 1 then max_depth, stop_at_blue_link = num, false else error('Invalid text value "' .. text .. '". Valid values are: "++" (full chain), "+" (first step only), "*" (until first blue link), a number (max steps), ":lang" (stop at language), or ":lang*" (stop at language or first bluelink if redlink)') end end local text_output, text_render_meta = M.text.render({ data_tree = ety_data_tree, format_term_func = Util.format_term, lang_matches_stop_code = Util.lang_matches_stop_code, max_depth = max_depth, stop_at_blue_link = stop_at_blue_link, curr_page = page_data.pagename, nodot = args.nodot, dot = args.dot, stop_at_lang = stop_at_lang, stop_at_lang_or_bluelink = stop_at_lang_or_bluelink, }) table.insert(output, text_output) if stop_at_lang and text_render_meta and not text_render_meta.stop_lang_reached then M.tracking.track_text_stop_lang_missing(lang, stop_at_lang) text_stop_lang_missing = stop_at_lang end end if rfe then table.insert(output, Util.expand_request_template(frame, "rfe", rfe, lang:getCode())) end if etystub then table.insert(output, Util.expand_request_template(frame, "etystub", etystub, lang:getCode())) end if is_nonlemma then table.insert(output, " " .. frame:expandTemplate({ title = "nonlemma", args = {}, })) end local categories = {} if Util.is_content_page() then M.tracking.track_tree_metrics({ max_depth_reached = __state.max_depth_reached, total_nodes = __state.total_nodes, language_count = __state.language_count, lang = lang, }) categories = M.categories.build({ data_tree = ety_data_tree, page_lang = lang, available_etymon_ids = __state.available_etymon_ids, senseid_parent_etymon = __state.senseid_parent_etymon, get_norm_lang_func = Util.get_norm_lang, lang_exc = lang_exc, suppress_categories = lang_exc and lang_exc.suppress_categories, nocat = args.nocat, tree = tree, text = text, exnihilo = args.exnihilo, toplevel_has_inline_etymology = __state.toplevel_has_inline_etymology, toplevel_redundant_etymology = __state.toplevel_redundant_etymology, toplevel_idless_etymon = __state.toplevel_idless_etymon, has_mismatched_id = __state.has_mismatched_id, linked_page_multiple_etymons_idless = __state.linked_page_multiple_etymons_idless, linked_page_partial_etymology_sections = __state.linked_page_partial_etymology_sections, text_stop_lang_missing = text_stop_lang_missing, }) M.tracking.track_keywords(__state.toplevel_keyword_stats, lang) M.tracking.track_page_id(lang, id) M.tracking.track_ids(__state.id_stats, lang) end if #categories > 0 then table.insert(output, M.categories.format(categories, lang)) end if __state.warnings then for i, warning in ipairs(__state.warnings) do table.insert(output, (i == 1 and "\n" or "") .. warning .. "\n") end end return table.concat(output) end return export sym1jq8qhwxvh09l8kvavgce98cdthz