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}} [ ]
: 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}} [ ]
: 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