Wiktionary
thwiktionary
https://th.wiktionary.org/wiki/%E0%B8%A7%E0%B8%B4%E0%B8%81%E0%B8%B4%E0%B8%9E%E0%B8%88%E0%B8%99%E0%B8%B2%E0%B8%99%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%A1:%E0%B8%AB%E0%B8%99%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B1%E0%B8%81
MediaWiki 1.47.0-wmf.6
case-sensitive
สื่อ
พิเศษ
พูดคุย
ผู้ใช้
คุยกับผู้ใช้
วิกิพจนานุกรม
คุยเรื่องวิกิพจนานุกรม
ไฟล์
คุยเรื่องไฟล์
มีเดียวิกิ
คุยเรื่องมีเดียวิกิ
แม่แบบ
คุยเรื่องแม่แบบ
วิธีใช้
คุยเรื่องวิธีใช้
หมวดหมู่
คุยเรื่องหมวดหมู่
ภาคผนวก
คุยเรื่องภาคผนวก
ดัชนี
คุยเรื่องดัชนี
สัมผัส
คุยเรื่องสัมผัส
อรรถาภิธาน
คุยเรื่องอรรถาภิธาน
TimedText
TimedText talk
มอดูล
คุยเรื่องมอดูล
Event
Event talk
nightclub
0
16553
5724439
914934
2026-06-09T13:42:52Z
Mawyuri
18975
/* ภาษาอังกฤษ */
5724439
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
==={{หน้าที่|en|นาม}}===
{{en-noun}}
# [[ไนต์คลับ]]
62an6zgwl8avbphup9ejobnmkxplifx
5724476
5724439
2026-06-10T06:29:19Z
OctraBot
3198
/* ภาษาอังกฤษ */ เก็บกวาด
5724476
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
{{ety|en|:af|night|club|text=+|tree=1}}
=== การออกเสียง ===
* {{IPA|en|/ˈnʌɪtklʌb/}}
* {{audio|en|en-us-nightclub.ogg|a=US}}
=== คำนาม ===
{{wp}}
{{en-noun}}
# [[ไนต์คลับ]], [[สถานประกอบการ]][[สาธารณะ]]หรือ[[ส่วนตัว]]ที่[[เปิด]]ให้บริการเวลา[[กลางคืน]] เพื่อมอบ[[ความบันเทิง]] [[อาหาร]] [[เครื่องดื่ม]] [[ดนตรี]] หรือ[[การเต้นรำ]]
#: {{syn|en|nightspot}}
#: {{hyper|en|club}}
#* {{quote-journal|en|journal=The Monthly Record|volume=61|year=1957|page=22|passage=They respond instantly to the faintest rustling in the covert of a sheaf of Ulysses S. Grants, or the homely, rustic tinkle of a wheelbarrow full of rubies being jounced along over a '''nightclub''' floor.}}
#* {{quote-journal|en|date=2007-09-06|author=Lisa Belkin|title=What Do Young Jobseekers Want? (Something Other Than the Job)|work=w:The New York Times|url=http://www.nytimes.com/2007/09/06/fashion/06Work.html
|passage=EARLY this summer, Joshua J. Pelton decided that he was meant to live in Orlando, Fla. So he quit his sales job in Detroit, packed his car with all the belongings that fit, put the rest in storage, and drove southeast daydreaming about sundrenched winters and packed '''nightclubs'''.|archiveurl=https://web.archive.org/web/20221126035936/https://www.nytimes.com/2007/09/06/fashion/06Work.html}}
#* {{RQ:NYT
|en
|date=March 21, 2008
|author=Tim Sullivan
|title=Bhutanese reluctantly stepping into world of democracy
|archiveurl=https://web.archive.org/web/20131213150143/https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|url=https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|archivedate=December 13, 2013
|section=Asia Pacific
|url2=https://archive.ph/hdkcF
|text=This is a country where '''nightclubs''' in Thimbu, the capital, throb with techno music, but where smoking is illegal and television did not arrive until 1999.}}
# {{lb|en|Philippines}} [[สถานบันเทิง]][[เปลื้อง]][[ผ้า]]
==== ลูกคำ ====
{{col|en|nightclubber|nightclubby|nightclublike
|nightclub-goer}}
==== คำเกี่ยวข้อง ====
{{col|en
|clubber
|clubbing
|clubgoer
|clubhouse
}}
=== คำกริยา ===
{{en-verb|++}}
# {{lb|en|informal|ambitransitive}} ไป[[เที่ยว]]ไนต์คลับเพื่อความบันเทิง
#: {{ux|en|Our first night in the big city we went out '''nightclubbing'''. The next morning we stayed in hung over.}}
{{cln|en|2-syllable words|endocentric compounds}}
{{C|en|Night|Businesses}}
mln91qe8qrvhs7rumv1upm33gpno74m
5724477
5724476
2026-06-10T06:30:50Z
OctraBot
3198
/* */ เก็บกวาด
5724477
wikitext
text/x-wiki
== ภาษาสเปน ==
=== รากศัพท์ ===
{{ubor|es|en|nightclub}}
=== การออกเสียง ===
{{es-pr|náithclub|náiclub}}
=== คำนาม ===
{{es-noun|m|+,#es}}
# [[ไนต์คลับ]]
==== หมายเหตุการใช้ ====
{{es-unadapted}}
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
{{ety|en|:af|night|club|text=+|tree=1}}
=== การออกเสียง ===
* {{IPA|en|/ˈnʌɪtklʌb/}}
* {{audio|en|en-us-nightclub.ogg|a=US}}
=== คำนาม ===
{{wp}}
{{en-noun}}
# [[ไนต์คลับ]], [[สถานประกอบการ]][[สาธารณะ]]หรือ[[ส่วนตัว]]ที่[[เปิด]]ให้บริการเวลา[[กลางคืน]] เพื่อมอบ[[ความบันเทิง]] [[อาหาร]] [[เครื่องดื่ม]] [[ดนตรี]] หรือ[[การเต้นรำ]]
#: {{syn|en|nightspot}}
#: {{hyper|en|club}}
#* {{quote-journal|en|journal=The Monthly Record|volume=61|year=1957|page=22|passage=They respond instantly to the faintest rustling in the covert of a sheaf of Ulysses S. Grants, or the homely, rustic tinkle of a wheelbarrow full of rubies being jounced along over a '''nightclub''' floor.}}
#* {{quote-journal|en|date=2007-09-06|author=Lisa Belkin|title=What Do Young Jobseekers Want? (Something Other Than the Job)|work=w:The New York Times|url=http://www.nytimes.com/2007/09/06/fashion/06Work.html
|passage=EARLY this summer, Joshua J. Pelton decided that he was meant to live in Orlando, Fla. So he quit his sales job in Detroit, packed his car with all the belongings that fit, put the rest in storage, and drove southeast daydreaming about sundrenched winters and packed '''nightclubs'''.|archiveurl=https://web.archive.org/web/20221126035936/https://www.nytimes.com/2007/09/06/fashion/06Work.html}}
#* {{RQ:NYT
|en
|date=March 21, 2008
|author=Tim Sullivan
|title=Bhutanese reluctantly stepping into world of democracy
|archiveurl=https://web.archive.org/web/20131213150143/https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|url=https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|archivedate=December 13, 2013
|section=Asia Pacific
|url2=https://archive.ph/hdkcF
|text=This is a country where '''nightclubs''' in Thimbu, the capital, throb with techno music, but where smoking is illegal and television did not arrive until 1999.}}
# {{lb|en|Philippines}} [[สถานบันเทิง]][[เปลื้อง]][[ผ้า]]
==== ลูกคำ ====
{{col|en|nightclubber|nightclubby|nightclublike
|nightclub-goer}}
==== คำเกี่ยวข้อง ====
{{col|en
|clubber
|clubbing
|clubgoer
|clubhouse
}}
=== คำกริยา ===
{{en-verb|++}}
# {{lb|en|informal|ambitransitive}} ไป[[เที่ยว]]ไนต์คลับเพื่อความบันเทิง
#: {{ux|en|Our first night in the big city we went out '''nightclubbing'''. The next morning we stayed in hung over.}}
{{cln|en|2-syllable words|endocentric compounds}}
{{C|en|Night|Businesses}}
axyyq61b5hk94ooy46pfh5yt1yvnz8s
5724491
5724477
2026-06-10T06:57:48Z
OctraBot
3198
/* ภาษาอังกฤษ */
5724491
wikitext
text/x-wiki
== ภาษาสเปน ==
=== รากศัพท์ ===
{{ubor|es|en|nightclub}}
=== การออกเสียง ===
{{es-pr|náithclub|náiclub}}
=== คำนาม ===
{{es-noun|m|+,#es}}
# [[ไนต์คลับ]]
==== หมายเหตุการใช้ ====
{{es-unadapted}}
== ภาษาอังกฤษ ==
===Alternative forms===
* {{alt|en|night club}}
=== รากศัพท์ ===
{{ety|en|:af|night|club|text=+|tree=1}}
=== การออกเสียง ===
* {{IPA|en|/ˈnʌɪtklʌb/}}
* {{audio|en|en-us-nightclub.ogg|a=US}}
=== คำนาม ===
{{wp}}
{{en-noun}}
# [[ไนต์คลับ]], [[สถานประกอบการ]][[สาธารณะ]]หรือ[[ส่วนตัว]]ที่[[เปิด]]ให้บริการเวลา[[กลางคืน]] เพื่อมอบ[[ความบันเทิง]] [[อาหาร]] [[เครื่องดื่ม]] [[ดนตรี]] หรือ[[การเต้นรำ]]
#: {{syn|en|nightspot}}
#: {{hyper|en|club}}
#* {{quote-journal|en|journal=The Monthly Record|volume=61|year=1957|page=22|passage=They respond instantly to the faintest rustling in the covert of a sheaf of Ulysses S. Grants, or the homely, rustic tinkle of a wheelbarrow full of rubies being jounced along over a '''nightclub''' floor.}}
#* {{quote-journal|en|date=2007-09-06|author=Lisa Belkin|title=What Do Young Jobseekers Want? (Something Other Than the Job)|work=w:The New York Times|url=http://www.nytimes.com/2007/09/06/fashion/06Work.html
|passage=EARLY this summer, Joshua J. Pelton decided that he was meant to live in Orlando, Fla. So he quit his sales job in Detroit, packed his car with all the belongings that fit, put the rest in storage, and drove southeast daydreaming about sundrenched winters and packed '''nightclubs'''.|archiveurl=https://web.archive.org/web/20221126035936/https://www.nytimes.com/2007/09/06/fashion/06Work.html}}
#* {{RQ:NYT
|en
|date=March 21, 2008
|author=Tim Sullivan
|title=Bhutanese reluctantly stepping into world of democracy
|archiveurl=https://web.archive.org/web/20131213150143/https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|url=https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|archivedate=December 13, 2013
|section=Asia Pacific
|url2=https://archive.ph/hdkcF
|text=This is a country where '''nightclubs''' in Thimbu, the capital, throb with techno music, but where smoking is illegal and television did not arrive until 1999.}}
# {{lb|en|Philippines}} [[สถานบันเทิง]][[เปลื้อง]][[ผ้า]]
==== ลูกคำ ====
{{col|en|nightclubber|nightclubby|nightclublike
|nightclub-goer}}
==== คำเกี่ยวข้อง ====
{{col|en
|clubber
|clubbing
|clubgoer
|clubhouse
}}
=== คำกริยา ===
{{en-verb|++}}
# {{lb|en|informal|ambitransitive}} ไป[[เที่ยว]]ไนต์คลับเพื่อความบันเทิง
#: {{ux|en|Our first night in the big city we went out '''nightclubbing'''. The next morning we stayed in hung over.}}
{{cln|en|2-syllable words|endocentric compounds}}
{{C|en|Night|Businesses}}
87wbuf6e8hshx5dxxj7pl0kjhbeufap
5724492
5724491
2026-06-10T06:57:59Z
OctraBot
3198
/* Alternative forms */ เก็บกวาด
5724492
wikitext
text/x-wiki
== ภาษาสเปน ==
=== รากศัพท์ ===
{{ubor|es|en|nightclub}}
=== การออกเสียง ===
{{es-pr|náithclub|náiclub}}
=== คำนาม ===
{{es-noun|m|+,#es}}
# [[ไนต์คลับ]]
==== หมายเหตุการใช้ ====
{{es-unadapted}}
== ภาษาอังกฤษ ==
=== รูปแบบอื่น ===
* {{alt|en|night club}}
=== รากศัพท์ ===
{{ety|en|:af|night|club|text=+|tree=1}}
=== การออกเสียง ===
* {{IPA|en|/ˈnʌɪtklʌb/}}
* {{audio|en|en-us-nightclub.ogg|a=US}}
=== คำนาม ===
{{wp}}
{{en-noun}}
# [[ไนต์คลับ]], [[สถานประกอบการ]][[สาธารณะ]]หรือ[[ส่วนตัว]]ที่[[เปิด]]ให้บริการเวลา[[กลางคืน]] เพื่อมอบ[[ความบันเทิง]] [[อาหาร]] [[เครื่องดื่ม]] [[ดนตรี]] หรือ[[การเต้นรำ]]
#: {{syn|en|nightspot}}
#: {{hyper|en|club}}
#* {{quote-journal|en|journal=The Monthly Record|volume=61|year=1957|page=22|passage=They respond instantly to the faintest rustling in the covert of a sheaf of Ulysses S. Grants, or the homely, rustic tinkle of a wheelbarrow full of rubies being jounced along over a '''nightclub''' floor.}}
#* {{quote-journal|en|date=2007-09-06|author=Lisa Belkin|title=What Do Young Jobseekers Want? (Something Other Than the Job)|work=w:The New York Times|url=http://www.nytimes.com/2007/09/06/fashion/06Work.html
|passage=EARLY this summer, Joshua J. Pelton decided that he was meant to live in Orlando, Fla. So he quit his sales job in Detroit, packed his car with all the belongings that fit, put the rest in storage, and drove southeast daydreaming about sundrenched winters and packed '''nightclubs'''.|archiveurl=https://web.archive.org/web/20221126035936/https://www.nytimes.com/2007/09/06/fashion/06Work.html}}
#* {{RQ:NYT
|en
|date=March 21, 2008
|author=Tim Sullivan
|title=Bhutanese reluctantly stepping into world of democracy
|archiveurl=https://web.archive.org/web/20131213150143/https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|url=https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|archivedate=December 13, 2013
|section=Asia Pacific
|url2=https://archive.ph/hdkcF
|text=This is a country where '''nightclubs''' in Thimbu, the capital, throb with techno music, but where smoking is illegal and television did not arrive until 1999.}}
# {{lb|en|Philippines}} [[สถานบันเทิง]][[เปลื้อง]][[ผ้า]]
==== ลูกคำ ====
{{col|en|nightclubber|nightclubby|nightclublike
|nightclub-goer}}
==== คำเกี่ยวข้อง ====
{{col|en
|clubber
|clubbing
|clubgoer
|clubhouse
}}
=== คำกริยา ===
{{en-verb|++}}
# {{lb|en|informal|ambitransitive}} ไป[[เที่ยว]]ไนต์คลับเพื่อความบันเทิง
#: {{ux|en|Our first night in the big city we went out '''nightclubbing'''. The next morning we stayed in hung over.}}
{{cln|en|2-syllable words|endocentric compounds}}
{{C|en|Night|Businesses}}
k1wpx7kupculaf1ez4341nfmvf7tgm4
5724493
5724492
2026-06-10T07:00:58Z
OctraBot
3198
/* คำกริยา */
5724493
wikitext
text/x-wiki
== ภาษาสเปน ==
=== รากศัพท์ ===
{{ubor|es|en|nightclub}}
=== การออกเสียง ===
{{es-pr|náithclub|náiclub}}
=== คำนาม ===
{{es-noun|m|+,#es}}
# [[ไนต์คลับ]]
==== หมายเหตุการใช้ ====
{{es-unadapted}}
== ภาษาอังกฤษ ==
=== รูปแบบอื่น ===
* {{alt|en|night club}}
=== รากศัพท์ ===
{{ety|en|:af|night|club|text=+|tree=1}}
=== การออกเสียง ===
* {{IPA|en|/ˈnʌɪtklʌb/}}
* {{audio|en|en-us-nightclub.ogg|a=US}}
=== คำนาม ===
{{wp}}
{{en-noun}}
# [[ไนต์คลับ]], [[สถานประกอบการ]][[สาธารณะ]]หรือ[[ส่วนตัว]]ที่[[เปิด]]ให้บริการเวลา[[กลางคืน]] เพื่อมอบ[[ความบันเทิง]] [[อาหาร]] [[เครื่องดื่ม]] [[ดนตรี]] หรือ[[การเต้นรำ]]
#: {{syn|en|nightspot}}
#: {{hyper|en|club}}
#* {{quote-journal|en|journal=The Monthly Record|volume=61|year=1957|page=22|passage=They respond instantly to the faintest rustling in the covert of a sheaf of Ulysses S. Grants, or the homely, rustic tinkle of a wheelbarrow full of rubies being jounced along over a '''nightclub''' floor.}}
#* {{quote-journal|en|date=2007-09-06|author=Lisa Belkin|title=What Do Young Jobseekers Want? (Something Other Than the Job)|work=w:The New York Times|url=http://www.nytimes.com/2007/09/06/fashion/06Work.html
|passage=EARLY this summer, Joshua J. Pelton decided that he was meant to live in Orlando, Fla. So he quit his sales job in Detroit, packed his car with all the belongings that fit, put the rest in storage, and drove southeast daydreaming about sundrenched winters and packed '''nightclubs'''.|archiveurl=https://web.archive.org/web/20221126035936/https://www.nytimes.com/2007/09/06/fashion/06Work.html}}
#* {{RQ:NYT
|en
|date=March 21, 2008
|author=Tim Sullivan
|title=Bhutanese reluctantly stepping into world of democracy
|archiveurl=https://web.archive.org/web/20131213150143/https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|url=https://www.nytimes.com/2008/03/21/world/asia/21iht-bhutan.1.11312503.html
|archivedate=December 13, 2013
|section=Asia Pacific
|url2=https://archive.ph/hdkcF
|text=This is a country where '''nightclubs''' in Thimbu, the capital, throb with techno music, but where smoking is illegal and television did not arrive until 1999.}}
# {{lb|en|Philippines}} [[สถานบันเทิง]][[เปลื้อง]][[ผ้า]]
==== ลูกคำ ====
{{col|en|nightclubber|nightclubby|nightclublike
|nightclub-goer}}
==== คำเกี่ยวข้อง ====
{{col|en
|clubber
|clubbing
|clubgoer
|clubhouse
}}
=== คำกริยา ===
{{en-verb|++}}
# {{lb|en|informal|ambitransitive}} ไป[[เที่ยว]]ไนต์คลับเพื่อความบันเทิง
#: {{ux|en|Our first night in the big city we went out '''nightclubbing'''. The next morning we stayed in hung over.}}
{{cln|en|2-syllable words|endocentric compounds}}
{{C|en|กลางคืน|กิจการ}}
dwscfvmsa5k1ia1v47kt4lar7nksg5l
cattivo
0
25351
5724470
2188000
2026-06-10T04:48:34Z
OctraBot
3198
/* การออกเสียง */
5724470
wikitext
text/x-wiki
== ภาษาอิตาลี ==
=== รากศัพท์ ===
{{inh+|it|la|captīvus|t=captive” → “caught by the devil” → “bad}}; เทียบการพัฒนาเชิงความหมายของ{{cog|fr|chétif||puny, scrawny}} และ {{cog|gl|cativo}}
===Pronunciation===
{{it-pr|^ì<audio:It-cattivo.ogg><audio:LL-Q652 (ita)-LangPao-cattivo.wav>}}
=== คำคุณศัพท์ ===
{{it-adj|sup=cattivissimo|dim=cattivèllo,cattivétto,cattivùccio|aug=cattivóne<q:โดยปกติขำขัน><pos:noun><g:m>,cattivóna<g:f>|pej=cattivàccio}}
# [[แย่]], [[ไม่]][[ดี]]
#: {{syn|it|brutto|malvagio}}
#: {{ant|it|buono}}
#: {{ux|it|Ho un '''cattivo''' presentimento.|ฉันรู้สึก'''ไม่ดี'''}}
# [[ร้าย]], [[เกเร]]
==== ลูกคำ ====
* {{l|it|cattivamente}}
* {{l|it|cattiveria}}
==== ดูเพิ่ม ====
* {{l|it|male}}
* {{l|it|malo}}
* {{l|it|malvagio}}
=== คำนาม ===
{{it-noun|m|f=cattiva}}
# [[ตัวร้าย]]
==== ลูกคำ ====
* {{l|it|cattivello}}
* {{l|it|cattivone}}
* {{l|it|cattivaccio}}
7gv68gbe3bpgzmmwwafm1wwio77xqi9
5724471
5724470
2026-06-10T04:48:42Z
OctraBot
3198
/* Pronunciation */ เก็บกวาด
5724471
wikitext
text/x-wiki
== ภาษาอิตาลี ==
=== รากศัพท์ ===
{{inh+|it|la|captīvus|t=captive” → “caught by the devil” → “bad}}; เทียบการพัฒนาเชิงความหมายของ{{cog|fr|chétif||puny, scrawny}} และ {{cog|gl|cativo}}
=== การออกเสียง ===
{{it-pr|^ì<audio:It-cattivo.ogg><audio:LL-Q652 (ita)-LangPao-cattivo.wav>}}
=== คำคุณศัพท์ ===
{{it-adj|sup=cattivissimo|dim=cattivèllo,cattivétto,cattivùccio|aug=cattivóne<q:โดยปกติขำขัน><pos:noun><g:m>,cattivóna<g:f>|pej=cattivàccio}}
# [[แย่]], [[ไม่]][[ดี]]
#: {{syn|it|brutto|malvagio}}
#: {{ant|it|buono}}
#: {{ux|it|Ho un '''cattivo''' presentimento.|ฉันรู้สึก'''ไม่ดี'''}}
# [[ร้าย]], [[เกเร]]
==== ลูกคำ ====
* {{l|it|cattivamente}}
* {{l|it|cattiveria}}
==== ดูเพิ่ม ====
* {{l|it|male}}
* {{l|it|malo}}
* {{l|it|malvagio}}
=== คำนาม ===
{{it-noun|m|f=cattiva}}
# [[ตัวร้าย]]
==== ลูกคำ ====
* {{l|it|cattivello}}
* {{l|it|cattivone}}
* {{l|it|cattivaccio}}
esx60txh2dpffadv8l1chtni3s82yek
5724472
5724471
2026-06-10T04:48:59Z
OctraBot
3198
/* คำคุณศัพท์ */
5724472
wikitext
text/x-wiki
== ภาษาอิตาลี ==
=== รากศัพท์ ===
{{inh+|it|la|captīvus|t=captive” → “caught by the devil” → “bad}}; เทียบการพัฒนาเชิงความหมายของ{{cog|fr|chétif||puny, scrawny}} และ {{cog|gl|cativo}}
=== การออกเสียง ===
{{it-pr|^ì<audio:It-cattivo.ogg><audio:LL-Q652 (ita)-LangPao-cattivo.wav>}}
=== คำคุณศัพท์ ===
{{it-adj|sup=cattivissimo|adv=cattivamente|dim_end=cattivello|dim=cattivetto|end=cattivuccio}}
# [[แย่]], [[ไม่]][[ดี]]
#: {{syn|it|brutto|malvagio}}
#: {{ant|it|buono}}
#: {{ux|it|Ho un '''cattivo''' presentimento.|ฉันรู้สึก'''ไม่ดี'''}}
# [[ร้าย]], [[เกเร]]
==== ลูกคำ ====
* {{l|it|cattivamente}}
* {{l|it|cattiveria}}
==== ดูเพิ่ม ====
* {{l|it|male}}
* {{l|it|malo}}
* {{l|it|malvagio}}
=== คำนาม ===
{{it-noun|m|f=cattiva}}
# [[ตัวร้าย]]
==== ลูกคำ ====
* {{l|it|cattivello}}
* {{l|it|cattivone}}
* {{l|it|cattivaccio}}
648bjs7oxtd6g01chg8po8n52c5hpzk
มอดูล:es-headword
828
40573
5724478
5713268
2026-06-10T06:45:37Z
OctraBot
3198
5724478
Scribunto
text/plain
local export = {}
local pos_functions = {}
local force_cat = false -- for testing; if true, categories appear in non-mainspace pages
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local require_when_needed = require("Module:utilities/require when needed")
local m_table = require("Module:table")
local com = require("Module:es-common")
local en_utilities_module = "Module:en-utilities"
local es_verb_module = "Module:es-verb"
local headword_module = "Module:headword"
local headword_utilities_module = "Module:headword utilities"
local inflection_utilities_module = "Module:inflection utilities"
local romut_module = "Module:romance utilities"
local m_en_utilities = require_when_needed(en_utilities_module)
local m_headword_utilities = require_when_needed(headword_utilities_module)
local m_string_utilities = require_when_needed("Module:string utilities")
local glossary_link = require_when_needed(headword_utilities_module, "glossary_link")
local lang = require("Module:languages").getByCode("es")
local langname = --[[lang:getCanonicalName()]] lang:getCategoryName()
local insert = table.insert
local remove = table.remove
local rsub = com.rsub
local sort = table.sort
local ulower = mw.ustring.lower
local usub = mw.ustring.sub
local uupper = mw.ustring.upper
local function track(page)
require("Module:debug").track("es-headword/" .. page)
return true
end
local list_param = {list = true, disallow_holes = true}
local boolean_param = {type = "boolean"}
-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
local poscat = frame.args[1]
or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
-- หมวดหมู่เป็นภาษาไทย
local poscat_th = require("Module:th-utilities").th_pos(poscat)
local parargs = frame:getParent().args
local params = {
["head"] = list_param,
["id"] = true,
["splithyph"] = boolean_param,
["nolink"] = boolean_param,
["nolinkhead"] = {alias_of = "nolink"},
["json"] = boolean_param,
["pagename"] = true, -- for testing
}
if pos_functions[poscat_th] then
for key, val in pairs(pos_functions[poscat_th].params) do
params[key] = val
end
end
local args = require("Module:parameters").process(parargs, params)
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local user_specified_heads = args.head
local heads = user_specified_heads
if args.nolink then
if #heads == 0 then
heads = {pagename}
end
else
local romut = require(romut_module)
local auto_linked_head = romut.add_links_to_multiword_term(pagename, args.splithyph)
if #heads == 0 then
heads = {auto_linked_head}
else
for i, head in ipairs(heads) do
if head:find("^~") then
head = romut.apply_link_modifiers(auto_linked_head, usub(head, 2))
heads[i] = head
end
end
end
end
local data = {
lang = lang,
pos_category = pos_functions[poscat_th] and pos_functions[poscat_th].pos_category or poscat_th,
categories = {},
heads = heads,
user_specified_heads = user_specified_heads,
no_redundant_head_cat = #user_specified_heads == 0,
genders = {},
inflections = {},
pagename = pagename,
id = args.id,
force_cat_output = force_cat,
checkredlinks = pos_functions[poscat_th] and pos_functions[poscat_th].redlink_pos or true,
}
if pagename:find("^%-") and poscat_th ~= "รูปปัจจัย" then
data.is_suffix = true
data.pos_category = "ปัจจัย"
data.checkredlinks = true
local singular_poscat = --[[m_en_utilities.singularize(poscat)]] poscat_th
insert(data.categories, "ปัจจัยสร้าง" .. singular_poscat .. langname)
insert(data.inflections, {label = "ปัจจัยสร้าง" .. singular_poscat})
end
local pagename_lower = ulower(pagename)
for _, ch in ipairs{"jh", "kh", "ph", "qü", "sh", "th", "tl", "ts", "tz", "wh", "zh", "ze", "zi"} do
if pagename_lower:find(ch) then
insert(data.categories, "ศัพท์" .. langname .. "ที่สะกดด้วย " .. uupper(ch))
end
end
if pos_functions[poscat_th] then
pos_functions[poscat_th].func(args, data, frame, is_suffix)
end
if args.json then
return require("Module:JSON").toJSON(data)
end
return require(headword_module).full_headword(data)
end
-----------------------------------------------------------------------------------------
-- Utility functions --
-----------------------------------------------------------------------------------------
local function replace_hash_with_lemma(term, lemma)
-- If there is a % sign in the lemma, we have to replace it with %% so it doesn't get interpreted as a capture
-- replace expression.
lemma = m_string_utilities.replacement_escape(lemma)
return (term:gsub("#", lemma)) -- discard second retval
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw arguments come
-- from `args[field]`, which is parsed for inline modifiers. `label` is the label that the inflections are given;
-- `accel` is the accelerator form, or nil.
local function parse_and_insert_inflection(data, args, field, label, accel)
m_headword_utilities.parse_and_insert_inflection {
headdata = data,
forms = args[field],
paramname = field,
splitchar = ",",
label = label,
accel = accel and {form = accel} or nil,
}
end
-- Insert default plurals generated when a given plural had the value of + and default plurals were fetched as a result.
-- `plobj` is the parsed object whose `term` field is "+". `defpls` is the list of default plurals. `dest` is the list
-- into which the plurals are inserted (which inherit their qualifiers and labels from `plobj`).
local function insert_defpls(defpls, plobj, dest)
if not defpls then
-- Happens e.g. with [[S.A.]] where the default plural algorithm returns nothing.
return
end
if #defpls == 1 then
plobj.term = defpls[1]
insert(dest, plobj)
else
for _, defpl in ipairs(defpls) do
local newplobj = m_table.shallowCopy(plobj)
newplobj.term = defpl
insert(dest, newplobj)
end
end
end
-----------------------------------------------------------------------------------------
-- Adjectives --
-----------------------------------------------------------------------------------------
local function do_adjective(args, data, is_superlative)
local feminines = {}
local masculine_plurals = {}
local feminine_plurals = {}
-- Use "participle" not "past participle" for categories such as 'invariable participles'
local category_plpos = data.checkredlinks
if category_plpos == true then
category_plpos = data.pos_category
end
local category_pos = --[[m_en_utilities.singularize(category_plpos)]] category_plpos
if args.sp then
local romut = require(romut_module)
if not romut.allowed_special_indicators[args.sp] then
local indicators = {}
for indic, _ in pairs(romut.allowed_special_indicators) do
insert(indicators, "'" .. indic .. "'")
end
sort(indicators)
error("Special inflection indicator beginning can only be " ..
mw.text.listToText(indicators) .. ": " .. args.sp)
end
end
local lemma = data.pagename
local function fetch_inflections(field)
local retval = m_headword_utilities.parse_term_list_with_modifiers {
paramname = field,
forms = args[field],
splitchar = ",",
}
if not retval[1] then
return {{term = "+"}}
end
return retval
end
local function insert_inflection(terms, label, accel)
m_headword_utilities.insert_inflection {
headdata = data,
terms = terms,
label = label,
accel = accel and {form = accel} or nil,
}
end
if args.inv then
-- invariable adjective
insert(data.inflections, {label = glossary_link("ผันรูปไม่ได้")})
insert(data.categories, category_plpos .. "ผันรูปไม่ได้" .. langname)
if args.sp or args.f[1] or args.pl[1] or args.mpl[1] or args.fpl[1] then
error("Can't specify inflections with an invariable " .. category_pos)
end
elseif args.fonly then
-- feminine-only
if args.f[1] then
error("Can't specify explicit feminines with feminine-only " .. category_pos)
end
if args.pl[1] then
error("Can't specify explicit plurals with feminine-only " .. category_pos .. ", use fpl=")
end
if args.mpl[1] then
error("Can't specify explicit masculine plurals with feminine-only " .. category_pos)
end
local argsfpl = fetch_inflections("fpl")
for _, fpl in ipairs(argsfpl) do
if fpl.term == "+" then
-- Generate default feminine plural.
local defpls = com.make_plural(lemma, "f", args.sp)
if not defpls then
error("Unable to generate default plural of '" .. lemma .. "'")
end
insert_defpls(defpls, fpl, feminine_plurals)
else
fpl.term = replace_hash_with_lemma(fpl.term, lemma)
insert(feminine_plurals, fpl)
end
end
insert(data.inflections, {label = "เพศหญิงเท่านั้น"})
insert_inflection(feminine_plurals, "เพศหญิงพหูพจน์", "f|p")
else
-- Gather feminines.
for _, f in ipairs(fetch_inflections("f")) do
if f.term == "+" then
-- Generate default feminine.
f.term = com.make_feminine(lemma, args.sp)
else
f.term = replace_hash_with_lemma(f.term, lemma)
end
insert(feminines, f)
end
local fem_like_lemma = #feminines == 1 and feminines[1].term == lemma and
not m_headword_utilities.termobj_has_qualifiers_or_labels(feminines[1])
if fem_like_lemma then
insert(data.categories, langname .. " epicene " .. category_plpos)
end
local mpl_field = "mpl"
local fpl_field = "fpl"
if args.pl[1] then
if args.mpl[1] or args.fpl[1] then
error("Can't specify both pl= and mpl=/fpl=")
end
mpl_field = "pl"
fpl_field = "pl"
end
local argsmpl = fetch_inflections(mpl_field)
local argsfpl = fetch_inflections(fpl_field)
for _, mpl in ipairs(argsmpl) do
if mpl.term == "+" then
-- Generate default masculine plural.
local defpls = com.make_plural(lemma, "m", args.sp)
if not defpls then
error("Unable to generate default plural of '" .. lemma .. "'")
end
insert_defpls(defpls, mpl, masculine_plurals)
else
mpl.term = replace_hash_with_lemma(mpl.term, lemma)
insert(masculine_plurals, mpl)
end
end
for _, fpl in ipairs(argsfpl) do
if fpl.term == "+" then
for _, f in ipairs(feminines) do
-- Generate default feminine plural; f is a table.
local defpls = com.make_plural(f.term, "f", args.sp)
if not defpls then
error("Unable to generate default plural of '" .. f.term .. "'")
end
for _, defpl in ipairs(defpls) do
local fplobj = m_table.shallowCopy(fpl)
fplobj.term = defpl
m_headword_utilities.combine_termobj_qualifiers_labels(fplobj, f)
insert(feminine_plurals, fplobj)
end
end
else
fpl.term = replace_hash_with_lemma(fpl.term, lemma)
insert(feminine_plurals, fpl)
end
end
parse_and_insert_inflection(data, args, "mapoc", "เพศชายเอกพจน์ก่อนคำนาม")
local fem_pl_like_masc_pl = masculine_plurals[1] and feminine_plurals[1] and
m_table.deepEquals(masculine_plurals, feminine_plurals)
local masc_pl_like_lemma = #masculine_plurals == 1 and masculine_plurals[1].term == lemma and
not m_headword_utilities.termobj_has_qualifiers_or_labels(masculine_plurals[1])
if fem_like_lemma and fem_pl_like_masc_pl and masc_pl_like_lemma then
-- actually invariable
insert(data.inflections, {label = glossary_link("ผันรูปไม่ได้")})
insert(data.categories, category_plpos .. "ผันรูปไม่ได้" .. langname)
else
-- Make sure there are feminines given and not same as lemma.
if not fem_like_lemma then
insert_inflection(feminines, "เพศหญิง", "f|s")
elseif args.gneut then
data.genders = {"gneut"}
else
data.genders = {"mf"}
end
if fem_pl_like_masc_pl then
if args.gneut then
insert_inflection(masculine_plurals, "พหูพจน์", "p")
else
insert_inflection(masculine_plurals, "เพศชายและเพศหญิงพหูพจน์", "p")
end
else
insert_inflection(masculine_plurals, "เพศชายพหูพจน์", "m|p")
insert_inflection(feminine_plurals, "เพศหญิงพหูพจน์", "f|p")
end
end
end
parse_and_insert_inflection(data, args, "comp", "ขั้นกว่า")
parse_and_insert_inflection(data, args, "sup", "ขั้นสุด")
parse_and_insert_inflection(data, args, "dim", "ตัวบอกความเล็ก")
parse_and_insert_inflection(data, args, "aug", "ตัวบอกความใหญ่")
if args.irreg and is_superlative then
insert(data.categories, category_plpos .. "ขั้นสุดไม่ปรกติ" .. langname)
end
end
local function get_adjective_params(adjtype)
local params = {
["inv"] = boolean_param, --invariable
["sp"] = true, -- special indicator: "first", "first-last", etc.
}
local function ins_infl(field)
params[field] = list_param --feminine form(s)
end
ins_infl("f") -- feminine form(s)
ins_infl("pl") -- plural override(s)
ins_infl("mpl") -- masculine plural override(s)
ins_infl("fpl") -- feminine plural override(s)
if adjtype == "base" then
ins_infl("mapoc") --masculine apocopated (before a noun)
ins_infl("comp") --comparative(s)
ins_infl("sup") --superlative(s)
ins_infl("dim") --diminutive(s)
ins_infl("aug") --augmentative(s)
params["fonly"] = boolean_param -- feminine only
params["gneut"] = boolean_param -- gender-neutral adjective e.g. [[latine]]
params["hascomp"] = true -- has comparative
end
if adjtype == "sup" then
params["irreg"] = boolean_param
end
return params
end
pos_functions["คำคุณศัพท์"] = {
params = get_adjective_params("base"),
func = do_adjective,
}
pos_functions["รูปกริยาขยายอดีตกาล"] = {
params = get_adjective_params("part"),
func = do_adjective,
redlink_pos = "รูปกริยาขยาย",
}
pos_functions["ตัวกำหนด"] = {
params = get_adjective_params("det"),
func = do_adjective,
}
pos_functions["คำสรรพนาม"] = {
params = get_adjective_params("pron"),
func = do_adjective,
}
pos_functions["คำคุณศัพท์ขั้นกว่า"] = {
params = get_adjective_params("comp"),
func = do_adjective,
pos_category = "คำคุณศัพท์",
}
pos_functions["คำคุณศัพท์ขั้นสุด"] = {
params = get_adjective_params("sup"),
func = function(args, data)
do_adjective(args, data, true)
end,
pos_category = "คำคุณศัพท์",
}
-----------------------------------------------------------------------------------------
-- Adverbs --
-----------------------------------------------------------------------------------------
pos_functions["คำกริยาวิเศษณ์"] = {
params = {
["sup"] = list_param, --superlative(s)
},
func = function(args, data)
parse_and_insert_inflection(data, args, "sup", "ขั้นสุด")
end,
}
-----------------------------------------------------------------------------------------
-- Numerals --
-----------------------------------------------------------------------------------------
pos_functions["เลขเชิงการนับ"] = {
params = {
["f"] = list_param, --feminine(s)
["mapoc"] = list_param, --masculine apocopated form(s)
},
func = function(args, data)
insert(data.categories, 1, "เลขเชิงการนับ" .. langname)
if args.f[1] then
insert(data.genders, "m")
parse_and_insert_inflection(data, args, "f", "เพศหญิง")
end
parse_and_insert_inflection(data, args, "mapoc", "เพศชายก่อนคำนาม")
end,
pos_category = "เลข",
}
-----------------------------------------------------------------------------------------
-- Nouns --
-----------------------------------------------------------------------------------------
local allowed_genders = m_table.listToSet(
{"m", "f", "mf", "mfbysense", "mfequiv", "gneut", "n", "m-p", "f-p", "mf-p", "mfbysense-p", "mfequiv-p", "gneut-p", "n-p", "?", "?-p"}
)
local function validate_genders(genders)
for _, g in ipairs(genders) do
if type(g) == "table" then
g = g.spec
end
if not allowed_genders[g] then
error("Unrecognized gender: " .. g)
end
end
end
-- Display additional inflection information for a noun
local function do_noun(args, data, is_proper)
local is_plurale_tantum = false
local has_singular = false
local category_plpos = data.checkredlinks
if category_plpos == true then
category_plpos = data.pos_category
end
local category_pos = --[[m_en_utilities.singularize(category_plpos)]] category_plpos
validate_genders(args[1])
data.genders = args[1]
local saw_m = false
local saw_f = false
local saw_gneut = false
local gender_for_irreg_ending, gender_for_make_plural
-- Check for specific genders and pluralia tantum.
for _, g in ipairs(args[1]) do
if type(g) == "table" then
g = g.spec
end
if g:find("-p$") then
is_plurale_tantum = true
else
has_singular = true
if g == "m" or g == "mf" or g == "mfbysense" then
saw_m = true
end
if g == "f" or g == "mf" or g == "mfbysense" then
saw_f = true
end
if g == "gneut" then
saw_gneut = true
end
end
end
if saw_m and saw_f then
gender_for_irreg_ending = "mf"
elseif saw_f then
gender_for_irreg_ending = "f"
else
gender_for_irreg_ending = "m"
end
gender_for_make_plural = saw_gneut and "gneut" or gender_for_irreg_ending
local lemma = data.pagename
local plurals = {}
if is_plurale_tantum and not has_singular then
if args[2][1] then
error("Can't specify plurals of plurale tantum " .. category_pos)
end
insert(data.inflections, {label = glossary_link("พหูพจน์เท่านั้น")})
else
plurals = m_headword_utilities.parse_term_list_with_modifiers {
paramname = {2, "pl"},
forms = args[2],
splitchar = ",",
}
-- Check for special plural signals
local mode = nil
local pl1 = plurals[1]
if pl1 and #pl1.term == 1 then
mode = pl1.term
if mode == "?" or mode == "!" or mode == "-" or mode == "~" then
pl1.term = nil
if next(pl1) then
error(("Can't specify inline modifiers with plural code '%s'"):format(mode))
end
remove(plurals, 1) -- Remove the mode parameter
elseif mode ~= "+" and mode ~= "#" then
error(("Unexpected plural code '%s'"):format(mode))
end
end
if mode == "?" then
-- Plural is unknown
insert(data.categories, langname .. " " .. category_plpos .. " with unknown or uncertain plurals")
elseif mode == "!" then
-- Plural is not attested
insert(data.inflections, {label = "plural not attested"})
insert(data.categories, langname .. " " .. category_plpos .. " with unattested plurals")
if plurals[1] then
error("Can't specify any plurals along with unattested plural code '!'")
end
elseif mode == "-" then
-- Uncountable noun; may occasionally have a plural
insert(data.categories, category_plpos .. "นับไม่ได้" .. langname)
-- If plural forms were given explicitly, then show "usually"
if plurals[1] then
insert(data.inflections, {label = "โดยปกติ" .. glossary_link("นับไม่ได้")})
insert(data.categories, category_plpos .. "นับได้" .. langname)
else
insert(data.inflections, {label = glossary_link("นับไม่ได้")})
end
else
-- Countable or mixed countable/uncountable
if not plurals[1] and not is_proper then
plurals[1] = {term = "+"}
end
if mode == "~" then
-- Mixed countable/uncountable noun, always has a plural
insert(data.inflections, {label = glossary_link("นับได้") .. "และ" .. glossary_link("นับไม่ได้")})
insert(data.categories, category_plpos .. "นับไม่ได้" .. langname)
insert(data.categories, category_plpos .. "นับได้" .. langname)
elseif plurals[1] then
-- Countable nouns
insert(data.categories, category_plpos .. "นับได้" .. langname)
else
-- Uncountable nouns
insert(data.categories, category_plpos .. "นับไม่ได้" .. langname)
end
end
-- Gather plurals, handling requests for default plurals.
local has_default_or_hash = false
for _, pl in ipairs(plurals) do
if pl.term:find("^%+") or pl.term:find("#") then
has_default_or_hash = true
break
end
end
if has_default_or_hash then
local newpls = {}
for _, pl in ipairs(plurals) do
if pl.term == "+" then
local default_pls = com.make_plural(lemma, gender_for_make_plural)
insert_defpls(default_pls, pl, newpls)
elseif pl.term:find("^%+") then
pl.term = require(romut_module).get_special_indicator(pl.term)
local default_pls = com.make_plural(lemma, gender_for_make_plural, pl.term)
insert_defpls(default_pls, pl, newpls)
else
pl.term = replace_hash_with_lemma(pl.term, lemma)
insert(newpls, pl)
end
end
plurals = newpls
end
end
if #plurals > 1 then
insert(data.categories, langname .. " " .. category_plpos .. " with multiple plurals")
end
-- Gather masculines/feminines. For each one, generate the corresponding plural(s). `field` is the name of the
-- field containing the masculine or feminine forms (normally "m" or "f"); `gender` is "m" or "f" for the gender
-- of the forms; `inflect` is a function of one or two arguments to generate the default masculine or feminine from
-- the lemma (the arguments are the lemma and optionally a "special" flag to indicate how to handle multiword
-- lemmas, and the function is normally make_feminine or make_masculine from [[Module:es-common]]); and
-- `default_plurals` is a list into which the corresponding default plurals of the gathered or generated masculine
-- or feminine forms are stored. Note that there may be more default plurals than masculines or feminines, because
-- some terms have multiple possible plurals.
local function handle_mf(field, gender, inflect, default_plurals)
local mfs = m_headword_utilities.parse_term_list_with_modifiers {
paramname = field,
forms = args[field],
splitchar = ",",
frob = function(term)
if term == "+" then
-- Generate default masculine/feminine.
term = inflect(lemma)
else
term = replace_hash_with_lemma(term, lemma)
end
local special = require(romut_module).get_special_indicator(term)
if special then
term = inflect(lemma, special)
end
return term
end
}
for _, mf in ipairs(mfs) do
local mfpls = com.make_plural(mf.term, gender, special)
if mfpls then
for _, mfpl in ipairs(mfpls) do
local plobj = m_table.shallowCopy(mf)
plobj.term = mfpl
-- Add an accelerator for each masculine/feminine plural whose lemma
-- is the corresponding singular, so that the accelerated entry
-- that is generated has a definition that looks like
-- # {{plural of|es|MFSING}}
plobj.accel = {form = "p", lemma = mf.term}
insert(default_plurals, plobj)
end
end
end
return mfs
end
local feminine_plurals = {}
local feminines = handle_mf("f", "f", com.make_feminine, feminine_plurals)
local masculine_plurals = {}
local masculines = handle_mf("m", "m", com.make_masculine, masculine_plurals)
local function handle_mf_plural(mfplfield, gender, default_plurals, singulars)
local mfpl = m_headword_utilities.parse_term_list_with_modifiers {
paramname = mfplfield,
forms = args[mfplfield],
splitchar = ",",
}
local new_mfpls = {}
local saw_plus
for i, mfpl in ipairs(mfpl) do
local accel
if #mfpl == #singulars then
-- If same number of overriding masculine/feminine plurals as singulars,
-- assume each plural goes with the corresponding singular
-- and use each corresponding singular as the lemma in the accelerator.
-- The generated entry will have # {{plural of|es|SINGULAR}} as the
-- definition.
accel = {form = "p", lemma = singulars[i].term}
else
accel = nil
end
if mfpl.term == "+" then
-- We should never see + twice. If we do, it will lead to problems since we overwrite the values of
-- default_plurals the first time around.
if saw_plus then
error(("Saw + twice when handling %s="):format(mfplfield))
end
saw_plus = true
for _, defpl in ipairs(default_plurals) do
-- defpl is already a table and has an accel field
m_headword_utilities.combine_termobj_qualifiers_labels(defpl, mfpl)
insert(new_mfpls, defpl)
end
elseif mfpl.term:find("^%+") then
mfpl.term = require(romut_module).get_special_indicator(mfpl.term)
for _, mf in ipairs(singulars) do
local default_mfpls = com.make_plural(mf.term, gender, mfpl.term)
for _, defp in ipairs(default_mfpls) do
local mfplobj = m_table.shallowCopy(mfpl)
mfplobj.term = defp
mfplobj.accel = accel
m_headword_utilities.combine_termobj_qualifiers_labels(mfplobj, mf)
insert(new_mfpls, mfplobj)
end
end
else
mfpl.accel = accel
mfpl.term = replace_hash_with_lemma(mfpl.term, lemma)
insert(new_mfpls, mfpl)
end
end
return new_mfpls
end
if args.fpl[1] then
-- Override any existing feminine plurals.
feminine_plurals = handle_mf_plural("fpl", "f", feminine_plurals, feminines)
end
if args.mpl[1] then
-- Override any existing masculine plurals.
masculine_plurals = handle_mf_plural("mpl", "m", masculine_plurals, masculines)
end
local function parse_and_insert_noun_inflection(field, label, accel)
parse_and_insert_inflection(data, args, field, label, accel)
end
local function insert_noun_inflection(terms, label, accel)
m_headword_utilities.insert_inflection {
headdata = data,
terms = terms,
label = label,
accel = accel and {form = accel} or nil,
}
end
insert_noun_inflection(plurals, "พหูพจน์", "p")
insert_noun_inflection(feminines, "เพศหญิง", "f")
insert_noun_inflection(feminine_plurals, "เพศหญิงพหูพจน์")
insert_noun_inflection(masculines, "เพศชาย")
insert_noun_inflection(masculine_plurals, "เพศชายพหูพจน์")
parse_and_insert_noun_inflection("dim", "ตัวบอกความเล็ก")
parse_and_insert_noun_inflection("aug", "ตัวบอกความใหญ่")
parse_and_insert_noun_inflection("pej", "pejorative")
parse_and_insert_noun_inflection("dem", "คำประชานาม")
parse_and_insert_noun_inflection("fdem", "คำประชานามเพศหญิง")
-- Maybe add category 'Spanish nouns with irregular gender' (or similar)
local irreg_gender_lemma = rsub(lemma, " .*", "") -- only look at first word
if (rfind(irreg_gender_lemma, "o$") and (gender_for_irreg_ending == "f" or gender_for_irreg_ending == "mf")) or
(irreg_gender_lemma:find("a$") and (gender_for_irreg_ending == "m" or gender_for_irreg_ending == "mf")) then
insert(data.categories, "คำนาม" .. langname .. "ที่มีเพศไม่ปรกติ")
end
end
local function get_noun_params(is_proper)
return {
[1] = {list = "g", disallow_holes = true, required = not is_proper, default = "?", type = "genders",
flatten = true}, -- gender(s)
[2] = {list = "pl", disallow_holes = true}, --plural override(s)
["f"] = list_param, --feminine form(s)
["m"] = list_param, --masculine form(s)
["fpl"] = list_param, --feminine plural override(s)
["mpl"] = list_param, --masculine plural override(s)
["dim"] = list_param, --diminutive(s)
["aug"] = list_param, --diminutive(s)
["pej"] = list_param, --pejorative(s)
["dem"] = list_param, --demonym(s)
["fdem"] = list_param, --female demonym(s)
}
end
pos_functions["คำนาม"] = {
params = get_noun_params(),
func = do_noun,
}
pos_functions["คำวิสามานยนาม"] = {
params = get_noun_params("is proper"),
func = function(args, data)
do_noun(args, data, "is proper")
end,
}
-----------------------------------------------------------------------------------------
-- Verbs --
-----------------------------------------------------------------------------------------
pos_functions["คำกริยา"] = {
params = {
[1] = {},
["pres"] = list_param, --present
["pres_qual"] = {list = "pres\1_qual", allow_holes = true},
["pret"] = list_param, --preterite
["pret_qual"] = {list = "pret\1_qual", allow_holes = true},
["part"] = list_param, --participle
["part_qual"] = {list = "part\1_qual", allow_holes = true},
["pagename"] = {}, -- for testing
["noautolinktext"] = boolean_param,
["noautolinkverb"] = boolean_param,
["attn"] = boolean_param,
},
func = function(args, data)
local preses, prets, parts
if args.attn then
insert(data.categories, "Requests for attention concerning " .. langname)
return
end
local es_verb = require(es_verb_module)
local alternant_multiword_spec = es_verb.do_generate_forms(args, "es-verb", data.heads[1])
local specforms = alternant_multiword_spec.forms
local function slot_exists(slot)
return specforms[slot] and specforms[slot][1]
end
local function do_finite(slot_tense, label_tense)
-- Use pres_3s if it exists and pres_1s doesn't exist (e.g. impersonal verbs); similarly for pres_3p (only3p verbs);
-- but fall back to pres_1s if neither pres_1s nor pres_3s nor pres_3p exist (e.g. [[empedernir]]).
local has_1s = slot_exists(slot_tense .. "_1s")
local has_3s = slot_exists(slot_tense .. "_3s")
local has_3p = slot_exists(slot_tense .. "_3p")
if has_1s or (not has_3s and not has_3p) then
return {
slot = slot_tense .. "_1s",
label = ("บุรุษที่หนึ่งเอกพจน์%s"):format(label_tense),
}
elseif has_3s then
return {
slot = slot_tense .. "_3s",
label = ("บุรุษที่สามเอกพจน์%s"):format(label_tense),
}
else
return {
slot = slot_tense .. "_3p",
label = ("บุรุษที่สามพหูพจน์%s"):format(label_tense),
}
end
end
preses = do_finite("pres", "ปัจจุบันกาล")
prets = do_finite("pret", "preterite")
parts = {
slot = "pp_ms",
label = "รูปกริยาขยายอดีตกาล",
}
if args.pres[1] or args.pret[1] or args.part[1] then
track("verb-old-multiarg")
end
local function strip_brackets(qualifiers)
if not qualifiers then
return nil
end
local stripped_qualifiers = {}
for _, qualifier in ipairs(qualifiers) do
local stripped_qualifier = qualifier:match("^%[(.*)%]$")
if not stripped_qualifier then
error("Internal error: Qualifier should be surrounded by brackets at this stage: " .. qualifier)
end
insert(stripped_qualifiers, stripped_qualifier)
end
return stripped_qualifiers
end
local function do_verb_form(args, qualifiers, slot_desc, skip_if_empty)
local forms
local to_insert
if #args == 0 then
forms = specforms[slot_desc.slot]
if not forms or #forms == 0 then
if skip_if_empty then
return
end
forms = {{form = "-"}}
end
elseif #args == 1 and args[1] == "-" then
forms = {{form = "-"}}
else
forms = {}
for i, arg in ipairs(args) do
local qual = qualifiers[i]
if qual then
-- FIXME: It's annoying we have to add brackets and strip them out later. The inflection
-- code adds all footnotes with brackets around them; we should change this.
qual = {"[" .. qual .. "]"}
end
local form = arg
if not args.noautolinkverb then
-- [[Module:inflection utilities]] already loaded by [[Module:es-verb]]
form = require(inflection_utilities_module).add_links(form)
end
insert(forms, {form = form, footnotes = qual})
end
end
if forms[1].form == "-" then
to_insert = {label = "ไม่มี" .. slot_desc.label}
else
local into_table = {label = slot_desc.label}
for _, form in ipairs(forms) do
local qualifiers = strip_brackets(form.footnotes)
-- Strip redundant brackets surrounding entire form. These may get generated e.g.
-- if we use the angle bracket notation with a single word.
local stripped_form = rmatch(form.form, "^%[%[([^%[%]]*)%]%]$") or form.form
-- Don't include accelerators if brackets remain in form, as the result will be wrong.
-- FIXME: For now, don't include accelerators. We should use {{es-verb form of}} instead.
-- local this_accel = not stripped_form:find("%[%[") and accel or nil
local this_accel = nil
insert(into_table, {term = stripped_form, q = qualifiers, accel = this_accel})
end
to_insert = into_table
end
insert(data.inflections, to_insert)
end
local skip_pres_if_empty
if alternant_multiword_spec.no_pres1_and_sub then
insert(data.inflections, {label = "ไม่มีบุรุษที่หนึ่งเอกพจน์ปัจจุบันกาล"})
insert(data.inflections, {label = "no present subjunctive"})
end
if alternant_multiword_spec.no_pres_stressed then
insert(data.inflections, {label = "no stressed present indicative or subjunctive"})
skip_pres_if_empty = true
end
if alternant_multiword_spec.only3s then
insert(data.inflections, {label = glossary_link("อบุรุษ")})
elseif alternant_multiword_spec.only3sp then
insert(data.inflections, {label = "บุรุษที่สามเท่านั้น"})
elseif alternant_multiword_spec.only3p then
insert(data.inflections, {label = "บุรุษที่สามพหูพจน์เท่านั้น"})
end
do_verb_form(args.pres, args.pres_qual, preses, skip_pres_if_empty)
do_verb_form(args.pret, args.pret_qual, prets)
do_verb_form(args.part, args.part_qual, parts)
-- Add categories.
for _, cat in ipairs(alternant_multiword_spec.categories) do
insert(data.categories, cat)
end
-- If the user didn't explicitly specify head=, or specified exactly one head (not 2+) and we were able to
-- incorporate any links in that head into the 1= specification, use the infinitive generated by
-- [[Module:es-verb]] in place of the user-specified or auto-generated head. This was copied from
-- [[Module:it-headword]], where doing this gets accents marked on the verb(s). We don't have accents marked on
-- the verb but by doing this we do get any footnotes on the infinitive propagated here. Don't do this if the
-- user gave multiple heads or gave a head with a multiword-linked verbal expression such as Italian
-- '[[dare esca]] [[al]] [[fuoco]]' (FIXME: give Spanish equivalent).
if #data.user_specified_heads == 0 or (
#data.user_specified_heads == 1 and alternant_multiword_spec.incorporated_headword_head_into_lemma
) then
data.heads = {}
for _, lemma_obj in ipairs(alternant_multiword_spec.forms.infinitive_linked) do
local quals, refs = require(inflection_utilities_module).
convert_footnotes_to_qualifiers_and_references(lemma_obj.footnotes)
insert(data.heads, {term = lemma_obj.form, q = quals, refs = refs})
end
end
end
}
-----------------------------------------------------------------------------------------
-- Phrases --
-----------------------------------------------------------------------------------------
pos_functions["วลี"] = {
params = {
["g"] = {list = true, disallow_holes = true, type = "genders", flatten = true},
["m"] = list_param,
["f"] = list_param,
},
func = function(args, data)
validate_genders(args.g)
data.genders = args.g
parse_and_insert_inflection(data, args, "m", "เพศชาย")
parse_and_insert_inflection(data, args, "f", "เพศหญิง")
end,
}
-----------------------------------------------------------------------------------------
-- Suffix forms --
-----------------------------------------------------------------------------------------
pos_functions["รูปปัจจัย"] = {
params = {
[1] = {required = true, list = true, disallow_holes = true},
["g"] = {list = true, disallow_holes = true, type = "genders", flatten = true},
},
func = function(args, data)
validate_genders(args.g)
data.genders = args.g
local suffix_type = {}
for _, typ in ipairs(args[1]) do
insert(suffix_type, "ปัจจัยสร้าง" .. typ)
end
insert(data.inflections, {label = "รูปผันของ " .. require("Module:table").serialCommaJoin(suffix_type, {conj = "หรือ"})})
end,
}
return export
ctd4wzsypptavzqun6rkv0c2xtna0jc
มอดูล:affix
828
135995
5724465
5684443
2026-06-10T03:37:49Z
OctraBot
3198
5724465
Scribunto
text/plain
local export = {}
local debug_force_cat = false -- if set to true, always display categories even on userspace pages
local m_links = require("Module:links")
local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local en_utilities_module = "Module:en-utilities"
local etymology_module = "Module:etymology"
local pron_qualifier_module = "Module:pron qualifier"
local scripts_module = "Module:scripts"
local utilities_module = "Module:utilities"
-- Export this so the category code in [[Module:category tree/etymology]] can access it.
export.affix_lang_data_module_prefix = "Module:affix/lang-data/"
local rsub = m_str_utils.gsub
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local rfind = m_str_utils.find
local rmatch = m_str_utils.match
local pluralize = require(en_utilities_module).pluralize
local u = m_str_utils.char
local ucfirst = m_str_utils.ucfirst
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
function export.affix_variants(canonical, variants)
local mappings = {}
for _, variant in ipairs(variants) do
mappings[variant] = canonical
end
return mappings
end
function export.id_mapping(default, ids)
local mapping = { default = default }
if ids then
for id, target in pairs(ids) do
mapping[id] = target
end
end
return mapping
end
function export.id_mapping_with_affix_variants(base, id_variants)
local mappings = {}
for id, variants in pairs(id_variants) do
for _, variant in ipairs(variants) do
mappings[variant] = export.id_mapping(base, {[id] = base})
end
end
return mappings
end
function export.merge_tables(...)
local result = {}
for i = 1, select('#', ...) do
local t = select(i, ...)
if t then
for k, v in pairs(t) do
result[k] = v
end
end
end
return result
end
-- Export this so the category code in [[Module:category tree/etymology]] can access it.
export.langs_with_lang_specific_data = {
["az"] = true,
["fi"] = true,
["fr"] = true,
["izh"] = true,
["la"] = true,
["sah"] = true,
["tr"] = true,
["trk-pro"] = true,
}
local default_pos = "ศัพท์"
--[==[ intro:
===About different types of hyphens ("template", "display" and "lookup"):===
* The "template hyphen" is the per-script hyphen character that is used in template calls to indicate that a term is an
affix. This is always a single Unicode char, but there may be multiple possible hyphens for a given script. Normally
this is just the regular hyphen character "-", but for some non-Latin-script languages (currently only right-to-left
languages), it is different.
* The "display hyphen" is the string (which might be an empty string) that is added onto a term as displayed and linked,
to indicate that a term is an affix. Currently this is always either the same as the template hyphen or an empty
string, but the code below is written generally enough to handle arbitrary display hyphens. Specifically:
*# For East Asian languages, the display hyphen is always blank.
*# For Arabic-script languages, either tatweel (ـ) or ZWNJ (zero-width non-joiner) are allowed as template hyphens,
where ZWNJ is supported primarily for Farsi, because some suffixes have non-joining behavior. The display hyphen
corresponding to tatweel is also tatweel, but the display hyphen corresponding to ZWNJ is blank (tatweel is also
the default display hyphen, for calls to {{tl|prefix}}/{{tl|suffix}}/etc. that don't include an explicit hyphen).
* The "lookup hyphen" is the hyphen that is used when looking up language-specific affix mappings. (These mappings are
discussed in more detail below when discussing link affixes.) It depends only on the script of the affix in question.
Most scripts (including East Asian scripts) use a regular hyphen "-" as the lookup hyphen, but Hebrew and Arabic
have their own lookup hyphens (respectively maqqef and tatweel). Note that for Arabic in particular, there are
three possible template hyphens that are recognized (tatweel, ZWNJ and regular hyphen), but mappings must use tatweel.
===About different types of affixes ("template", "display", "link", "lookup" and "category"):===
* A "template affix" is an affix in its source form as it appears in a template call. Generally, a template affix has an
attached template hyphen (see above) to indicate that it is an affix and indicate what type of affix it is (prefix,
suffix, interfix or circumfix), but some of the older-style templates such as {{tl|suffix}}, {{tl|prefix}},
{{tl|confix}}, etc. have "positional" affixes where the presence of the affix in a certain position (e.g. the second
or third parameter) indicates that it is a certain type of affix, whether or not it has an attached template hyphen.
* A "display affix" is the corresponding affix as it is actually displayed to the user. The display affix may differ
from the template affix for various reasons:
*# The display affix may be specified explicitly using the {{para|alt<var>N</var>}} parameter, the `<alt:...>` inline
modifier or a piped link of the form e.g. `<nowiki>[[-kas|-käs]]</nowiki>` (here indicating that the affix should
display as `-käs` but be linked as `-kas`). Here, the template affix is arguably the entire piped link, while the
display affix is `-käs`.
*# Even in the absence of {{para|alt<var>N</var>}} parameters, `<alt:...>` inline modifiers and piped links, certain
languages have differences between the "template hyphen" specified in the template (which always needs to be
specified somehow or other in templates like {{tl|affix}}, to indicate that the term is an affix and what type of
affix it is) and the display hyphen (see above), with corresponding differences between template and display
affixes.
* A (regular) "link affix" is the affix that is linked to when the affix is shown to the user. The link affix is usually
the same as the display affix, but will differ in one of three circumstances:
*# The display and link affixes are explicitly made different using {{para|alt<var>N</var>}} parameters, `<alt:...>`
inline modifiers or piped links, as described above under "display affix".
*# For certain languages, certain affixes are mapped to canonical form using language-specific mappings. For example,
in Finnish, the adjective-forming suffix {{m|fi|-kas}} appears as {{m|fi|-käs}} after front vowels, but logically
both forms are the same suffix and should be linked and categorized the same. Similarly, in Latin, the negative and
intensive prefixes spelled {{m|la|in-}} (etymologically two distinct prefixes) appear variously as {{m|la|il-}},
{{m|la|im-}} or {{m|la|ir-}} before certain consonants. Mappings are supplied in [[Module:affix/lang-data/LANGCODE]]
to convert Finnish {{m|fi|-käs}} to {{m|fi|-kas}} for linking and categorization purposes. Note that the affixes in
the mappings use "lookup hyphens" to indicate the different types of affixes, which is usually the same as the
template hyphen but differs for Arabic scripts, because there are multiple possible template hyphens recognized but
only one lookup hyphen (tatweel). The form of the affix as used to look up in the mapping tables is called the
"lookup affix"; see below.
* A "stripped link affix" is a link affix that has been passed through the language's `stripDiacritics()` function, which
may strip certain diacritics: e.g. macrons in Latin and Old English (indicating length); acute and grave accents in
Russian and various other Slavic languages (indicating stress); vowel diacritics in most Arabic-script languages; and
also tatweel in some Arabic-script languages (currently, for example, Persian, Arabic and Urdu strip tatweel, but
Ottoman Turkish does not). Stripped link affixes are currently what are used in category names.
* A "lookup affix" is the form of the affix as it is looked up in the language-specific lookup mappings described above
under link affixes. There are actually two lookup stages:
*# First, the affix is looked up in a modified display form (specifically, the same as the display affix but using
lookup hyphens). Note that this lookup does not occur if an explicit display form is given using
{{para|alt<var>N</var>}} or an `<alt:...>` inline modifier, or if the template affix contains a piped or embedded
link.
*# If no entry is found, the affix is then looked up in a modified link form (specifically, the modified display
form passed through the language's `stripDiacritics()` function, which strips out certain diacritics, but with the
lookup hyphen re-added if it was stripped out, as in the case of tatweel in many Arabic-script languages).
The reason for this double lookup procedure is to allow for mappings that are sensitive to the extra diacritics, but
also allow for mappings that are not sensitive in this fashion (e.g. Russian {{m|ru|-ливый}} occurs both stressed and
unstressed, but is the same prefix either way).
* A "category affix" is the affix as it appears in categories such as [[:Category:Finnish terms suffixed with -kas|
Category:Finnish terms suffixed with ''-kas'']]. The category affix is currently always the same as the stripped link
affix. This means that for Arabic-script languages, it may or may not have a tatweel, even if the correponding display
affix and regular link affix have a tatweel. As mentioned above, stripDiacritics() strips tatweel for Arabic, Persian
and Urdu, but not for Ottoman Turkish. Hence affix categories for Arabic, Persian and Urdu will be missing the
tatweel, but affix categories for Ottoman Turkish will have it. An additional complication is that if the template
affix contains a ZWNJ, the display (and hence the link and category affixes) will have no hyphen attached in any case.
]==]
-----------------------------------------------------------------------------------------
-- Template and display hyphens --
-----------------------------------------------------------------------------------------
--[=[
Per-script template hyphens. The template hyphen is what appears in the {{affix}}/{{prefix}}/{{suffix}}/etc. template
(in the wikicode). See above.
They key below is a script code, after removing a hyphen and anything preceding. Hence, script codes like 'fa-Arab'
and 'ur-Arab' will match 'Arab'.
The value below is a string consisting of one or more hyphen characters. If there is more than one character, the
default hyphen must come last and a non-default function must be specified for the script in display_hyphens[] so
the correct display hyphen will be specified when no template hyphen is given (in {{suffix}}/{{prefix}}/etc.).
Script detection is normally done when linking, but we need to do it earlier. However, under most circumstances we
don't need to do script detection. Specifically, we only need to do script detection for a given language if
(a) the language has multiple scripts; and
(b) at least one of those scripts is listed below or in display_hyphens.
]=]
local ZWNJ = u(0x200C) -- zero-width non-joiner
local template_hyphens = {
-- This covers all Arabic scripts. See above.
["Arab"] = "ـ" .. ZWNJ .. "-", -- tatweel + zero-width non-joiner + regular hyphen
["Hebr"] = "־", -- Hebrew-specific hyphen termed "maqqef"
["Mong"] = "᠊",
-- FIXME! What about the following right-to-left scripts?
-- Adlm (Adlam)
-- Armi (Imperial Aramaic)
-- Avst (Avestan)
-- Cprt (Cypriot)
-- Khar (Kharoshthi)
-- Mand (Mandaic/Mandaean)
-- Mani (Manichaean)
-- Mend (Mende/Mende Kikakui)
-- Narb (Old North Arabian)
-- Nbat (Nabataean/Nabatean)
-- Nkoo (N'Ko)
-- Orkh (Orkhon runes)
-- Phli (Inscriptional Pahlavi)
-- Phlp (Psalter Pahlavi)
-- Phlv (Book Pahlavi)
-- Phnx (Phoenician)
-- Prti (Inscriptional Parthian)
-- Rohg (Hanifi Rohingya)
-- Samr (Samaritan)
-- Sarb (Old South Arabian)
-- Sogd (Sogdian)
-- Sogo (Old Sogdian)
-- Syrc (Syriac)
-- Thaa (Thaana)
}
-- Hyphens used when looking up an affix in a lang-specific affix mapping. Defaults to regular hyphen (-). The keys
-- are script codes, after removing a hyphen and anything preceding. Hence, script codes like 'fa-Arab' and 'ur-Arab'
-- will match 'Arab'. The value should be a single character.
local lookup_hyphens = {
["Hebr"] = "־",
-- This covers all Arabic scripts. See above.
["Arab"] = "ـ",
}
-- Default display-hyphen function.
local function default_display_hyphen(script, hyph)
if not hyph then
return template_hyphens[script] or "-"
end
return hyph
end
local function arab_get_display_hyphen(script, hyph)
if not hyph then
return "ـ" -- tatweel
elseif hyph == ZWNJ then
return ""
else
return hyph
end
end
local function no_display_hyphen(script, hyph)
return ""
end
-- Per-script function to return the correct display hyphen given the script and template hyphen. The function should
-- also handle the case where the passed-in template hyphen is nil, corresponding to the situation in
-- {{prefix}}/{{suffix}}/etc. where no template hyphen is specified. The key is the script code after removing a hyphen
-- and anything preceding, so 'fa-Arab', 'ur-Arab' etc. will match 'Arab'.
local display_hyphens = {
-- This covers all Arabic scripts. See above.
["Arab"] = arab_get_display_hyphen,
["Bopo"] = no_display_hyphen,
["Hani"] = no_display_hyphen,
["Hans"] = no_display_hyphen,
["Hant"] = no_display_hyphen,
-- The following is a mixture of several scripts. Hopefully the specs here are correct!
["Jpan"] = no_display_hyphen,
["Jurc"] = no_display_hyphen,
["Kitl"] = no_display_hyphen,
["Kits"] = no_display_hyphen,
["Laoo"] = no_display_hyphen,
["Nshu"] = no_display_hyphen,
["Shui"] = no_display_hyphen,
["Tang"] = no_display_hyphen,
["Thaa"] = no_display_hyphen,
["Thai"] = no_display_hyphen,
["Tibt"] = no_display_hyphen,
}
-----------------------------------------------------------------------------------------
-- Basic Utility functions --
-----------------------------------------------------------------------------------------
local function glossary_link(entry, text)
text = text or entry
return "[[ภาคผนวก:อภิธานศัพท์#" .. entry .. "|" .. text .. "]]"
end
local function track(page)
if type(page) == "table" then
for i, pg in ipairs(page) do
page[i] = "affix/" .. pg
end
else
page = "affix/" .. page
end
require("Module:debug/track")(page)
end
local function ine(val)
return val ~= "" and val or nil
end
-----------------------------------------------------------------------------------------
-- Compound types --
-----------------------------------------------------------------------------------------
local function make_compound_type(typ, alttext)
return {
text = "คำประสม" .. glossary_link(typ, alttext),
cat = "คำประสม" .. typ,
}
end
-- Make a compound type entry with a simple rather than glossary link.
-- These should be replaced with a glossary link when the entry in the glossary
-- is created.
local function make_non_glossary_compound_type(typ, alttext)
local link = alttext and "[[" .. typ .. "|" .. alttext .. "]]" or "[[" .. typ .. "]]"
return {
text = "คำประสม" .. link,
cat = "คำประสม" .. typ,
}
end
local function make_raw_compound_type(typ, alttext)
return {
text = glossary_link(typ, alttext),
cat = pluralize(typ),
}
end
local function make_borrowing_type(typ, alttext)
return {
text = glossary_link(typ, alttext),
borrowing_type = pluralize(typ),
}
end
export.etymology_types = {
["adapted borrowing"] = make_borrowing_type("adapted borrowing"),
["adap"] = "adapted borrowing",
["abor"] = "adapted borrowing",
["alliterative"] = make_non_glossary_compound_type("alliterative"),
["allit"] = "alliterative",
["ตรงข้าม"] = make_non_glossary_compound_type("ตรงข้าม"),
["antonymous"] = "ตรงข้าม",
["ant"] = "ตรงข้าม",
["พหุวรีหิ"] = make_compound_type("พหุวรีหิ"),
["bahuvrihi"] = "พหุวรีหิ",
["bahu"] = "พหุวรีหิ",
["bv"] = "พหุวรีหิ",
["coordinative"] = make_compound_type("coordinative"),
["coord"] = "coordinative",
["descriptive"] = make_compound_type("descriptive"),
["desc"] = "descriptive",
["determinative"] = make_compound_type("determinative"),
["det"] = "determinative",
["ทวันทวะ"] = make_compound_type("ทวันทวะ"),
["dvandva"] = "ทวันทวะ",
["dva"] = "ทวันทวะ",
["dvigu"] = make_compound_type("dvigu"),
["dvi"] = "dvigu",
["endocentric"] = make_compound_type("endocentric"),
["endo"] = "endocentric",
["exocentric"] = make_compound_type("exocentric"),
["exo"] = "exocentric",
["izafet I"] = make_compound_type("izafet I"),
["iz1"] = "izafet I",
["izafet II"] = make_compound_type("izafet II"),
["iz2"] = "izafet II",
["izafet III"] = make_compound_type("izafet III"),
["iz3"] = "izafet III",
["กรรมธารยะ"] = make_compound_type("กรรมธารยะ"),
["karmadharaya"] = "กรรมธารยะ",
["karma"] = "กรรมธารยะ",
["kd"] = "กรรมธารยะ",
["kenning"] = make_raw_compound_type("kenning"),
["ken"] = "kenning",
["สัมผัส"] = make_non_glossary_compound_type("สัมผัส"),
["rhyming"] = "สัมผัส",
["rhy"] = "สัมผัส",
["พ้องความ"] = make_non_glossary_compound_type("พ้องความ"),
["synonymous"] = "พ้องความ",
["syn"] = "พ้องความ",
["ตัตปุรุษะ"] = make_compound_type("ตัตปุรุษะ"),
["tatpurusa"] = "ตัตปุรุษะ",
["tat"] = "ตัตปุรุษะ",
["tp"] = "ตัตปุรุษะ",
}
local function process_etymology_type(typ, nocap, notext, has_parts)
local text_sections = {}
local categories = {}
local borrowing_type
if typ then
local typdata = export.etymology_types[typ]
if type(typdata) == "string" then
typdata = export.etymology_types[typdata]
end
if not typdata then
error("Internal error: Unrecognized type '" .. typ .. "'")
end
local text = typdata.text
if not nocap then
text = ucfirst(text)
end
local cat = typdata.cat
borrowing_type = typdata.borrowing_type
local oftext = typdata.oftext or " ของ"
if not notext then
table.insert(text_sections, text)
if has_parts then
table.insert(text_sections, oftext)
table.insert(text_sections, " ")
end
end
if cat then
table.insert(categories, cat)
end
end
return text_sections, categories, borrowing_type
end
-----------------------------------------------------------------------------------------
-- Utility functions --
-----------------------------------------------------------------------------------------
-- Iterate an array up to the greatest integer index found.
local function ipairs_with_gaps(t)
local indices = m_table.numKeys(t)
local max_index = #indices > 0 and math.max(unpack(indices)) or 0
local i = 0
return function()
while i < max_index do
i = i + 1
return i, t[i]
end
end
end
export.ipairs_with_gaps = ipairs_with_gaps
--[==[
Join formatted parts (in `parts_formatted`) together with any overall {{para|lit}} spec (in `lit`) plus categories,
which are formatted by prepending the language name as found in `lang`. The value of an entry in `categories` can be
either a string (which is formatted using `sort_key`) or a table of the form `{ {cat=<var>category</var>,
sort_key=<var>sort_key</var>, sort_base=<var>sort_base</var>}`, specifying the sort key and sort base to use when
formatting the category. If `nocat` is given, no categories are added; otherwise, `force_cat` causes categories to be
added even on userspace pages.
]==]
function export.join_formatted_parts(data)
local cattext
local lang = data.data.lang
local force_cat = data.data.force_cat or debug_force_cat
if data.data.nocat then
cattext = ""
else
for i, cat in ipairs(data.categories) do
if type(cat) == "table" then
--data.categories[i] = require(utilities_module).format_categories(lang:getFullName() .. " " .. cat.cat,
-- lang, cat.sort_key, cat.sort_base, force_cat)
if cat.cat:match("^ศัพท์ที่") then
data.categories[i] = require(utilities_module).format_categories("ศัพท์ภาษา" .. lang:getFullName() .. usub(cat.cat, 6),
lang, cat.sort_key, cat.sort_base, force_cat)
else
data.categories[i] = require(utilities_module).format_categories(cat.cat .. "ภาษา" .. lang:getFullName(),
lang, cat.sort_key, cat.sort_base, force_cat)
end
else
--data.categories[i] = require(utilities_module).format_categories(lang:getFullName() .. " " .. cat, lang,
-- data.data.sort_key, nil, force_cat)
if cat:match("^ศัพท์ที่") then
data.categories[i] = require(utilities_module).format_categories("ศัพท์ภาษา" .. lang:getFullName() .. usub(cat, 6),
data.data.sort_key, nil, force_cat)
else
data.categories[i] = require(utilities_module).format_categories(cat .. "ภาษา" .. lang:getFullName(),
data.data.sort_key, nil, force_cat)
end
end
end
cattext = table.concat(data.categories)
end
local result = table.concat(data.parts_formatted, not data.separator_already_added and " +‎ " or nil) ..
(data.data.lit and ", literally " .. m_links.mark(data.data.lit, "gloss") or "")
local q = data.data.q
local qq = data.data.qq
local l = data.data.l
local ll = data.data.ll
local infl = data.data.infl
if q and q[1] or qq and qq[1] or l and l[1] or ll and ll[1] or infl and infl[1] then
result = require(pron_qualifier_module).format_qualifiers {
lang = lang,
text = result,
q = q,
qq = qq,
l = l,
ll = ll,
infl = infl,
}
end
return result .. cattext
end
local function pluralize(pos)
--[[ ไม่ใช้ในภาษาไทย
if pos ~= "nouns" and usub(pos, -5) ~= "verbs" and usub(pos, -4) ~= "ives" then
if pos:find("[sx]$") then
pos = pos .. "es"
else
pos = pos .. "s"
end
end
--]]
return pos
end
-- Remove links and call lang:stripDiacritics(term).
local function strip_diacritics_no_links(lang, term)
return lang:stripDiacritics(m_links.remove_links(term))
end
--[=[
Convert a raw part as passed into an entry point into a part ready for linking. `lang` and `sc` are the overall
language and script objects. This uses the overall language and script objects as defaults for the part and parses off
any fragment from the term. We need to do the latter so that fragments don't end up in categories and so that we
correctly do affix mapping even in the presence of fragments.
]=]
local function canonicalize_part(part, lang, sc)
if not part then
return
end
-- Save the original (user-specified, part-specific) value of `lang`. If such a value is specified, we don't insert
-- a '*fixed with' category, and we format the part using format_derived() in [[Module:etymology]] rather than
-- full_link() in [[Module:links]].
part.part_lang = part.lang
part.lang = part.lang or lang
part.sc = part.sc or sc
local term = part.term
if not term then
return
elseif not part.fragment then
part.term, part.fragment = m_links.get_fragment(term)
else
part.term = m_links.get_fragment(term)
end
end
--[==[
Construct a single linked part based on the information in `part`, for use by `show_affix()` and other entry points.
This should be called after `canonicalize_part()` is called on the part. This is a thin wrapper around `full_link()` in
[[Module:links]] unless `part.part_lang` is specified (indicating that a part-specific language was given), in which
case `format_derived()` in [[Module:etymology]] is called to display a term in a language other than the language of
the overall term (specified in `data.lang`). `data` contains the entire object passed into the entry point and is used
to access information for constructing the categories added by `format_derived()`.
]==]
function export.link_term(part, data, include_separator)
local result
if part.part_lang then
result = require(etymology_module).format_derived {
lang = data.lang,
terms = {part},
sources = {part.lang},
sort_key = data.sort_key,
nocat = data.nocat,
template_name = "affix",
qualifiers_labels_on_outside = true,
borrowing_type = data.borrowing_type,
force_cat = data.force_cat or debug_force_cat,
}
else
result = m_links.full_link(part, "term", nil, "show qualifiers")
end
if include_separator and part.separator then
return part.separator .. result
else
return result
end
end
local function canonicalize_script_code(scode)
-- Convert fa-Arab, ur-Arab etc. to Arab.
return (scode:gsub("^.*%-", ""))
end
-----------------------------------------------------------------------------------------
-- Affix-handling functions --
-----------------------------------------------------------------------------------------
-- Figure out the appropriate script for the given affix and language (unless the script is explicitly passed in), and
-- return the values of template_hyphens[], display_hyphens[] and lookup_hyphens[] for that script, substituting
-- default values as appropriate. Four values are returned:
-- DETECTED_SCRIPT, TEMPLATE_HYPHEN, DISPLAY_HYPHEN, LOOKUP_HYPHEN
local function detect_script_and_hyphens(text, lang, sc)
local scode
-- 1. If the script is explicitly passed in, use it.
if sc then
scode = sc:getCode()
else
local possible_script_codes = lang:getScriptCodes()
-- YUCK! `possible_script_codes` comes from loadData() so #possible_scripts doesn't work (always returns 0).
local num_possible_script_codes = m_table.length(possible_script_codes)
if num_possible_script_codes == 0 then
-- This shouldn't happen; if the language has no script codes,
-- the list {"None"} should be returned.
error("Something is majorly wrong! Language " .. lang:getCanonicalName() .. " has no script codes.")
end
if num_possible_script_codes == 1 then
-- 2. If the language has only one possible script, use it.
scode = possible_script_codes[1]
else
-- 3. Check if any of the possible scripts for the language have non-default values for template_hyphens[]
-- or display_hyphens[]. If so, we need to do script detection on the text. If not, just use "Latn",
-- which may not be technically correct but produces the right results because Latn has all default
-- values for template_hyphens[] and display_hyphens[].
local may_have_nondefault_hyphen = false
for _, script_code in ipairs(possible_script_codes) do
script_code = canonicalize_script_code(script_code)
if template_hyphens[script_code] or display_hyphens[script_code] then
may_have_nondefault_hyphen = true
break
end
end
if not may_have_nondefault_hyphen then
scode = "Latn"
else
scode = lang:findBestScript(text):getCode()
end
end
end
scode = canonicalize_script_code(scode)
local template_hyphen = template_hyphens[scode] or "-"
local lookup_hyphen = lookup_hyphens[scode] or "-"
local display_hyphen = display_hyphens[scode] or default_display_hyphen
return scode, template_hyphen, display_hyphen, lookup_hyphen
end
--[=[
Given a template affix `term` and an affix type `affix_type`, change the relevant template hyphen(s) in the affix to
the display or lookup hyphen specified in `new_hyphen`, or add them if they are missing. `new_hyphen` can be a string,
specifying a fixed hyphen, or a function of two arguments (the script code `scode` and the discovered template hyphen,
or nil of no relevant template hyphen is present). `thyph_re` is a Lua pattern (which must be enclosed in parens) that
matches the possible template hyphens. Note that not all template hyphens present in the affix are changed, but only
the "relevant" ones (e.g. for a prefix, a relevant template hyphen is one coming at the end of the affix).
]=]
local function reconstruct_term_per_hyphens(term, affix_type, scode, thyph_re, new_hyphen)
local function get_hyphen(hyph)
if type(new_hyphen) == "string" then
return new_hyphen
end
return new_hyphen(scode, hyph)
end
if affix_type == "ไม่ใช่หน่วยคำเติม" then
return term
elseif affix_type == "หน่วยคำเติมคร่อม" then
local before, before_hyphen, after_hyphen, after = rmatch(term, "^(.*)" .. thyph_re .. " " .. thyph_re
.. "(.*)$")
if not before or ulen(term) <= 3 then
-- Unlike with other types of affixes, don't try to add hyphens in the middle of the term to convert it to
-- a circumfix. Also, if the term is just hyphen + space + hyphen, return it.
return term
end
return before .. get_hyphen(before_hyphen) .. " " .. get_hyphen(after_hyphen) .. after
elseif affix_type == "อาคม" or affix_type == "หน่วยคำเติมเชื่อม" then
local before_hyphen, middle, after_hyphen = rmatch(term, "^" .. thyph_re .. "(.*)" .. thyph_re .. "$")
if before_hyphen and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return get_hyphen(before_hyphen) .. (middle or term) .. get_hyphen(after_hyphen)
elseif affix_type == "อุปสรรค" then
local middle, after_hyphen = rmatch(term, "^(.*)" .. thyph_re .. "$")
if middle and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return (middle or term) .. get_hyphen(after_hyphen)
elseif affix_type == "ปัจจัย" then
local before_hyphen, middle = rmatch(term, "^" .. thyph_re .. "(.*)$")
if before_hyphen and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return get_hyphen(before_hyphen) .. (middle or term)
else
error(("Internal error: Unrecognized affix type '%s'"):format(affix_type))
end
end
--[=[
Look up a mapping from a given affix variant to the canonical form used in categories and links. The lookup tables are
language-specific according to `lang`, and may be ID-specific according to `affix_id`. The affixes as they appear in the
lookup tables (both the variant and the canonical form) are in "lookup affix" format (approximately speaking, they use a
regular hyphen for most scripts, but a tatweel for Arabic-script entries and a maqqef for Hebrew-script entries), but
the passed-in `affix` param is in "template affix" format (which differs from the lookup affix for Arabic-script
entries, because more types of hyphens are allowed in template affixes; see the comments at the top of the file). The
remaining parameters to this function are used to convert from template affixes to lookup affixes; see the
reconstruct_term_per_hyphens() function above.
If the affix contains brackets, no lookup is done. Otherwise, a two-stage process is used, first looking up the affix
directly and then stripping diacritics and looking it up again. The reason for this is documented above in the comments
at the top of the file (specifically, the comments describing lookup affixes).
The value of a mapping can either be a string (do the mapping regardless of affix ID) or a table indexed by affix ID
(where the special value `false` indicates no affix ID). The values of entries in this table can also be strings, or
tables with keys `affix` and `id` (again, use `false` to indicate no ID). This allows an affix mapping to map from one
ID to another (for example, this is used in English to map the [[an-]] prefix with no ID to the [[a-]] prefix with the
ID 'not').
The Given a template affix `term` and an affix type `affix_type`, change the relevant template hyphen(s) in the affix to
the display or lookup hyphen specified in `new_hyphen`, or add them if they are missing. `new_hyphen` can be a string,
specifying a fixed hyphen, or a function of two arguments (the script code `scode` and the discovered template hyphen,
or nil of no relevant template hyphen is present). `thyph_re` is a Lua pattern (which must be enclosed in parens) that
matches the possible template hyphens. Note that not all template hyphens present in the affix are changed, but only
the "relevant" ones (e.g. for a prefix, a relevant template hyphen is one coming at the end of the affix).
]=]
local function lookup_affix_mapping(affix, affix_type, lang, scode, thyph_re, lookup_hyph, affix_id)
local function do_lookup(affix)
-- Ensure that the affix uses lookup hyphens regardless of whether it used a different type of hyphens before
-- or no hyphens.
local lookup_affix = reconstruct_term_per_hyphens(affix, affix_type, scode, thyph_re, lookup_hyph)
local function do_lookup_for_langcode(langcode)
if export.langs_with_lang_specific_data[langcode] then
local langdata = mw.loadData(export.affix_lang_data_module_prefix .. langcode)
if langdata.affix_mappings then
local mapping = langdata.affix_mappings[lookup_affix]
if mapping then
if type(mapping) == "table" then
mapping = mapping[affix_id] or mapping.default or mapping[affix_id or false]
if mapping then
return mapping
end
else
return mapping
end
end
end
end
end
-- If `lang` is an etymology-only language, look for a mapping both for it and its full parent.
local langcode = lang:getCode()
local mapping = do_lookup_for_langcode(langcode)
if mapping then
return mapping
end
local full_langcode = lang:getFullCode()
if full_langcode ~= langcode then
mapping = do_lookup_for_langcode(full_langcode)
if mapping then
return mapping
end
end
return nil
end
if affix:find("%[%[") then
return nil
end
return do_lookup(affix) or do_lookup(lang:stripDiacritics(affix)) or nil
end
--[==[
For a given template term in a given language (see the definition of "template affix" near the top of the file),
possibly in an explicitly specified script `sc` (but usually nil), return the term's affix type ({"prefix"},
{"interfix"}, {"suffix"}, {"circumfix"} or {"non-affix"}) along with the corresponding link and display affixes
(see definitions near the top of the file); also the corresponding lookup affix (if `return_lookup_affix` is specified).
The term passed in should already have any fragment (after the # sign) parsed off of it. Four values are returned:
`affix_type`, `link_term`, `display_term` and `lookup_term`. The affix type can be passed in instead of autodetected; in
this case, the template term need not have any attached hyphens, and the appropriate hyphens will be added in the
appropriate places. If `do_affix_mapping` is specified, look up the affix in the lang-specific affix mappings, as
described in the comment at the top of the file; otherwise, the link and display terms will always be the same. (They
will be the same in any case if the template term has a bracketed link in it or is not an affix.) If
`return_lookup_affix` is given, the fourth return value contains the term with appropriate lookup hyphens in the
appropriate places; otherwise, it is the same as the display term. (This functionality is used in
[[Module:category tree/affixes and compounds]] to convert link affixes into lookup affixes so that they can be looked up
in the affix mapping tables.)
]==]
local function parse_term_for_affixes(term, lang, sc, affix_type, do_affix_mapping, return_lookup_affix, affix_id)
if not term then
return "ไม่ใช่หน่วยคำเติม", nil, nil, nil
end
if term == "^" then
-- Indicates a null term to emulate the behavior of {{suffix|foo||bar}}.
term = ""
return "ไม่ใช่หน่วยคำเติม", term, term, term
end
if term:find("^%^") then
-- HACK! ^ at the beginning of Korean languages has a special meaning, triggering capitalization of the
-- transliteration. Don't interpret it as "force non-affix" for those languages.
local langcode = lang:getCode()
if langcode ~= "ko" and langcode ~= "okm" and langcode ~= "jje" then
-- Formerly we allowed ^ to force non-affix type; this is now handled using an inline modifier
-- <naf>, <root>, etc. Throw an error for the moment when the old way is encountered.
error("Use of ^ to force non-affix status is no longer supported; use an inline modifier <naf> or <root> " ..
"after the component")
end
end
-- Remove an asterisk if the morpheme is reconstructed and add it back at the end.
local reconstructed = ""
if term:find("^%*") then
reconstructed = "*"
term = term:gsub("^%*", "")
end
local scode, thyph, dhyph, lhyph = detect_script_and_hyphens(term, lang, sc)
thyph = "([" .. thyph .. "])"
if not affix_type then
if rfind(term, thyph .. " " .. thyph) then
affix_type = "หน่วยคำเติมคร่อม"
else
local has_beginning_hyphen = rfind(term, "^" .. thyph)
local has_ending_hyphen = rfind(term, thyph .. "$")
if has_beginning_hyphen and has_ending_hyphen then
affix_type = "หน่วยคำเติมเชื่อม"
elseif has_ending_hyphen then
affix_type = "อุปสรรค"
elseif has_beginning_hyphen then
affix_type = "ปัจจัย"
else
affix_type = "ไม่ใช่หน่วยคำเติม"
end
end
end
local link_term, display_term, lookup_term
if affix_type == "ไม่ใช่หน่วยคำเติม" then
link_term = term
display_term = term
lookup_term = term
else
display_term = reconstruct_term_per_hyphens(term, affix_type, scode, thyph, dhyph)
if do_affix_mapping then
link_term = lookup_affix_mapping(term, affix_type, lang, scode, thyph, lhyph, affix_id)
-- The return value of lookup_affix_mapping() may be an affix mapping with lookup hyphens if a mapping
-- was found, otherwise nil if a mapping was not found. We need to convert to display hyphens in
-- either case, but in the latter case we can reuse the display term, which has already been converted.
if link_term then
link_term = reconstruct_term_per_hyphens(link_term, affix_type, scode, thyph, dhyph)
else
link_term = display_term
end
else
link_term = display_term
end
if return_lookup_affix then
lookup_term = reconstruct_term_per_hyphens(term, affix_type, scode, thyph, lhyph)
else
lookup_term = display_term
end
end
link_term = reconstructed .. link_term
display_term = reconstructed .. display_term
lookup_term = reconstructed .. lookup_term
return affix_type, link_term, display_term, lookup_term
end
--[==[
Add a hyphen to a term in the appropriate place, based on the specified affix type, stripping off any existing hyphens
in that place. For example, if `affix_type` == {"prefix"}, we'll add a hyphen onto the end if it's not already there (or
is of the wrong type). Three values are returned: the link term, display term and lookup term. This function is a thin
wrapper around `parse_term_for_affixes`; see the comments above that function for more information. Note that this
function is exposed externally because it is called by [[Module:category tree/affixes and compounds]]; see the comment
in `parse_term_for_affixes` for more information.
]==]
function export.make_affix(term, lang, sc, affix_type, do_affix_mapping, return_lookup_affix, affix_id)
if not (affix_type == "อุปสรรค" or affix_type == "ปัจจัย" or affix_type == "หน่วยคำเติมคร่อม" or affix_type == "อาคม" or
affix_type == "หน่วยคำเติมเชื่อม" or affix_type == "ไม่ใช่หน่วยคำเติม") then
error("Internal error: Invalid affix type " .. (affix_type or "(nil)"))
end
local _, link_term, display_term, lookup_term = parse_term_for_affixes(term, lang, sc, affix_type,
do_affix_mapping, return_lookup_affix, affix_id)
return link_term, display_term, lookup_term
end
-----------------------------------------------------------------------------------------
-- Main entry points --
-----------------------------------------------------------------------------------------
--[==[
Core categorization logic for affixes. This is shared between show_affix(), show_compound_like() and
get_affix_categories_only(). Returns the categories array and other metadata needed for formatting.
]==]
local function generate_affix_categories(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
local text_sections, categories, borrowing_type =
process_etymology_type(data.type, data.surface_analysis or data.nocap, data.notext, #data.parts > 0)
data.borrowing_type = borrowing_type
-- Process each part
local whole_words = 0
local is_affix_or_compound = false
-- Canonicalize and generate links for all the parts first; then do categorization in a separate step, because when
-- processing the first part for categorization, we may access the second part and need it already canonicalized.
for i, part in ipairs_with_gaps(data.parts) do
part = part or {}
data.parts[i] = part
canonicalize_part(part, data.lang, data.sc)
-- Determine affix type and get link and display terms (see text at top of file). Store them in the part
-- (in fields that won't clash with fields used by full_link() in [[Module:links]] or link_term()), so they
-- can be used in the loop below when categorizing.
part.affix_type, part.affix_link_term, part.affix_display_term = parse_term_for_affixes(part.term,
part.lang, part.sc, part.type, not part.alt, nil, part.id)
-- If link_term is an empty string, either a bare ^ was specified or an empty term was used along with inline
-- modifiers. The intention in either case is not to link the term.
part.term = ine(part.affix_link_term)
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
part.alt = part.alt or (part.affix_display_term ~= part.affix_link_term and part.affix_display_term) or nil
end
if not data.noaffixcat then
-- Now do categorization.
for i, part in ipairs_with_gaps(data.parts) do
local affix_type = part.affix_type
if affix_type ~= "ไม่ใช่หน่วยคำเติม" then
is_affix_or_compound = true
-- Make a sort key. For the first part, use the second part as the sort key; the intention is that if the
-- term has a prefix, sorting by the prefix won't be very useful so we sort by what follows, which is
-- presumably the root.
local part_sort_base = nil
local part_sort = part.sort or data.sort_key
if i == 1 and data.parts[2] and data.parts[2].term then
local part2 = data.parts[2]
-- If the second-part link term is empty, the user requested an unlinked term; avoid a wikitext error
-- by using the alt value if available.
part_sort_base = ine(part2.affix_link_term) or ine(part2.alt)
if part_sort_base then
part_sort_base = strip_diacritics_no_links(part2.lang, part_sort_base)
end
end
if part.pos and rfind(part.pos, "ปิตุวงศ์") then
table.insert(categories, {cat = "ชื่อปิตุวงศ์", sort_key = part_sort, sort_base = part_sort_base})
end
if data.pos ~= "terms" and part.pos and rfind(part.pos, "บอกความเล็ก") then
table.insert(categories, {cat = data.pos .. "บอกความเล็ก", sort_key = part_sort,
sort_base = part_sort_base})
end
-- Don't add a '*fixed with' category if the link term is empty or is in a different language.
if ine(part.affix_link_term) and not part.part_lang then
table.insert(categories, {cat = data.pos .. "ที่เติม" .. affix_type .. " " ..
strip_diacritics_no_links(part.lang, part.affix_link_term) ..
(part.id and " (" .. part.id .. ")" or ""),
sort_key = part_sort, sort_base = part_sort_base})
end
else
whole_words = whole_words + 1
if whole_words == 2 then
is_affix_or_compound = true
--table.insert(categories, "compound " .. data.pos)
if data.pos == "ศัพท์" then --th
table.insert(categories, "คำประสม")
else
table.insert(categories, data.pos .. "ประสม")
end
end
end
end
-- Make sure there was either an affix or a compound (two or more non-affix terms).
if not is_affix_or_compound and not data.allow_no_affixes_or_compounds then
error("The parameters did not include any affixes, and the term is not a compound. Please provide at least one affix.")
end
end
return text_sections, categories, borrowing_type
end
--[==[
Implementation of {{tl|affix}} and {{tl|surface analysis}}. `data` contains all the information describing the affixes to
be displayed, and contains the following:
* `.lang` ('''required'''): Overall language object. Different from term-specific language objects (see `.parts` below).
* `.sc`: Overall script object (usually omitted). Different from term-specific script objects.
* `.parts` ('''required'''): List of objects describing the affixes to show. The general format of each object is as would
be passed to `full_link()`, except that the `.lang` field should be missing unless the term is of a language
different from the overall `.lang` value (in such a case, the language name is shown along with the term and
an additional "derived from" category is added). '''WARNING''': The data in `.parts` will be destructively
modified.
* `.pos`: Overall part of speech (used in categories, defaults to {"terms"}). Different from term-specific part of speech.
* `.sort_key`: Overall sort key. Normally omitted except e.g. in Japanese.
* `.type`: Type of compound, if the parts in `.parts` describe a compound. Strictly optional, and if supplied, the
compound type is displayed before the parts (normally capitalized, unless `.nocap` is given).
* `.nocap`: Don't capitalize the first letter of text displayed before the parts (relevant only if `.type` or
`.surface_analysis` is given).
* `.notext`: Don't display any text before the parts (relevant only if `.type` or `.surface_analysis` is given).
* `.nocat`: Disable all categorization.
* `.noaffixcat`: Disable affix (and compound) categorization. Relevant for e.g. blends, which may otherwise
be incorrectly categorized as compound terms.
* `.lit`: Overall literal definition. Different from term-specific literal definitions.
* `.force_cat`: Always display categories, even on userspace pages.
* `.surface_analysis`: Implement {{surface analysis}}; adds `By surface analysis, ` before the parts.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_affix(data)
local text_sections, categories, borrowing_type = generate_affix_categories(data)
-- Process each part for display
local parts_formatted = {}
for i, part in ipairs_with_gaps(data.parts) do
-- Make a link for the part
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if data.surface_analysis then
--local text = "by " .. glossary_link("surface analysis") .. ", "
local text = "พิจารณาคร่าว ๆ เทียบเท่า "
if not data.nocap then
text = ucfirst(text)
end
table.insert(text_sections, 1, text)
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Get only the categories that would be generated by show_affix(), without any text output or formatting.
This is used by Module:etymon to get affix categorization.
Returns an array of category objects, where
each entry is either a string (simple category name) or a table with keys `cat`, `sort_key`,
and `sort_base` for more complex categorization.
`data` should have the same structure as passed to show_affix():
* `.lang` (required): Overall language object
* `.parts` (required): Array of affix part objects with `.term`, `.lang`, `.id`, etc.
* `.pos`: Part of speech (defaults to "terms")
* `.sort_key`: Overall sort key for categories
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.get_affix_categories_only(data)
local text_sections, categories, borrowing_type = generate_affix_categories(data)
return categories
end
function export.show_surface_analysis(data)
data.surface_analysis = true
data.allow_no_affixes_or_compounds = true
return export.show_affix(data)
end
--[==[
Implementation of {{tl|compound}}.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_compound(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
local text_sections, categories, borrowing_type =
process_etymology_type(data.type, data.nocap, data.notext, #data.parts > 0)
data.borrowing_type = borrowing_type
local parts_formatted = {}
--table.insert(categories, "compound " .. data.pos)
if data.pos == "ศัพท์" then --th
table.insert(categories, "คำประสม")
else
table.insert(categories, data.pos .. "ประสม")
end
-- Make links out of all the parts
local whole_words = 0
for i, part in ipairs(data.parts) do
canonicalize_part(part, data.lang, data.sc)
-- Determine affix type and get link and display terms (see text at top of file).
local affix_type, link_term, display_term = parse_term_for_affixes(part.term, part.lang, part.sc,
part.type, not part.alt, nil, part.id)
-- If the term is an interfix or the type was explicitly given, recognize it as such (which means e.g. that we
-- will display the term without hyphens for East Asian languages). Otherwise, ignore the fact that it looks
-- like an affix and display as specified in the template (but pay attention to the detected affix type for
-- certain tracking purposes).
if affix_type == "หน่วยคำเติมเชื่อม" or (part.type and part.type ~= "ไม่ใช่หน่วยคำเติม") then
-- If link_term is an empty string, either a bare ^ was specified or an empty term was used along with
-- inline modifiers. The intention in either case is not to link the term. Don't add a '*fixed with'
-- category in this case, or if the term is in a different language.
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
if link_term and link_term ~= "" and not part.part_lang then
table.insert(categories, {cat = data.pos .. "ที่เติม" .. affix_type .. " " ..
strip_diacritics_no_links(part.lang, link_term), sort_key = part.sort or data.sort_key})
end
part.term = link_term ~= "" and link_term or nil
part.alt = part.alt or (display_term ~= link_term and display_term) or nil
else
if affix_type ~= "ไม่ใช่หน่วยคำเติม" then
local langcode = data.lang:getCode()
-- If `data.lang` is an etymology-only language, track both using its code and its full parent's code.
track { affix_type, affix_type .. "/lang/" .. langcode }
local full_langcode = data.lang:getFullCode()
if langcode ~= full_langcode then
track(affix_type .. "/lang/" .. full_langcode)
end
else
whole_words = whole_words + 1
end
end
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if whole_words == 1 then
track("one whole word")
elseif whole_words == 0 then
track("looks like confix")
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Implementation of {{tl|blend}}, {{tl|univerbation}} and similar "compound-like" templates.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_compound_like(data)
data.allow_no_affixes_or_compounds = true
local text_sections, categories, borrowing_type = generate_affix_categories(data)
if data.cat then
table.insert(categories, data.cat)
end
-- Process each part for display
local parts_formatted = {}
for i, part in ipairs_with_gaps(data.parts) do
-- Make a link for the part
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if #data.parts > 0 and data.oftext then
table.insert(text_sections, 1, " " .. data.oftext .. " ")
end
if data.text then
table.insert(text_sections, 1, data.text)
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Make `part` (a structure holding information on an affix part) into an affix of type `affix_type`, and apply any
relevant affix mappings. For example, if the desired affix type is "suffix", this will (in general) add a hyphen onto
the beginning of the term, alt, tr and ts components of the part if not already present. The hyphen that's added is the
"display hyphen" (see above) and may be script-specific. (In the case of East Asian scripts, the display hyphen is an
empty string whereas the template hyphen is the regular hyphen, meaning that any regular hyphen at the beginning of the
part will be effectively removed.) `lang` and `sc` hold overall language and script objects.
Note that this also applies any language-specific affix mappings, so that e.g. if the language is Finnish and the user
specified [[-käs]] in the affix and didn't specify an `.alt` value, `part.term` will contain [[-kas]] and `part.alt` will
contain [[-käs]].
This function is used by the "legacy" templates ({{tl|prefix}}, {{tl|suffix}}, {{tl|confix}}, etc.) where the nature of
the affix is specified by the template itself rather than auto-determined from the affix, as is the case with
{{tl|affix}}.
'''WARNING''': This destructively modifies `part`.
]==]
local function make_part_into_affix(part, lang, sc, affix_type)
canonicalize_part(part, lang, sc)
local link_term, display_term = export.make_affix(part.term, part.lang, part.sc, affix_type, not part.alt, nil, part.id)
part.term = link_term
-- When we don't specify `do_affix_mapping` to make_affix(), link and display terms (first and second retvals of
-- make_affix()) are the same.
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
part.alt = part.alt and export.make_affix(part.alt, part.lang, part.sc, affix_type) or (display_term ~= link_term and display_term) or nil
local Latn = require(scripts_module).getByCode("Latn")
part.tr = export.make_affix(part.tr, part.lang, Latn, affix_type)
part.ts = export.make_affix(part.ts, part.lang, Latn, affix_type)
end
local function track_wrong_affix_type(template, part, expected_affix_type)
if part and not part.type then
local affix_type = parse_term_for_affixes(part.term, part.lang, part.sc)
if affix_type ~= expected_affix_type then
local part_name = expected_affix_type or "base"
local langcode = part.lang:getCode()
local full_langcode = part.lang:getFullCode()
require("Module:debug/track") {
template,
template .. "/" .. part_name,
template .. "/" .. part_name .. "/" .. (affix_type or "none"),
template .. "/" .. part_name .. "/" .. (affix_type or "none") .. "/lang/" .. langcode
}
-- If `part.lang` is an etymology-only language, track both using its code and its full parent's code.
if full_langcode ~= langcode then
require("Module:debug/track")(
template .. "/" .. part_name .. "/" .. (affix_type or "none") .. "/lang/" .. full_langcode
)
end
end
end
end
local function insert_affix_category(categories, pos, affix_type, part, sort_key, sort_base)
-- Don't add a '*fixed with' category if the link term is empty or is in a different language.
if part.term and not part.part_lang then
local cat = pos .. "ที่เติม" .. affix_type .. " " .. strip_diacritics_no_links(part.lang, part.term) ..
(part.id and " (" .. part.id .. ")" or "")
if sort_key or sort_base then
table.insert(categories, {cat = cat, sort_key = sort_key, sort_base = sort_base})
else
table.insert(categories, cat)
end
end
end
--[==[
Implementation of {{tl|circumfix}}.
'''WARNING''': This destructively modifies both `data` and `.prefix`, `.base` and `.suffix`.
]==]
function export.show_circumfix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.prefix, data.lang, data.sc, "อุปสรรค")
make_part_into_affix(data.suffix, data.lang, data.sc, "ปัจจัย")
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.prefix, "อุปสรรค")
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.base, nil)
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.suffix, "ปัจจัย")
-- Create circumfix term.
local circumfix = nil
if data.prefix.term and data.suffix.term then
circumfix = data.prefix.term .. " " .. data.suffix.term
data.prefix.alt = data.prefix.alt or data.prefix.term
data.suffix.alt = data.suffix.alt or data.suffix.term
data.prefix.term = circumfix
data.suffix.term = circumfix
end
-- Make links out of all the parts.
local parts_formatted = {}
local categories = {}
local sort_base
if data.base.term then
sort_base = strip_diacritics_no_links(data.base.lang, data.base.term)
end
table.insert(parts_formatted, export.link_term(data.prefix, data))
table.insert(parts_formatted, export.link_term(data.base, data))
table.insert(parts_formatted, export.link_term(data.suffix, data))
-- Insert the categories, but don't add a '*fixed with' category if the link term is in a different language.
if not data.prefix.part_lang then
table.insert(categories, {cat=data.pos .. "ที่เติมหน่วยคำเติมคร่อม " .. strip_diacritics_no_links(data.prefix.lang,
circumfix), sort_key=data.sort_key, sort_base=sort_base})
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|confix}}.
'''WARNING''': This destructively modifies both `data` and `.prefix`, `.base` and `.suffix`.
]==]
function export.show_confix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.prefix, data.lang, data.sc, "อุปสรรค")
make_part_into_affix(data.suffix, data.lang, data.sc, "ปัจจัย")
track_wrong_affix_type("confix", data.prefix, "อุปสรรค")
track_wrong_affix_type("confix", data.base, nil)
track_wrong_affix_type("confix", data.suffix, "ปัจจัย")
-- Make links out of all the parts.
local parts_formatted = {}
local prefix_sort_base
if data.base and data.base.term then
prefix_sort_base = strip_diacritics_no_links(data.base.lang, data.base.term)
elseif data.suffix.term then
prefix_sort_base = strip_diacritics_no_links(data.suffix.lang, data.suffix.term)
end
-- Insert the categories and parts.
local categories = {}
table.insert(parts_formatted, export.link_term(data.prefix, data))
insert_affix_category(categories, data.pos, "อุปสรรค", data.prefix, data.sort_key, prefix_sort_base)
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
end
table.insert(parts_formatted, export.link_term(data.suffix, data))
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "ปัจจัย", data.suffix)
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|infix}}.
'''WARNING''': This destructively modifies both `data` and `.base` and `.infix`.
]==]
function export.show_infix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.infix, data.lang, data.sc, "อาคม")
track_wrong_affix_type("อาคม", data.base, nil)
track_wrong_affix_type("อาคม", data.infix, "อาคม")
-- Make links out of all the parts.
local parts_formatted = {}
local categories = {}
table.insert(parts_formatted, export.link_term(data.base, data))
table.insert(parts_formatted, export.link_term(data.infix, data))
-- Insert the categories.
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "อาคม", data.infix)
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|prefix}}.
'''WARNING''': This destructively modifies both `data` and the structures within `.prefixes`, as well as `.base`.
]==]
function export.show_prefix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
for i, prefix in ipairs(data.prefixes) do
make_part_into_affix(prefix, data.lang, data.sc, "อุปสรรค")
end
for i, prefix in ipairs(data.prefixes) do
track_wrong_affix_type("อุปสรรค", prefix, "อุปสรรค")
end
track_wrong_affix_type("อุปสรรค", data.base, nil)
-- Make links out of all the parts.
local parts_formatted = {}
local first_sort_base = nil
local categories = {}
if data.prefixes[2] then
first_sort_base = ine(data.prefixes[2].term) or ine(data.prefixes[2].alt)
if first_sort_base then
first_sort_base = strip_diacritics_no_links(data.prefixes[2].lang, first_sort_base)
end
elseif data.base then
first_sort_base = ine(data.base.term) or ine(data.base.alt)
if first_sort_base then
first_sort_base = strip_diacritics_no_links(data.base.lang, first_sort_base)
end
end
for i, prefix in ipairs(data.prefixes) do
table.insert(parts_formatted, export.link_term(prefix, data))
insert_affix_category(categories, data.pos, "อุปสรรค", prefix, data.sort_key, i == 1 and first_sort_base or nil)
end
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
else
table.insert(parts_formatted, "")
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|suffix}}.
'''WARNING''': This destructively modifies both `data` and the structures within `.suffixes`, as well as `.base`.
]==]
function export.show_suffix(data)
local categories = {}
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
for i, suffix in ipairs(data.suffixes) do
make_part_into_affix(suffix, data.lang, data.sc, "ปัจจัย")
end
track_wrong_affix_type("ปัจจัย", data.base, nil)
for i, suffix in ipairs(data.suffixes) do
track_wrong_affix_type("ปัจจัย", suffix, "ปัจจัย")
end
-- Make links out of all the parts.
local parts_formatted = {}
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
else
table.insert(parts_formatted, "")
end
for i, suffix in ipairs(data.suffixes) do
table.insert(parts_formatted, export.link_term(suffix, data))
end
-- Insert the categories.
for i, suffix in ipairs(data.suffixes) do
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "ปัจจัย", suffix)
if suffix.pos and rfind(suffix.pos, "ปิตุวงศ์") then
table.insert(categories, "ชื่อปิตุวงศ์")
end
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
return export
ryfgqerbet39grzk76uwfaeyyr3s3fv
5724467
5724465
2026-06-10T03:48:11Z
OctraBot
3198
5724467
Scribunto
text/plain
local export = {}
local debug_force_cat = false -- if set to true, always display categories even on userspace pages
local m_links = require("Module:links")
local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local en_utilities_module = "Module:en-utilities"
local etymology_module = "Module:etymology"
local pron_qualifier_module = "Module:pron qualifier"
local scripts_module = "Module:scripts"
local utilities_module = "Module:utilities"
-- Export this so the category code in [[Module:category tree/etymology]] can access it.
export.affix_lang_data_module_prefix = "Module:affix/lang-data/"
local rsub = m_str_utils.gsub
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local rfind = m_str_utils.find
local rmatch = m_str_utils.match
local pluralize = require(en_utilities_module).pluralize
local u = m_str_utils.char
local ucfirst = m_str_utils.ucfirst
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
function export.affix_variants(canonical, variants)
local mappings = {}
for _, variant in ipairs(variants) do
mappings[variant] = canonical
end
return mappings
end
function export.id_mapping(default, ids)
local mapping = { default = default }
if ids then
for id, target in pairs(ids) do
mapping[id] = target
end
end
return mapping
end
function export.id_mapping_with_affix_variants(base, id_variants)
local mappings = {}
for id, variants in pairs(id_variants) do
for _, variant in ipairs(variants) do
mappings[variant] = export.id_mapping(base, {[id] = base})
end
end
return mappings
end
function export.merge_tables(...)
local result = {}
for i = 1, select('#', ...) do
local t = select(i, ...)
if t then
for k, v in pairs(t) do
result[k] = v
end
end
end
return result
end
-- Export this so the category code in [[Module:category tree/etymology]] can access it.
export.langs_with_lang_specific_data = {
["az"] = true,
["fi"] = true,
["fr"] = true,
["izh"] = true,
["la"] = true,
["sah"] = true,
["tr"] = true,
["trk-pro"] = true,
}
local default_pos = "ศัพท์"
--[==[ intro:
===About different types of hyphens ("template", "display" and "lookup"):===
* The "template hyphen" is the per-script hyphen character that is used in template calls to indicate that a term is an
affix. This is always a single Unicode char, but there may be multiple possible hyphens for a given script. Normally
this is just the regular hyphen character "-", but for some non-Latin-script languages (currently only right-to-left
languages), it is different.
* The "display hyphen" is the string (which might be an empty string) that is added onto a term as displayed and linked,
to indicate that a term is an affix. Currently this is always either the same as the template hyphen or an empty
string, but the code below is written generally enough to handle arbitrary display hyphens. Specifically:
*# For East Asian languages, the display hyphen is always blank.
*# For Arabic-script languages, either tatweel (ـ) or ZWNJ (zero-width non-joiner) are allowed as template hyphens,
where ZWNJ is supported primarily for Farsi, because some suffixes have non-joining behavior. The display hyphen
corresponding to tatweel is also tatweel, but the display hyphen corresponding to ZWNJ is blank (tatweel is also
the default display hyphen, for calls to {{tl|prefix}}/{{tl|suffix}}/etc. that don't include an explicit hyphen).
* The "lookup hyphen" is the hyphen that is used when looking up language-specific affix mappings. (These mappings are
discussed in more detail below when discussing link affixes.) It depends only on the script of the affix in question.
Most scripts (including East Asian scripts) use a regular hyphen "-" as the lookup hyphen, but Hebrew and Arabic
have their own lookup hyphens (respectively maqqef and tatweel). Note that for Arabic in particular, there are
three possible template hyphens that are recognized (tatweel, ZWNJ and regular hyphen), but mappings must use tatweel.
===About different types of affixes ("template", "display", "link", "lookup" and "category"):===
* A "template affix" is an affix in its source form as it appears in a template call. Generally, a template affix has an
attached template hyphen (see above) to indicate that it is an affix and indicate what type of affix it is (prefix,
suffix, interfix or circumfix), but some of the older-style templates such as {{tl|suffix}}, {{tl|prefix}},
{{tl|confix}}, etc. have "positional" affixes where the presence of the affix in a certain position (e.g. the second
or third parameter) indicates that it is a certain type of affix, whether or not it has an attached template hyphen.
* A "display affix" is the corresponding affix as it is actually displayed to the user. The display affix may differ
from the template affix for various reasons:
*# The display affix may be specified explicitly using the {{para|alt<var>N</var>}} parameter, the `<alt:...>` inline
modifier or a piped link of the form e.g. `<nowiki>[[-kas|-käs]]</nowiki>` (here indicating that the affix should
display as `-käs` but be linked as `-kas`). Here, the template affix is arguably the entire piped link, while the
display affix is `-käs`.
*# Even in the absence of {{para|alt<var>N</var>}} parameters, `<alt:...>` inline modifiers and piped links, certain
languages have differences between the "template hyphen" specified in the template (which always needs to be
specified somehow or other in templates like {{tl|affix}}, to indicate that the term is an affix and what type of
affix it is) and the display hyphen (see above), with corresponding differences between template and display
affixes.
* A (regular) "link affix" is the affix that is linked to when the affix is shown to the user. The link affix is usually
the same as the display affix, but will differ in one of three circumstances:
*# The display and link affixes are explicitly made different using {{para|alt<var>N</var>}} parameters, `<alt:...>`
inline modifiers or piped links, as described above under "display affix".
*# For certain languages, certain affixes are mapped to canonical form using language-specific mappings. For example,
in Finnish, the adjective-forming suffix {{m|fi|-kas}} appears as {{m|fi|-käs}} after front vowels, but logically
both forms are the same suffix and should be linked and categorized the same. Similarly, in Latin, the negative and
intensive prefixes spelled {{m|la|in-}} (etymologically two distinct prefixes) appear variously as {{m|la|il-}},
{{m|la|im-}} or {{m|la|ir-}} before certain consonants. Mappings are supplied in [[Module:affix/lang-data/LANGCODE]]
to convert Finnish {{m|fi|-käs}} to {{m|fi|-kas}} for linking and categorization purposes. Note that the affixes in
the mappings use "lookup hyphens" to indicate the different types of affixes, which is usually the same as the
template hyphen but differs for Arabic scripts, because there are multiple possible template hyphens recognized but
only one lookup hyphen (tatweel). The form of the affix as used to look up in the mapping tables is called the
"lookup affix"; see below.
* A "stripped link affix" is a link affix that has been passed through the language's `stripDiacritics()` function, which
may strip certain diacritics: e.g. macrons in Latin and Old English (indicating length); acute and grave accents in
Russian and various other Slavic languages (indicating stress); vowel diacritics in most Arabic-script languages; and
also tatweel in some Arabic-script languages (currently, for example, Persian, Arabic and Urdu strip tatweel, but
Ottoman Turkish does not). Stripped link affixes are currently what are used in category names.
* A "lookup affix" is the form of the affix as it is looked up in the language-specific lookup mappings described above
under link affixes. There are actually two lookup stages:
*# First, the affix is looked up in a modified display form (specifically, the same as the display affix but using
lookup hyphens). Note that this lookup does not occur if an explicit display form is given using
{{para|alt<var>N</var>}} or an `<alt:...>` inline modifier, or if the template affix contains a piped or embedded
link.
*# If no entry is found, the affix is then looked up in a modified link form (specifically, the modified display
form passed through the language's `stripDiacritics()` function, which strips out certain diacritics, but with the
lookup hyphen re-added if it was stripped out, as in the case of tatweel in many Arabic-script languages).
The reason for this double lookup procedure is to allow for mappings that are sensitive to the extra diacritics, but
also allow for mappings that are not sensitive in this fashion (e.g. Russian {{m|ru|-ливый}} occurs both stressed and
unstressed, but is the same prefix either way).
* A "category affix" is the affix as it appears in categories such as [[:Category:Finnish terms suffixed with -kas|
Category:Finnish terms suffixed with ''-kas'']]. The category affix is currently always the same as the stripped link
affix. This means that for Arabic-script languages, it may or may not have a tatweel, even if the correponding display
affix and regular link affix have a tatweel. As mentioned above, stripDiacritics() strips tatweel for Arabic, Persian
and Urdu, but not for Ottoman Turkish. Hence affix categories for Arabic, Persian and Urdu will be missing the
tatweel, but affix categories for Ottoman Turkish will have it. An additional complication is that if the template
affix contains a ZWNJ, the display (and hence the link and category affixes) will have no hyphen attached in any case.
]==]
-----------------------------------------------------------------------------------------
-- Template and display hyphens --
-----------------------------------------------------------------------------------------
--[=[
Per-script template hyphens. The template hyphen is what appears in the {{affix}}/{{prefix}}/{{suffix}}/etc. template
(in the wikicode). See above.
They key below is a script code, after removing a hyphen and anything preceding. Hence, script codes like 'fa-Arab'
and 'ur-Arab' will match 'Arab'.
The value below is a string consisting of one or more hyphen characters. If there is more than one character, the
default hyphen must come last and a non-default function must be specified for the script in display_hyphens[] so
the correct display hyphen will be specified when no template hyphen is given (in {{suffix}}/{{prefix}}/etc.).
Script detection is normally done when linking, but we need to do it earlier. However, under most circumstances we
don't need to do script detection. Specifically, we only need to do script detection for a given language if
(a) the language has multiple scripts; and
(b) at least one of those scripts is listed below or in display_hyphens.
]=]
local ZWNJ = u(0x200C) -- zero-width non-joiner
local template_hyphens = {
-- This covers all Arabic scripts. See above.
["Arab"] = "ـ" .. ZWNJ .. "-", -- tatweel + zero-width non-joiner + regular hyphen
["Hebr"] = "־", -- Hebrew-specific hyphen termed "maqqef"
["Mong"] = "᠊",
-- FIXME! What about the following right-to-left scripts?
-- Adlm (Adlam)
-- Armi (Imperial Aramaic)
-- Avst (Avestan)
-- Cprt (Cypriot)
-- Khar (Kharoshthi)
-- Mand (Mandaic/Mandaean)
-- Mani (Manichaean)
-- Mend (Mende/Mende Kikakui)
-- Narb (Old North Arabian)
-- Nbat (Nabataean/Nabatean)
-- Nkoo (N'Ko)
-- Orkh (Orkhon runes)
-- Phli (Inscriptional Pahlavi)
-- Phlp (Psalter Pahlavi)
-- Phlv (Book Pahlavi)
-- Phnx (Phoenician)
-- Prti (Inscriptional Parthian)
-- Rohg (Hanifi Rohingya)
-- Samr (Samaritan)
-- Sarb (Old South Arabian)
-- Sogd (Sogdian)
-- Sogo (Old Sogdian)
-- Syrc (Syriac)
-- Thaa (Thaana)
}
-- Hyphens used when looking up an affix in a lang-specific affix mapping. Defaults to regular hyphen (-). The keys
-- are script codes, after removing a hyphen and anything preceding. Hence, script codes like 'fa-Arab' and 'ur-Arab'
-- will match 'Arab'. The value should be a single character.
local lookup_hyphens = {
["Hebr"] = "־",
-- This covers all Arabic scripts. See above.
["Arab"] = "ـ",
}
-- Default display-hyphen function.
local function default_display_hyphen(script, hyph)
if not hyph then
return template_hyphens[script] or "-"
end
return hyph
end
local function arab_get_display_hyphen(script, hyph)
if not hyph then
return "ـ" -- tatweel
elseif hyph == ZWNJ then
return ""
else
return hyph
end
end
local function no_display_hyphen(script, hyph)
return ""
end
-- Per-script function to return the correct display hyphen given the script and template hyphen. The function should
-- also handle the case where the passed-in template hyphen is nil, corresponding to the situation in
-- {{prefix}}/{{suffix}}/etc. where no template hyphen is specified. The key is the script code after removing a hyphen
-- and anything preceding, so 'fa-Arab', 'ur-Arab' etc. will match 'Arab'.
local display_hyphens = {
-- This covers all Arabic scripts. See above.
["Arab"] = arab_get_display_hyphen,
["Bopo"] = no_display_hyphen,
["Hani"] = no_display_hyphen,
["Hans"] = no_display_hyphen,
["Hant"] = no_display_hyphen,
-- The following is a mixture of several scripts. Hopefully the specs here are correct!
["Jpan"] = no_display_hyphen,
["Jurc"] = no_display_hyphen,
["Kitl"] = no_display_hyphen,
["Kits"] = no_display_hyphen,
["Laoo"] = no_display_hyphen,
["Nshu"] = no_display_hyphen,
["Shui"] = no_display_hyphen,
["Tang"] = no_display_hyphen,
["Thaa"] = no_display_hyphen,
["Thai"] = no_display_hyphen,
["Tibt"] = no_display_hyphen,
}
-----------------------------------------------------------------------------------------
-- Basic Utility functions --
-----------------------------------------------------------------------------------------
local function glossary_link(entry, text)
text = text or entry
return "[[ภาคผนวก:อภิธานศัพท์#" .. entry .. "|" .. text .. "]]"
end
local function track(page)
if type(page) == "table" then
for i, pg in ipairs(page) do
page[i] = "affix/" .. pg
end
else
page = "affix/" .. page
end
require("Module:debug/track")(page)
end
local function ine(val)
return val ~= "" and val or nil
end
-----------------------------------------------------------------------------------------
-- Compound types --
-----------------------------------------------------------------------------------------
local function make_compound_type(typ, alttext)
return {
text = "คำประสม" .. glossary_link(typ, alttext),
cat = "คำประสม" .. typ,
}
end
-- Make a compound type entry with a simple rather than glossary link.
-- These should be replaced with a glossary link when the entry in the glossary
-- is created.
local function make_non_glossary_compound_type(typ, alttext)
local link = alttext and "[[" .. typ .. "|" .. alttext .. "]]" or "[[" .. typ .. "]]"
return {
text = "คำประสม" .. link,
cat = "คำประสม" .. typ,
}
end
local function make_raw_compound_type(typ, alttext)
return {
text = glossary_link(typ, alttext),
cat = pluralize(typ),
}
end
local function make_borrowing_type(typ, alttext)
return {
text = glossary_link(typ, alttext),
borrowing_type = pluralize(typ),
}
end
export.etymology_types = {
["adapted borrowing"] = make_borrowing_type("adapted borrowing"),
["adap"] = "adapted borrowing",
["abor"] = "adapted borrowing",
["alliterative"] = make_non_glossary_compound_type("alliterative"),
["allit"] = "alliterative",
["ตรงข้าม"] = make_non_glossary_compound_type("ตรงข้าม"),
["antonymous"] = "ตรงข้าม",
["ant"] = "ตรงข้าม",
["พหุวรีหิ"] = make_compound_type("พหุวรีหิ"),
["bahuvrihi"] = "พหุวรีหิ",
["bahu"] = "พหุวรีหิ",
["bv"] = "พหุวรีหิ",
["coordinative"] = make_compound_type("coordinative"),
["coord"] = "coordinative",
["descriptive"] = make_compound_type("descriptive"),
["desc"] = "descriptive",
["determinative"] = make_compound_type("determinative"),
["det"] = "determinative",
["ทวันทวะ"] = make_compound_type("ทวันทวะ"),
["dvandva"] = "ทวันทวะ",
["dva"] = "ทวันทวะ",
["dvigu"] = make_compound_type("dvigu"),
["dvi"] = "dvigu",
["endocentric"] = make_compound_type("endocentric"),
["endo"] = "endocentric",
["exocentric"] = make_compound_type("exocentric"),
["exo"] = "exocentric",
["izafet I"] = make_compound_type("izafet I"),
["iz1"] = "izafet I",
["izafet II"] = make_compound_type("izafet II"),
["iz2"] = "izafet II",
["izafet III"] = make_compound_type("izafet III"),
["iz3"] = "izafet III",
["กรรมธารยะ"] = make_compound_type("กรรมธารยะ"),
["karmadharaya"] = "กรรมธารยะ",
["karma"] = "กรรมธารยะ",
["kd"] = "กรรมธารยะ",
["kenning"] = make_raw_compound_type("kenning"),
["ken"] = "kenning",
["สัมผัส"] = make_non_glossary_compound_type("สัมผัส"),
["rhyming"] = "สัมผัส",
["rhy"] = "สัมผัส",
["พ้องความ"] = make_non_glossary_compound_type("พ้องความ"),
["synonymous"] = "พ้องความ",
["syn"] = "พ้องความ",
["ตัตปุรุษะ"] = make_compound_type("ตัตปุรุษะ"),
["tatpurusa"] = "ตัตปุรุษะ",
["tat"] = "ตัตปุรุษะ",
["tp"] = "ตัตปุรุษะ",
}
local function process_etymology_type(typ, nocap, notext, has_parts)
local text_sections = {}
local categories = {}
local borrowing_type
if typ then
local typdata = export.etymology_types[typ]
if type(typdata) == "string" then
typdata = export.etymology_types[typdata]
end
if not typdata then
error("Internal error: Unrecognized type '" .. typ .. "'")
end
local text = typdata.text
if not nocap then
text = ucfirst(text)
end
local cat = typdata.cat
borrowing_type = typdata.borrowing_type
local oftext = typdata.oftext or " ของ"
if not notext then
table.insert(text_sections, text)
if has_parts then
table.insert(text_sections, oftext)
table.insert(text_sections, " ")
end
end
if cat then
table.insert(categories, cat)
end
end
return text_sections, categories, borrowing_type
end
-----------------------------------------------------------------------------------------
-- Utility functions --
-----------------------------------------------------------------------------------------
-- Iterate an array up to the greatest integer index found.
local function ipairs_with_gaps(t)
local indices = m_table.numKeys(t)
local max_index = #indices > 0 and math.max(unpack(indices)) or 0
local i = 0
return function()
while i < max_index do
i = i + 1
return i, t[i]
end
end
end
export.ipairs_with_gaps = ipairs_with_gaps
--[==[
Join formatted parts (in `parts_formatted`) together with any overall {{para|lit}} spec (in `lit`) plus categories,
which are formatted by prepending the language name as found in `lang`. The value of an entry in `categories` can be
either a string (which is formatted using `sort_key`) or a table of the form `{ {cat=<var>category</var>,
sort_key=<var>sort_key</var>, sort_base=<var>sort_base</var>}`, specifying the sort key and sort base to use when
formatting the category. If `nocat` is given, no categories are added; otherwise, `force_cat` causes categories to be
added even on userspace pages.
]==]
function export.join_formatted_parts(data)
local cattext
local lang = data.data.lang
local force_cat = data.data.force_cat or debug_force_cat
if data.data.nocat then
cattext = ""
else
for i, cat in ipairs(data.categories) do
if type(cat) == "table" then
--data.categories[i] = require(utilities_module).format_categories(lang:getFullName() .. " " .. cat.cat,
-- lang, cat.sort_key, cat.sort_base, force_cat)
if cat.cat:match("^ศัพท์ที่") then
data.categories[i] = require(utilities_module).format_categories("ศัพท์ภาษา" .. lang:getFullName() .. usub(cat.cat, 6),
lang, cat.sort_key, cat.sort_base, force_cat)
else
data.categories[i] = require(utilities_module).format_categories(cat.cat .. "ภาษา" .. lang:getFullName(),
lang, cat.sort_key, cat.sort_base, force_cat)
end
else
--data.categories[i] = require(utilities_module).format_categories(lang:getFullName() .. " " .. cat, lang,
-- data.data.sort_key, nil, force_cat)
if cat:match("^ศัพท์ที่") then
data.categories[i] = require(utilities_module).format_categories("ศัพท์ภาษา" .. lang:getFullName() .. usub(cat, 6), lang,
data.data.sort_key, nil, force_cat)
else
data.categories[i] = require(utilities_module).format_categories(cat .. "ภาษา" .. lang:getFullName(), lang,
data.data.sort_key, nil, force_cat)
end
end
end
cattext = table.concat(data.categories)
end
local result = table.concat(data.parts_formatted, not data.separator_already_added and " +‎ " or nil) ..
(data.data.lit and ", literally " .. m_links.mark(data.data.lit, "gloss") or "")
local q = data.data.q
local qq = data.data.qq
local l = data.data.l
local ll = data.data.ll
local infl = data.data.infl
if q and q[1] or qq and qq[1] or l and l[1] or ll and ll[1] or infl and infl[1] then
result = require(pron_qualifier_module).format_qualifiers {
lang = lang,
text = result,
q = q,
qq = qq,
l = l,
ll = ll,
infl = infl,
}
end
return result .. cattext
end
local function pluralize(pos)
--[[ ไม่ใช้ในภาษาไทย
if pos ~= "nouns" and usub(pos, -5) ~= "verbs" and usub(pos, -4) ~= "ives" then
if pos:find("[sx]$") then
pos = pos .. "es"
else
pos = pos .. "s"
end
end
--]]
return pos
end
-- Remove links and call lang:stripDiacritics(term).
local function strip_diacritics_no_links(lang, term)
return lang:stripDiacritics(m_links.remove_links(term))
end
--[=[
Convert a raw part as passed into an entry point into a part ready for linking. `lang` and `sc` are the overall
language and script objects. This uses the overall language and script objects as defaults for the part and parses off
any fragment from the term. We need to do the latter so that fragments don't end up in categories and so that we
correctly do affix mapping even in the presence of fragments.
]=]
local function canonicalize_part(part, lang, sc)
if not part then
return
end
-- Save the original (user-specified, part-specific) value of `lang`. If such a value is specified, we don't insert
-- a '*fixed with' category, and we format the part using format_derived() in [[Module:etymology]] rather than
-- full_link() in [[Module:links]].
part.part_lang = part.lang
part.lang = part.lang or lang
part.sc = part.sc or sc
local term = part.term
if not term then
return
elseif not part.fragment then
part.term, part.fragment = m_links.get_fragment(term)
else
part.term = m_links.get_fragment(term)
end
end
--[==[
Construct a single linked part based on the information in `part`, for use by `show_affix()` and other entry points.
This should be called after `canonicalize_part()` is called on the part. This is a thin wrapper around `full_link()` in
[[Module:links]] unless `part.part_lang` is specified (indicating that a part-specific language was given), in which
case `format_derived()` in [[Module:etymology]] is called to display a term in a language other than the language of
the overall term (specified in `data.lang`). `data` contains the entire object passed into the entry point and is used
to access information for constructing the categories added by `format_derived()`.
]==]
function export.link_term(part, data, include_separator)
local result
if part.part_lang then
result = require(etymology_module).format_derived {
lang = data.lang,
terms = {part},
sources = {part.lang},
sort_key = data.sort_key,
nocat = data.nocat,
template_name = "affix",
qualifiers_labels_on_outside = true,
borrowing_type = data.borrowing_type,
force_cat = data.force_cat or debug_force_cat,
}
else
result = m_links.full_link(part, "term", nil, "show qualifiers")
end
if include_separator and part.separator then
return part.separator .. result
else
return result
end
end
local function canonicalize_script_code(scode)
-- Convert fa-Arab, ur-Arab etc. to Arab.
return (scode:gsub("^.*%-", ""))
end
-----------------------------------------------------------------------------------------
-- Affix-handling functions --
-----------------------------------------------------------------------------------------
-- Figure out the appropriate script for the given affix and language (unless the script is explicitly passed in), and
-- return the values of template_hyphens[], display_hyphens[] and lookup_hyphens[] for that script, substituting
-- default values as appropriate. Four values are returned:
-- DETECTED_SCRIPT, TEMPLATE_HYPHEN, DISPLAY_HYPHEN, LOOKUP_HYPHEN
local function detect_script_and_hyphens(text, lang, sc)
local scode
-- 1. If the script is explicitly passed in, use it.
if sc then
scode = sc:getCode()
else
local possible_script_codes = lang:getScriptCodes()
-- YUCK! `possible_script_codes` comes from loadData() so #possible_scripts doesn't work (always returns 0).
local num_possible_script_codes = m_table.length(possible_script_codes)
if num_possible_script_codes == 0 then
-- This shouldn't happen; if the language has no script codes,
-- the list {"None"} should be returned.
error("Something is majorly wrong! Language " .. lang:getCanonicalName() .. " has no script codes.")
end
if num_possible_script_codes == 1 then
-- 2. If the language has only one possible script, use it.
scode = possible_script_codes[1]
else
-- 3. Check if any of the possible scripts for the language have non-default values for template_hyphens[]
-- or display_hyphens[]. If so, we need to do script detection on the text. If not, just use "Latn",
-- which may not be technically correct but produces the right results because Latn has all default
-- values for template_hyphens[] and display_hyphens[].
local may_have_nondefault_hyphen = false
for _, script_code in ipairs(possible_script_codes) do
script_code = canonicalize_script_code(script_code)
if template_hyphens[script_code] or display_hyphens[script_code] then
may_have_nondefault_hyphen = true
break
end
end
if not may_have_nondefault_hyphen then
scode = "Latn"
else
scode = lang:findBestScript(text):getCode()
end
end
end
scode = canonicalize_script_code(scode)
local template_hyphen = template_hyphens[scode] or "-"
local lookup_hyphen = lookup_hyphens[scode] or "-"
local display_hyphen = display_hyphens[scode] or default_display_hyphen
return scode, template_hyphen, display_hyphen, lookup_hyphen
end
--[=[
Given a template affix `term` and an affix type `affix_type`, change the relevant template hyphen(s) in the affix to
the display or lookup hyphen specified in `new_hyphen`, or add them if they are missing. `new_hyphen` can be a string,
specifying a fixed hyphen, or a function of two arguments (the script code `scode` and the discovered template hyphen,
or nil of no relevant template hyphen is present). `thyph_re` is a Lua pattern (which must be enclosed in parens) that
matches the possible template hyphens. Note that not all template hyphens present in the affix are changed, but only
the "relevant" ones (e.g. for a prefix, a relevant template hyphen is one coming at the end of the affix).
]=]
local function reconstruct_term_per_hyphens(term, affix_type, scode, thyph_re, new_hyphen)
local function get_hyphen(hyph)
if type(new_hyphen) == "string" then
return new_hyphen
end
return new_hyphen(scode, hyph)
end
if affix_type == "ไม่ใช่หน่วยคำเติม" then
return term
elseif affix_type == "หน่วยคำเติมคร่อม" then
local before, before_hyphen, after_hyphen, after = rmatch(term, "^(.*)" .. thyph_re .. " " .. thyph_re
.. "(.*)$")
if not before or ulen(term) <= 3 then
-- Unlike with other types of affixes, don't try to add hyphens in the middle of the term to convert it to
-- a circumfix. Also, if the term is just hyphen + space + hyphen, return it.
return term
end
return before .. get_hyphen(before_hyphen) .. " " .. get_hyphen(after_hyphen) .. after
elseif affix_type == "อาคม" or affix_type == "หน่วยคำเติมเชื่อม" then
local before_hyphen, middle, after_hyphen = rmatch(term, "^" .. thyph_re .. "(.*)" .. thyph_re .. "$")
if before_hyphen and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return get_hyphen(before_hyphen) .. (middle or term) .. get_hyphen(after_hyphen)
elseif affix_type == "อุปสรรค" then
local middle, after_hyphen = rmatch(term, "^(.*)" .. thyph_re .. "$")
if middle and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return (middle or term) .. get_hyphen(after_hyphen)
elseif affix_type == "ปัจจัย" then
local before_hyphen, middle = rmatch(term, "^" .. thyph_re .. "(.*)$")
if before_hyphen and ulen(term) <= 1 then
-- If the term is just a hyphen, return it.
return term
end
return get_hyphen(before_hyphen) .. (middle or term)
else
error(("Internal error: Unrecognized affix type '%s'"):format(affix_type))
end
end
--[=[
Look up a mapping from a given affix variant to the canonical form used in categories and links. The lookup tables are
language-specific according to `lang`, and may be ID-specific according to `affix_id`. The affixes as they appear in the
lookup tables (both the variant and the canonical form) are in "lookup affix" format (approximately speaking, they use a
regular hyphen for most scripts, but a tatweel for Arabic-script entries and a maqqef for Hebrew-script entries), but
the passed-in `affix` param is in "template affix" format (which differs from the lookup affix for Arabic-script
entries, because more types of hyphens are allowed in template affixes; see the comments at the top of the file). The
remaining parameters to this function are used to convert from template affixes to lookup affixes; see the
reconstruct_term_per_hyphens() function above.
If the affix contains brackets, no lookup is done. Otherwise, a two-stage process is used, first looking up the affix
directly and then stripping diacritics and looking it up again. The reason for this is documented above in the comments
at the top of the file (specifically, the comments describing lookup affixes).
The value of a mapping can either be a string (do the mapping regardless of affix ID) or a table indexed by affix ID
(where the special value `false` indicates no affix ID). The values of entries in this table can also be strings, or
tables with keys `affix` and `id` (again, use `false` to indicate no ID). This allows an affix mapping to map from one
ID to another (for example, this is used in English to map the [[an-]] prefix with no ID to the [[a-]] prefix with the
ID 'not').
The Given a template affix `term` and an affix type `affix_type`, change the relevant template hyphen(s) in the affix to
the display or lookup hyphen specified in `new_hyphen`, or add them if they are missing. `new_hyphen` can be a string,
specifying a fixed hyphen, or a function of two arguments (the script code `scode` and the discovered template hyphen,
or nil of no relevant template hyphen is present). `thyph_re` is a Lua pattern (which must be enclosed in parens) that
matches the possible template hyphens. Note that not all template hyphens present in the affix are changed, but only
the "relevant" ones (e.g. for a prefix, a relevant template hyphen is one coming at the end of the affix).
]=]
local function lookup_affix_mapping(affix, affix_type, lang, scode, thyph_re, lookup_hyph, affix_id)
local function do_lookup(affix)
-- Ensure that the affix uses lookup hyphens regardless of whether it used a different type of hyphens before
-- or no hyphens.
local lookup_affix = reconstruct_term_per_hyphens(affix, affix_type, scode, thyph_re, lookup_hyph)
local function do_lookup_for_langcode(langcode)
if export.langs_with_lang_specific_data[langcode] then
local langdata = mw.loadData(export.affix_lang_data_module_prefix .. langcode)
if langdata.affix_mappings then
local mapping = langdata.affix_mappings[lookup_affix]
if mapping then
if type(mapping) == "table" then
mapping = mapping[affix_id] or mapping.default or mapping[affix_id or false]
if mapping then
return mapping
end
else
return mapping
end
end
end
end
end
-- If `lang` is an etymology-only language, look for a mapping both for it and its full parent.
local langcode = lang:getCode()
local mapping = do_lookup_for_langcode(langcode)
if mapping then
return mapping
end
local full_langcode = lang:getFullCode()
if full_langcode ~= langcode then
mapping = do_lookup_for_langcode(full_langcode)
if mapping then
return mapping
end
end
return nil
end
if affix:find("%[%[") then
return nil
end
return do_lookup(affix) or do_lookup(lang:stripDiacritics(affix)) or nil
end
--[==[
For a given template term in a given language (see the definition of "template affix" near the top of the file),
possibly in an explicitly specified script `sc` (but usually nil), return the term's affix type ({"prefix"},
{"interfix"}, {"suffix"}, {"circumfix"} or {"non-affix"}) along with the corresponding link and display affixes
(see definitions near the top of the file); also the corresponding lookup affix (if `return_lookup_affix` is specified).
The term passed in should already have any fragment (after the # sign) parsed off of it. Four values are returned:
`affix_type`, `link_term`, `display_term` and `lookup_term`. The affix type can be passed in instead of autodetected; in
this case, the template term need not have any attached hyphens, and the appropriate hyphens will be added in the
appropriate places. If `do_affix_mapping` is specified, look up the affix in the lang-specific affix mappings, as
described in the comment at the top of the file; otherwise, the link and display terms will always be the same. (They
will be the same in any case if the template term has a bracketed link in it or is not an affix.) If
`return_lookup_affix` is given, the fourth return value contains the term with appropriate lookup hyphens in the
appropriate places; otherwise, it is the same as the display term. (This functionality is used in
[[Module:category tree/affixes and compounds]] to convert link affixes into lookup affixes so that they can be looked up
in the affix mapping tables.)
]==]
local function parse_term_for_affixes(term, lang, sc, affix_type, do_affix_mapping, return_lookup_affix, affix_id)
if not term then
return "ไม่ใช่หน่วยคำเติม", nil, nil, nil
end
if term == "^" then
-- Indicates a null term to emulate the behavior of {{suffix|foo||bar}}.
term = ""
return "ไม่ใช่หน่วยคำเติม", term, term, term
end
if term:find("^%^") then
-- HACK! ^ at the beginning of Korean languages has a special meaning, triggering capitalization of the
-- transliteration. Don't interpret it as "force non-affix" for those languages.
local langcode = lang:getCode()
if langcode ~= "ko" and langcode ~= "okm" and langcode ~= "jje" then
-- Formerly we allowed ^ to force non-affix type; this is now handled using an inline modifier
-- <naf>, <root>, etc. Throw an error for the moment when the old way is encountered.
error("Use of ^ to force non-affix status is no longer supported; use an inline modifier <naf> or <root> " ..
"after the component")
end
end
-- Remove an asterisk if the morpheme is reconstructed and add it back at the end.
local reconstructed = ""
if term:find("^%*") then
reconstructed = "*"
term = term:gsub("^%*", "")
end
local scode, thyph, dhyph, lhyph = detect_script_and_hyphens(term, lang, sc)
thyph = "([" .. thyph .. "])"
if not affix_type then
if rfind(term, thyph .. " " .. thyph) then
affix_type = "หน่วยคำเติมคร่อม"
else
local has_beginning_hyphen = rfind(term, "^" .. thyph)
local has_ending_hyphen = rfind(term, thyph .. "$")
if has_beginning_hyphen and has_ending_hyphen then
affix_type = "หน่วยคำเติมเชื่อม"
elseif has_ending_hyphen then
affix_type = "อุปสรรค"
elseif has_beginning_hyphen then
affix_type = "ปัจจัย"
else
affix_type = "ไม่ใช่หน่วยคำเติม"
end
end
end
local link_term, display_term, lookup_term
if affix_type == "ไม่ใช่หน่วยคำเติม" then
link_term = term
display_term = term
lookup_term = term
else
display_term = reconstruct_term_per_hyphens(term, affix_type, scode, thyph, dhyph)
if do_affix_mapping then
link_term = lookup_affix_mapping(term, affix_type, lang, scode, thyph, lhyph, affix_id)
-- The return value of lookup_affix_mapping() may be an affix mapping with lookup hyphens if a mapping
-- was found, otherwise nil if a mapping was not found. We need to convert to display hyphens in
-- either case, but in the latter case we can reuse the display term, which has already been converted.
if link_term then
link_term = reconstruct_term_per_hyphens(link_term, affix_type, scode, thyph, dhyph)
else
link_term = display_term
end
else
link_term = display_term
end
if return_lookup_affix then
lookup_term = reconstruct_term_per_hyphens(term, affix_type, scode, thyph, lhyph)
else
lookup_term = display_term
end
end
link_term = reconstructed .. link_term
display_term = reconstructed .. display_term
lookup_term = reconstructed .. lookup_term
return affix_type, link_term, display_term, lookup_term
end
--[==[
Add a hyphen to a term in the appropriate place, based on the specified affix type, stripping off any existing hyphens
in that place. For example, if `affix_type` == {"prefix"}, we'll add a hyphen onto the end if it's not already there (or
is of the wrong type). Three values are returned: the link term, display term and lookup term. This function is a thin
wrapper around `parse_term_for_affixes`; see the comments above that function for more information. Note that this
function is exposed externally because it is called by [[Module:category tree/affixes and compounds]]; see the comment
in `parse_term_for_affixes` for more information.
]==]
function export.make_affix(term, lang, sc, affix_type, do_affix_mapping, return_lookup_affix, affix_id)
if not (affix_type == "อุปสรรค" or affix_type == "ปัจจัย" or affix_type == "หน่วยคำเติมคร่อม" or affix_type == "อาคม" or
affix_type == "หน่วยคำเติมเชื่อม" or affix_type == "ไม่ใช่หน่วยคำเติม") then
error("Internal error: Invalid affix type " .. (affix_type or "(nil)"))
end
local _, link_term, display_term, lookup_term = parse_term_for_affixes(term, lang, sc, affix_type,
do_affix_mapping, return_lookup_affix, affix_id)
return link_term, display_term, lookup_term
end
-----------------------------------------------------------------------------------------
-- Main entry points --
-----------------------------------------------------------------------------------------
--[==[
Core categorization logic for affixes. This is shared between show_affix(), show_compound_like() and
get_affix_categories_only(). Returns the categories array and other metadata needed for formatting.
]==]
local function generate_affix_categories(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
local text_sections, categories, borrowing_type =
process_etymology_type(data.type, data.surface_analysis or data.nocap, data.notext, #data.parts > 0)
data.borrowing_type = borrowing_type
-- Process each part
local whole_words = 0
local is_affix_or_compound = false
-- Canonicalize and generate links for all the parts first; then do categorization in a separate step, because when
-- processing the first part for categorization, we may access the second part and need it already canonicalized.
for i, part in ipairs_with_gaps(data.parts) do
part = part or {}
data.parts[i] = part
canonicalize_part(part, data.lang, data.sc)
-- Determine affix type and get link and display terms (see text at top of file). Store them in the part
-- (in fields that won't clash with fields used by full_link() in [[Module:links]] or link_term()), so they
-- can be used in the loop below when categorizing.
part.affix_type, part.affix_link_term, part.affix_display_term = parse_term_for_affixes(part.term,
part.lang, part.sc, part.type, not part.alt, nil, part.id)
-- If link_term is an empty string, either a bare ^ was specified or an empty term was used along with inline
-- modifiers. The intention in either case is not to link the term.
part.term = ine(part.affix_link_term)
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
part.alt = part.alt or (part.affix_display_term ~= part.affix_link_term and part.affix_display_term) or nil
end
if not data.noaffixcat then
-- Now do categorization.
for i, part in ipairs_with_gaps(data.parts) do
local affix_type = part.affix_type
if affix_type ~= "ไม่ใช่หน่วยคำเติม" then
is_affix_or_compound = true
-- Make a sort key. For the first part, use the second part as the sort key; the intention is that if the
-- term has a prefix, sorting by the prefix won't be very useful so we sort by what follows, which is
-- presumably the root.
local part_sort_base = nil
local part_sort = part.sort or data.sort_key
if i == 1 and data.parts[2] and data.parts[2].term then
local part2 = data.parts[2]
-- If the second-part link term is empty, the user requested an unlinked term; avoid a wikitext error
-- by using the alt value if available.
part_sort_base = ine(part2.affix_link_term) or ine(part2.alt)
if part_sort_base then
part_sort_base = strip_diacritics_no_links(part2.lang, part_sort_base)
end
end
if part.pos and rfind(part.pos, "ปิตุวงศ์") then
table.insert(categories, {cat = "ชื่อปิตุวงศ์", sort_key = part_sort, sort_base = part_sort_base})
end
if data.pos ~= "terms" and part.pos and rfind(part.pos, "บอกความเล็ก") then
table.insert(categories, {cat = data.pos .. "บอกความเล็ก", sort_key = part_sort,
sort_base = part_sort_base})
end
-- Don't add a '*fixed with' category if the link term is empty or is in a different language.
if ine(part.affix_link_term) and not part.part_lang then
table.insert(categories, {cat = data.pos .. "ที่เติม" .. affix_type .. " " ..
strip_diacritics_no_links(part.lang, part.affix_link_term) ..
(part.id and " (" .. part.id .. ")" or ""),
sort_key = part_sort, sort_base = part_sort_base})
end
else
whole_words = whole_words + 1
if whole_words == 2 then
is_affix_or_compound = true
--table.insert(categories, "compound " .. data.pos)
if data.pos == "ศัพท์" then --th
table.insert(categories, "คำประสม")
else
table.insert(categories, data.pos .. "ประสม")
end
end
end
end
-- Make sure there was either an affix or a compound (two or more non-affix terms).
if not is_affix_or_compound and not data.allow_no_affixes_or_compounds then
error("The parameters did not include any affixes, and the term is not a compound. Please provide at least one affix.")
end
end
return text_sections, categories, borrowing_type
end
--[==[
Implementation of {{tl|affix}} and {{tl|surface analysis}}. `data` contains all the information describing the affixes to
be displayed, and contains the following:
* `.lang` ('''required'''): Overall language object. Different from term-specific language objects (see `.parts` below).
* `.sc`: Overall script object (usually omitted). Different from term-specific script objects.
* `.parts` ('''required'''): List of objects describing the affixes to show. The general format of each object is as would
be passed to `full_link()`, except that the `.lang` field should be missing unless the term is of a language
different from the overall `.lang` value (in such a case, the language name is shown along with the term and
an additional "derived from" category is added). '''WARNING''': The data in `.parts` will be destructively
modified.
* `.pos`: Overall part of speech (used in categories, defaults to {"terms"}). Different from term-specific part of speech.
* `.sort_key`: Overall sort key. Normally omitted except e.g. in Japanese.
* `.type`: Type of compound, if the parts in `.parts` describe a compound. Strictly optional, and if supplied, the
compound type is displayed before the parts (normally capitalized, unless `.nocap` is given).
* `.nocap`: Don't capitalize the first letter of text displayed before the parts (relevant only if `.type` or
`.surface_analysis` is given).
* `.notext`: Don't display any text before the parts (relevant only if `.type` or `.surface_analysis` is given).
* `.nocat`: Disable all categorization.
* `.noaffixcat`: Disable affix (and compound) categorization. Relevant for e.g. blends, which may otherwise
be incorrectly categorized as compound terms.
* `.lit`: Overall literal definition. Different from term-specific literal definitions.
* `.force_cat`: Always display categories, even on userspace pages.
* `.surface_analysis`: Implement {{surface analysis}}; adds `By surface analysis, ` before the parts.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_affix(data)
local text_sections, categories, borrowing_type = generate_affix_categories(data)
-- Process each part for display
local parts_formatted = {}
for i, part in ipairs_with_gaps(data.parts) do
-- Make a link for the part
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if data.surface_analysis then
--local text = "by " .. glossary_link("surface analysis") .. ", "
local text = "พิจารณาคร่าว ๆ เทียบเท่า "
if not data.nocap then
text = ucfirst(text)
end
table.insert(text_sections, 1, text)
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Get only the categories that would be generated by show_affix(), without any text output or formatting.
This is used by Module:etymon to get affix categorization.
Returns an array of category objects, where
each entry is either a string (simple category name) or a table with keys `cat`, `sort_key`,
and `sort_base` for more complex categorization.
`data` should have the same structure as passed to show_affix():
* `.lang` (required): Overall language object
* `.parts` (required): Array of affix part objects with `.term`, `.lang`, `.id`, etc.
* `.pos`: Part of speech (defaults to "terms")
* `.sort_key`: Overall sort key for categories
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.get_affix_categories_only(data)
local text_sections, categories, borrowing_type = generate_affix_categories(data)
return categories
end
function export.show_surface_analysis(data)
data.surface_analysis = true
data.allow_no_affixes_or_compounds = true
return export.show_affix(data)
end
--[==[
Implementation of {{tl|compound}}.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_compound(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
local text_sections, categories, borrowing_type =
process_etymology_type(data.type, data.nocap, data.notext, #data.parts > 0)
data.borrowing_type = borrowing_type
local parts_formatted = {}
--table.insert(categories, "compound " .. data.pos)
if data.pos == "ศัพท์" then --th
table.insert(categories, "คำประสม")
else
table.insert(categories, data.pos .. "ประสม")
end
-- Make links out of all the parts
local whole_words = 0
for i, part in ipairs(data.parts) do
canonicalize_part(part, data.lang, data.sc)
-- Determine affix type and get link and display terms (see text at top of file).
local affix_type, link_term, display_term = parse_term_for_affixes(part.term, part.lang, part.sc,
part.type, not part.alt, nil, part.id)
-- If the term is an interfix or the type was explicitly given, recognize it as such (which means e.g. that we
-- will display the term without hyphens for East Asian languages). Otherwise, ignore the fact that it looks
-- like an affix and display as specified in the template (but pay attention to the detected affix type for
-- certain tracking purposes).
if affix_type == "หน่วยคำเติมเชื่อม" or (part.type and part.type ~= "ไม่ใช่หน่วยคำเติม") then
-- If link_term is an empty string, either a bare ^ was specified or an empty term was used along with
-- inline modifiers. The intention in either case is not to link the term. Don't add a '*fixed with'
-- category in this case, or if the term is in a different language.
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
if link_term and link_term ~= "" and not part.part_lang then
table.insert(categories, {cat = data.pos .. "ที่เติม" .. affix_type .. " " ..
strip_diacritics_no_links(part.lang, link_term), sort_key = part.sort or data.sort_key})
end
part.term = link_term ~= "" and link_term or nil
part.alt = part.alt or (display_term ~= link_term and display_term) or nil
else
if affix_type ~= "ไม่ใช่หน่วยคำเติม" then
local langcode = data.lang:getCode()
-- If `data.lang` is an etymology-only language, track both using its code and its full parent's code.
track { affix_type, affix_type .. "/lang/" .. langcode }
local full_langcode = data.lang:getFullCode()
if langcode ~= full_langcode then
track(affix_type .. "/lang/" .. full_langcode)
end
else
whole_words = whole_words + 1
end
end
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if whole_words == 1 then
track("one whole word")
elseif whole_words == 0 then
track("looks like confix")
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Implementation of {{tl|blend}}, {{tl|univerbation}} and similar "compound-like" templates.
'''WARNING''': This destructively modifies both `data` and the individual structures within `.parts`.
]==]
function export.show_compound_like(data)
data.allow_no_affixes_or_compounds = true
local text_sections, categories, borrowing_type = generate_affix_categories(data)
if data.cat then
table.insert(categories, data.cat)
end
-- Process each part for display
local parts_formatted = {}
for i, part in ipairs_with_gaps(data.parts) do
-- Make a link for the part
table.insert(parts_formatted, export.link_term(part, data, "include_separator"))
end
if #data.parts > 0 and data.oftext then
table.insert(text_sections, 1, " " .. data.oftext .. " ")
end
if data.text then
table.insert(text_sections, 1, data.text)
end
table.insert(text_sections, export.join_formatted_parts { data = data, parts_formatted = parts_formatted,
categories = categories, separator_already_added = true })
return table.concat(text_sections)
end
--[==[
Make `part` (a structure holding information on an affix part) into an affix of type `affix_type`, and apply any
relevant affix mappings. For example, if the desired affix type is "suffix", this will (in general) add a hyphen onto
the beginning of the term, alt, tr and ts components of the part if not already present. The hyphen that's added is the
"display hyphen" (see above) and may be script-specific. (In the case of East Asian scripts, the display hyphen is an
empty string whereas the template hyphen is the regular hyphen, meaning that any regular hyphen at the beginning of the
part will be effectively removed.) `lang` and `sc` hold overall language and script objects.
Note that this also applies any language-specific affix mappings, so that e.g. if the language is Finnish and the user
specified [[-käs]] in the affix and didn't specify an `.alt` value, `part.term` will contain [[-kas]] and `part.alt` will
contain [[-käs]].
This function is used by the "legacy" templates ({{tl|prefix}}, {{tl|suffix}}, {{tl|confix}}, etc.) where the nature of
the affix is specified by the template itself rather than auto-determined from the affix, as is the case with
{{tl|affix}}.
'''WARNING''': This destructively modifies `part`.
]==]
local function make_part_into_affix(part, lang, sc, affix_type)
canonicalize_part(part, lang, sc)
local link_term, display_term = export.make_affix(part.term, part.lang, part.sc, affix_type, not part.alt, nil, part.id)
part.term = link_term
-- When we don't specify `do_affix_mapping` to make_affix(), link and display terms (first and second retvals of
-- make_affix()) are the same.
-- If part.alt would be the same as part.term, make it nil, so that it isn't erroneously tracked as being
-- redundant alt text.
part.alt = part.alt and export.make_affix(part.alt, part.lang, part.sc, affix_type) or (display_term ~= link_term and display_term) or nil
local Latn = require(scripts_module).getByCode("Latn")
part.tr = export.make_affix(part.tr, part.lang, Latn, affix_type)
part.ts = export.make_affix(part.ts, part.lang, Latn, affix_type)
end
local function track_wrong_affix_type(template, part, expected_affix_type)
if part and not part.type then
local affix_type = parse_term_for_affixes(part.term, part.lang, part.sc)
if affix_type ~= expected_affix_type then
local part_name = expected_affix_type or "base"
local langcode = part.lang:getCode()
local full_langcode = part.lang:getFullCode()
require("Module:debug/track") {
template,
template .. "/" .. part_name,
template .. "/" .. part_name .. "/" .. (affix_type or "none"),
template .. "/" .. part_name .. "/" .. (affix_type or "none") .. "/lang/" .. langcode
}
-- If `part.lang` is an etymology-only language, track both using its code and its full parent's code.
if full_langcode ~= langcode then
require("Module:debug/track")(
template .. "/" .. part_name .. "/" .. (affix_type or "none") .. "/lang/" .. full_langcode
)
end
end
end
end
local function insert_affix_category(categories, pos, affix_type, part, sort_key, sort_base)
-- Don't add a '*fixed with' category if the link term is empty or is in a different language.
if part.term and not part.part_lang then
local cat = pos .. "ที่เติม" .. affix_type .. " " .. strip_diacritics_no_links(part.lang, part.term) ..
(part.id and " (" .. part.id .. ")" or "")
if sort_key or sort_base then
table.insert(categories, {cat = cat, sort_key = sort_key, sort_base = sort_base})
else
table.insert(categories, cat)
end
end
end
--[==[
Implementation of {{tl|circumfix}}.
'''WARNING''': This destructively modifies both `data` and `.prefix`, `.base` and `.suffix`.
]==]
function export.show_circumfix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.prefix, data.lang, data.sc, "อุปสรรค")
make_part_into_affix(data.suffix, data.lang, data.sc, "ปัจจัย")
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.prefix, "อุปสรรค")
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.base, nil)
track_wrong_affix_type("หน่วยคำเติมคร่อม", data.suffix, "ปัจจัย")
-- Create circumfix term.
local circumfix = nil
if data.prefix.term and data.suffix.term then
circumfix = data.prefix.term .. " " .. data.suffix.term
data.prefix.alt = data.prefix.alt or data.prefix.term
data.suffix.alt = data.suffix.alt or data.suffix.term
data.prefix.term = circumfix
data.suffix.term = circumfix
end
-- Make links out of all the parts.
local parts_formatted = {}
local categories = {}
local sort_base
if data.base.term then
sort_base = strip_diacritics_no_links(data.base.lang, data.base.term)
end
table.insert(parts_formatted, export.link_term(data.prefix, data))
table.insert(parts_formatted, export.link_term(data.base, data))
table.insert(parts_formatted, export.link_term(data.suffix, data))
-- Insert the categories, but don't add a '*fixed with' category if the link term is in a different language.
if not data.prefix.part_lang then
table.insert(categories, {cat=data.pos .. "ที่เติมหน่วยคำเติมคร่อม " .. strip_diacritics_no_links(data.prefix.lang,
circumfix), sort_key=data.sort_key, sort_base=sort_base})
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|confix}}.
'''WARNING''': This destructively modifies both `data` and `.prefix`, `.base` and `.suffix`.
]==]
function export.show_confix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.prefix, data.lang, data.sc, "อุปสรรค")
make_part_into_affix(data.suffix, data.lang, data.sc, "ปัจจัย")
track_wrong_affix_type("confix", data.prefix, "อุปสรรค")
track_wrong_affix_type("confix", data.base, nil)
track_wrong_affix_type("confix", data.suffix, "ปัจจัย")
-- Make links out of all the parts.
local parts_formatted = {}
local prefix_sort_base
if data.base and data.base.term then
prefix_sort_base = strip_diacritics_no_links(data.base.lang, data.base.term)
elseif data.suffix.term then
prefix_sort_base = strip_diacritics_no_links(data.suffix.lang, data.suffix.term)
end
-- Insert the categories and parts.
local categories = {}
table.insert(parts_formatted, export.link_term(data.prefix, data))
insert_affix_category(categories, data.pos, "อุปสรรค", data.prefix, data.sort_key, prefix_sort_base)
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
end
table.insert(parts_formatted, export.link_term(data.suffix, data))
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "ปัจจัย", data.suffix)
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|infix}}.
'''WARNING''': This destructively modifies both `data` and `.base` and `.infix`.
]==]
function export.show_infix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
make_part_into_affix(data.infix, data.lang, data.sc, "อาคม")
track_wrong_affix_type("อาคม", data.base, nil)
track_wrong_affix_type("อาคม", data.infix, "อาคม")
-- Make links out of all the parts.
local parts_formatted = {}
local categories = {}
table.insert(parts_formatted, export.link_term(data.base, data))
table.insert(parts_formatted, export.link_term(data.infix, data))
-- Insert the categories.
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "อาคม", data.infix)
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|prefix}}.
'''WARNING''': This destructively modifies both `data` and the structures within `.prefixes`, as well as `.base`.
]==]
function export.show_prefix(data)
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
for i, prefix in ipairs(data.prefixes) do
make_part_into_affix(prefix, data.lang, data.sc, "อุปสรรค")
end
for i, prefix in ipairs(data.prefixes) do
track_wrong_affix_type("อุปสรรค", prefix, "อุปสรรค")
end
track_wrong_affix_type("อุปสรรค", data.base, nil)
-- Make links out of all the parts.
local parts_formatted = {}
local first_sort_base = nil
local categories = {}
if data.prefixes[2] then
first_sort_base = ine(data.prefixes[2].term) or ine(data.prefixes[2].alt)
if first_sort_base then
first_sort_base = strip_diacritics_no_links(data.prefixes[2].lang, first_sort_base)
end
elseif data.base then
first_sort_base = ine(data.base.term) or ine(data.base.alt)
if first_sort_base then
first_sort_base = strip_diacritics_no_links(data.base.lang, first_sort_base)
end
end
for i, prefix in ipairs(data.prefixes) do
table.insert(parts_formatted, export.link_term(prefix, data))
insert_affix_category(categories, data.pos, "อุปสรรค", prefix, data.sort_key, i == 1 and first_sort_base or nil)
end
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
else
table.insert(parts_formatted, "")
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
--[==[
Implementation of {{tl|suffix}}.
'''WARNING''': This destructively modifies both `data` and the structures within `.suffixes`, as well as `.base`.
]==]
function export.show_suffix(data)
local categories = {}
data.pos = data.pos or default_pos
data.pos = pluralize(data.pos)
canonicalize_part(data.base, data.lang, data.sc)
-- Hyphenate the affixes and apply any affix mappings.
for i, suffix in ipairs(data.suffixes) do
make_part_into_affix(suffix, data.lang, data.sc, "ปัจจัย")
end
track_wrong_affix_type("ปัจจัย", data.base, nil)
for i, suffix in ipairs(data.suffixes) do
track_wrong_affix_type("ปัจจัย", suffix, "ปัจจัย")
end
-- Make links out of all the parts.
local parts_formatted = {}
if data.base then
table.insert(parts_formatted, export.link_term(data.base, data))
else
table.insert(parts_formatted, "")
end
for i, suffix in ipairs(data.suffixes) do
table.insert(parts_formatted, export.link_term(suffix, data))
end
-- Insert the categories.
for i, suffix in ipairs(data.suffixes) do
-- FIXME, should we be specifying a sort base here?
insert_affix_category(categories, data.pos, "ปัจจัย", suffix)
if suffix.pos and rfind(suffix.pos, "ปิตุวงศ์") then
table.insert(categories, "ชื่อปิตุวงศ์")
end
end
return export.join_formatted_parts { data = data, parts_formatted = parts_formatted, categories = categories }
end
return export
h32biur7cc70qzaojoxhta6icu9uie2
มอดูล:affix/templates
828
135996
5724464
5684448
2026-06-10T03:27:44Z
OctraBot
3198
5724464
Scribunto
text/plain
local export = {}
local m_affix = require("Module:affix")
local m_utilities = require("Module:utilities")
local en_utilities_module = "Module:en-utilities"
local parameter_utilities_module = "Module:parameter utilities"
local pseudo_loan_module = "Module:affix/pseudo-loan"
local insert = table.insert
local boolean_param = {type = "boolean"}
local function is_property_key(k)
return require(parameter_utilities_module).item_key_is_property(k)
end
local recognized_affix_types = {
prefix = "prefix",
pre = "prefix",
suffix = "suffix",
suf = "suffix",
interfix = "interfix",
inter = "interfix",
infix = "infix",
["in"] = "infix",
circumfix = "circumfix",
circum = "circumfix",
["non-affix"] = "non-affix",
naf = "non-affix",
root = "non-affix",
}
local function pre_normalize_affix_type(data)
local modtext = data.modtext
modtext = modtext:match("^<(.*)>$")
if not modtext then
error(("Internal error: Passed-in modifier isn't surrounded by angle brackets: %s"):format(data.modtext))
end
if recognized_affix_types[modtext] then
modtext = "type:" .. modtext
end
return "<" .. modtext .. ">"
end
-- Parse raw arguments. A single parameter `data` is passed in, with the following fields:
-- * `raw_args`: The raw arguments to parse, normally taken from `frame:getParent().args`.
-- * `extra_params`: An optional function of one argument that is called on the `params` structure before parsing; its
-- purpose is to specify additional allowed parameters or possibly disable parameters.
-- * `has_source`: There is a source-language parameter following 1= (which becomes the "destination" language
-- parameter) and preceding the terms. This is currently used for {{pseudo-loan}}.
-- * `ilang`: If given, it is a language object that serves as the default for the language. If specified, there is no
-- language code specified in 1=; instead the term parameters start directly at 1= (or at 2= if `has_source` is
-- given).
-- * `require_index_for_pos`: There is no separate |pos= parameter distinct from |pos1=, |pos2=, etc. Instead,
-- specifying |pos= results in an error.
-- * `dont_require_index`: Allow |foo= to be specified as a synonym for |foo1= (except for |lit=, which remains
-- distinct).
-- * `allow_type`: Allow |type1=, |type2=, etc. or inline <type:...> for the affix type, and allow a separate |type=
-- parameter for the etymology type (FIXME: this may be confusing; consider changing the etymology type to |etype=).
-- * `allow_semicolon_separator`: Allow semicolon as a separator, displaying as " or ". This requires changes in the
-- display of the output, to not always put a + between the items.
--
-- Note that all language parameters are allowed to be etymology-only languages.
--
-- Return five values ARGS, ITEMS, LANG_OBJ, SCRIPT_OBJ, SOURCE_LANG_OBJ where ARGS is a table of the parsed arguments;
-- ITEMS is the list of parsed items; LANG_OBJ is the language object corresponding to the language code specified in 1=
-- (or taken from `ilang` if given); SCRIPT_OBJ is the script object corresponding to sc= (if given, otherwise nil); and
-- SOURCE_LANG_OBJ is the language object corresponding to the source-language code specified in 2= (or 1= if `ilang` is
-- given) if `has_source` is specified (otherwise nil).
local function parse_args(data)
local raw_args = data.raw_args
local has_source = data.has_source
local ilang = data.ilang
if raw_args.lang then
error("The |lang= parameter is not used by this template. Place the language code in parameter 1 instead.")
end
local term_index = (ilang and 1 or 2) + (has_source and 1 or 0)
local params = {
[term_index] = {list = true, allow_holes = true},
["sort"] = {},
["nocap"] = boolean_param, -- always allow this even if not used, for use with {{surf}}, which adds it
}
if not ilang then
params[1] = {required = true, type = "language", default = "und"}
end
local source_index
if has_source then
source_index = term_index - 1
params[source_index] = {required = true, type = "language", default = "und"}
end
local m_param_utils = require(parameter_utilities_module)
local param_mod_source = {}
if not data.dont_require_index then
insert(param_mod_source,
-- We want to require an index for all params (or use separate_no_index, which also requires an index for the
-- param corresponding to the first item).
{default = true, require_index = true}
)
end
insert(param_mod_source, {group = {"link", "ref", "lang", "q", "l", "infl"}})
-- Override lit= to be separate from lit1=.
insert(param_mod_source, {param = "lit", separate_no_index = true})
if not data.dont_require_index and not data.require_index_for_pos then
-- Override pos= to be separate from pos1=.
insert(param_mod_source, {param = "pos", separate_no_index = true})
end
if data.allow_type then
insert(param_mod_source, {param = "type", separate_no_index = true})
end
local param_mods = m_param_utils.construct_param_mods(param_mod_source)
if data.extra_params then
data.extra_params(params)
end
local items, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
params = params,
param_mods = param_mods,
raw_args = raw_args,
termarg = term_index,
parse_lang_prefix = true,
track_module = "homophones",
-- the inclusion of ‎ is what [[Module:affix]] has always done
default_separator = data.allow_semicolon_separator and " +‎ " or nil,
special_separators = data.allow_semicolon_separator and {[";"] = " or "} or nil,
disallow_custom_separators = not data.allow_semicolon_separator,
-- For compatibility, we need to not skip completely unspecified items. It is common, for example, to do
-- {{suffix|lang||foo}} to generate "+ -foo".
dont_skip_items = true,
-- Allow e.g. <infix> to be specified in place of <type:infix>.
pre_normalize_modifiers = pre_normalize_affix_type,
-- Don't pass in `lang` or `sc`, as they will be used as defaults to initialize the items, which we don't want
-- (particularly for `lang`), as the code in [[Module:affix]] uses the presence of `lang` as an indicator that
-- a part-specific language was explicitly given.
}
local lang = ilang or args[1]
local source
if has_source then
source = args[source_index]
end
-- For compatibility with the prior code, we need to convert items without term or properties to nil.
for i = 1, #items do
local item = items[i]
local saw_item_property = item.term
if not saw_item_property then
for k, v in pairs(item) do
if is_property_key(k) then
saw_item_property = true
break
end
end
end
if not saw_item_property then
items[i] = nil
elseif item.type then
-- Validate and canonicalize affix types.
if not recognized_affix_types[item.type] then
local valid_types = {}
for k in pairs(recognized_affix_types) do
insert(valid_types, ("'%s'"):format(k))
end
table.sort(recognized_affix_types)
error(("Unrecognized affix type '%s' in item %s; valid values are %s"):format(
item.type, item.itemno, table.concat(valid_types, ", ")))
else
item.type = recognized_affix_types[item.type]
end
end
end
if args.type and args.type.default and not m_affix.etymology_types[args.type.default] then
error("Unrecognized etymology type: '" .. args.type.default .. "'")
end
return args, items, lang, args.sc.default, source
end
local function augment_affix_data(data, args, lang, sc)
data.lang = lang
data.sc = sc
data.pos = args.pos and args.pos.default
data.lit = args.lit and args.lit.default
data.sort_key = args.sort
data.type = args.type and args.type.default
data.nocap = args.nocap
data.notext = args.notext
data.nocat = args.nocat
data.force_cat = args.force_cat
data.l = args.l.default
data.ll = args.ll.default
data.q = args.q.default
data.qq = args.qq.default
data.infl = args.infl.default
return data
end
function export.affix(frame)
local function extra_params(params)
params.notext = boolean_param
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
allow_type = true,
allow_semicolon_separator = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) and not args.type.default then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
parts = { {term = "prefix-"}, {term = "base"}, {term = "-suffix"} }
else
error("You must provide at least one part.")
end
end
return m_affix.show_affix(augment_affix_data({ parts = parts }, args, lang, sc))
end
function export.compound(frame)
local function extra_params(params)
params.notext = boolean_param
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
allow_type = true,
allow_semicolon_separator = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) and not args.type.default then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
parts = { {term = "first"}, {separator = " +‎ ", term = "second"} }
else
error("You must provide at least one part of a compound.")
end
end
return m_affix.show_compound(augment_affix_data({ parts = parts }, args, lang, sc))
end
-- FIXME: Temporary for check in compound_like() below for old-style {{contraction}} parameters. Remove eventually.
local function ine(arg)
if arg == "" then
return nil
else
return arg
end
end
function export.compound_like(frame)
local iparams = {
["lang"] = {type = "language"},
["template"] = {},
["text"] = {},
["oftext"] = {},
["cat"] = {},
["noaffixcat"] = boolean_param,
["dont_require_index"] = boolean_param,
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local parent_args = frame:getParent().args
-- Error to catch most uses of old-style parameters for {{contraction}}. (FIXME: Remove eventually.)
local term_param = iargs.lang and 1 or 2
if ine(parent_args[term_param + 2]) and not ine(parent_args[term_param + 1]) and not ine(parent_args.tr2) and not ine(parent_args.ts2)
and not ine(parent_args.t2) and not ine(parent_args.gloss2) and not ine(parent_args.g2)
and not ine(parent_args.alt2) then
error(("You specified a term in %s= and not one in %s=. You probably meant to use t= to specify a gloss instead. "
.. "If you intended to specify two terms, put the second term in %s=."):format(term_param + 2, term_param + 1,
term_param + 1))
end
if not ine(parent_args[term_param + 1]) and not ine(parent_args.alt2) and not ine(parent_args.tr2) and not ine(parent_args.ts2)
and ine(parent_args.g2) then
error(("You specified a gender in g2= but no term in %s=. You were probably trying to specify two genders for "
.. "a single term. To do that, put both genders in g=, comma-separated."):format(term_param + 1))
end
local function extra_params(params)
params.notext = boolean_param
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = parent_args,
extra_params = extra_params,
ilang = iargs.lang,
dont_require_index = iargs.dont_require_index,
-- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall
-- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this
-- necessary?
require_index_for_pos = not iargs.dont_require_index,
allow_semicolon_separator = true,
}
local template = iargs.template
local nocat = args.nocat
local notext = args.notext
local text = not notext and iargs.text
local oftext = not notext and (iargs.oftext or text and "ของ")
local cat = not nocat and iargs.cat
local noaffixcat = nocat or iargs.noaffixcat
if not next(parts) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
parts = { {term = "first"}, {separator = " +‎ ", term = "second"} }
end
end
return m_affix.show_compound_like(augment_affix_data({ parts = parts, text = text, oftext = oftext, cat = cat, noaffixcat = noaffixcat },
args, lang, sc))
end
function export.surface_analysis(frame)
local function ine(arg)
-- Since we're operating before calling [[Module:parameters]], we need to imitate how that module processes
-- arguments, including trimming since numbered arguments don't have automatic whitespace trimming.
if not arg then
return arg
end
arg = mw.text.trim(arg)
if arg == "" then
arg = nil
end
return arg
end
local parent_args = frame:getParent().args
local etymtext
local arg1 = ine(parent_args[1])
if not arg1 then
-- Allow omitted first argument to just display "By surface analysis".
etymtext = ""
elseif arg1:find("^%+") then
-- If the first argument (normally a language code) is prefixed with a +, it's a template name.
local template_name = arg1:sub(2)
local new_args = {}
for i, v in pairs(parent_args) do
if type(i) == "number" then
if i > 1 then
new_args[i - 1] = v
end
else
new_args[i] = v
end
end
new_args.nocap = true
etymtext = ", " .. frame:expandTemplate { title = template_name, args = new_args }
end
if etymtext then
--return (ine(parent_args.nocap) and "b" or "B") .. "y [[Appendix:Glossary#surface analysis|surface analysis]]" ..
-- etymtext
return "พิจารณาคร่าว ๆ" .. etymtext
end
local function extra_params(params)
params.notext = boolean_param
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = parent_args,
extra_params = extra_params,
allow_type = true,
allow_semicolon_separator = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
parts = { {term = "first"}, {separator = " +‎ ", term = "second"} }
else
error("You must provide at least one part.")
end
end
return m_affix.show_surface_analysis(augment_affix_data({ parts = parts }, args, lang, sc))
end
local function check_max_items(items, max_allowed)
if #items > max_allowed then
local bad_item = items[max_allowed + 1]
if bad_item.term then
error(("At most %s terms can be specified but saw a term specified for term #%s")
:format(max_allowed, max_allowed + 1))
else
for k, v in pairs(bad_item) do
if is_property_key(k) then
error(("At most %s terms can be specified but saw a value for property '%s' of term #%s")
:format(max_allowed, k, max_allowed + 1))
end
end
end
error(("Internal error: Something wrong, %s items generated when there should be at most %s, but item #%s doesn't have a term or any properties")
:format(#items, max_allowed, max_allowed + 1))
end
end
function export.circumfix(frame)
local function extra_params(params)
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local prefix = parts[1]
local base = parts[2]
local suffix = parts[3]
-- Just to make sure someone didn't use the template in a silly way
if not (prefix and base and suffix) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
prefix = {term = "circumfix", alt = "prefix"}
base = {term = "base"}
suffix = {term = "circumfix", alt = "suffix"}
else
error("You must specify a prefix part, a base term and a suffix part.")
end
end
return m_affix.show_circumfix(augment_affix_data({ prefix = prefix, base = base, suffix = suffix }, args, lang, sc))
end
function export.confix(frame)
local function extra_params(params)
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local prefix = parts[1]
local base = parts[3] and parts[2] or nil
local suffix = parts[3] or parts[2]
-- Just to make sure someone didn't use the template in a silly way
if not (prefix and suffix) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
prefix = {term = "prefix"}
suffix = {term = "suffix"}
else
error("You must specify a prefix part, an optional base term and a suffix part.")
end
end
return m_affix.show_confix(augment_affix_data({ prefix = prefix, base = base, suffix = suffix }, args, lang, sc))
end
function export.pseudo_loan(frame)
local function extra_params(params)
params.notext = boolean_param
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc, source = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
has_source = true,
-- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall
-- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this
-- necessary?
require_index_for_pos = true,
allow_semicolon_separator = true,
}
return require(pseudo_loan_module).show_pseudo_loan(
augment_affix_data({ source = source, parts = parts }, args, lang, sc))
end
function export.infix(frame)
local function extra_params(params)
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local base = parts[1]
local infix = parts[2]
-- Just to make sure someone didn't use the template in a silly way
if not (base and infix) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
base = {term = "base"}
infix = {term = "infix"}
else
error("You must provide a base term and an infix.")
end
end
return m_affix.show_infix(augment_affix_data({ base = base, infix = infix }, args, lang, sc))
end
function export.prefix(frame)
local function extra_params(params)
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
local prefixes = parts
local base = nil
local max_prefix = 0
for k, v in pairs(prefixes) do
max_prefix = math.max(k, max_prefix)
end
if max_prefix >= 2 then
base = prefixes[max_prefix]
prefixes[max_prefix] = nil
end
-- Just to make sure someone didn't use the template in a silly way
if not next(prefixes) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
base = {term = "base"}
prefixes = { {term = "prefix"} }
else
error("You must provide at least one prefix.")
end
end
return m_affix.show_prefix(augment_affix_data({ prefixes = prefixes, base = base }, args, lang, sc))
end
function export.suffix(frame)
local function extra_params(params)
params.nocat = boolean_param
params.force_cat = boolean_param
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
local base = parts[1]
local suffixes = {}
for k, v in pairs(parts) do
suffixes[k - 1] = v
end
-- Just to make sure someone didn't use the template in a silly way
if not next(suffixes) then
if mw.title.getCurrentTitle().nsText == "แม่แบบ" then
base = {term = "base"}
suffixes = { {term = "suffix"} }
else
error("You must provide at least one suffix.")
end
end
return m_affix.show_suffix(augment_affix_data({ base = base, suffixes = suffixes }, args, lang, sc))
end
function export.derivsee(frame)
local iargs = frame.args
local iparams = {
["derivtype"] = {},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local params = {
["head"] = {},
["id"] = {},
["sc"] = {type = "script"},
["pos"] = {},
}
local derivtype = iargs.derivtype
params[1] = {required = "true", type = "language", default = "und"}
params[2] = {}
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = args[1]
local term = args[2] or args.head
local id = args.id
local sc = args.sc
--local pos = require(en_utilities_module).pluralize(args.pos or "term")
local pos = args.pos or "term"
if not term then
local SUBPAGE = mw.loadData("Module:headword/data").pagename
if lang:hasType("reconstructed") or mw.title.getCurrentTitle().nsText == "การสืบสร้าง" then
term = "*" .. SUBPAGE
elseif lang:hasType("appendix-constructed") then
term = SUBPAGE
else
term = SUBPAGE
end
end
local category = nil
local langname = lang:getFullName()
if (derivtype == "compound" and pos == nil) then
category = langname .. " compounds with " .. term
elseif derivtype == "compound" and pos == "verbs" then
category = langname .. " compound " .. pos .. " formed with " .. term
elseif derivtype == "compound" then
category = langname .. " compound " .. pos .. " with " .. term
else
category = langname .. " " .. pos .. " " .. derivtype .. "ed with " .. term .. (id and " (" .. id .. ")" or "")
end
return require('Module:collapsible category tree').make{
lang = lang,
sc = sc,
category = category,
}
end
return export
91f1f8ynv78jc8gbp59306hzvlnlw3c
มอดูล:parameter utilities
828
380179
5724466
5684269
2026-06-10T03:39:30Z
OctraBot
3198
5724466
Scribunto
text/plain
local export = {}
local debug_track_module = "Module:debug/track"
local functions_module = "Module:fun"
local parameters_module = "Module:parameters"
local parse_interface_module = "Module:parse interface"
local parse_utilities_module = "Module:parse utilities"
local table_module = "Module:table"
local dump = mw.dumpObject
local error = error
local insert = table.insert
local ipairs = ipairs
local next = next
local pairs = pairs
local require = require
local tonumber = tonumber
local type = type
--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures
modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no
overhead after the first call, since the target functions are called directly in any subsequent calls.
]==]
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function is_callable(...)
is_callable = require(functions_module).is_callable
return is_callable(...)
end
local function list_to_set(...)
list_to_set = require(table_module).listToSet
return list_to_set(...)
end
local function parse_term_with_lang(...)
parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang
return parse_term_with_lang(...)
end
local function parse_inline_modifiers(...)
parse_inline_modifiers = require(parse_interface_module).parse_inline_modifiers
return parse_inline_modifiers(...)
end
local function process_params(...)
process_params = require(parameters_module).process
return process_params(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function table_len(...)
table_len = require(table_module).length
return table_len(...)
end
----------------- end loaders ----------------
local function track(page, track_module)
return debug_track((track_module or "parameter utilities") .. "/" .. page)
end
-- Throw an error prefixed with the words "Internal error" (and suffixed with a dumped version of `spec`, if provided).
-- This is for logic errors in the code itself rather than template user errors.
local function internal_error(msg, spec)
if spec then
msg = ("%s: %s"):format(msg, dump(spec))
end
error(("Internal error: %s"):format(msg))
end
-- Table listing the default recognized special separator arguments and how they display.
export.default_special_separators = {
[";"] = "; ",
["_"] = " ",
["~"] = " ~ ",
["→"] = " → ",
}
-- Table listing how subitem delimiters display. Unlike for `default_special_separators`, the presence of an item in
-- this table does not mean that the delimiter is recognized; only those specified by `data.splitchar` are recognized.
export.default_subitem_separator_map = {
[";"] = "; ",
[","] = ", ",
["/"] = "/",
["_"] = " ",
["~"] = " ~ ",
["→"] = " → ",
}
--[==[ intro:
The purpose of this module is to facilitate implementation of templates that can have arguments specified either through
inline modifiers or separate parameters. There are two types of templates supported: those that take a list of items
with associated properties, which can be specified either through indexed separate parameters (e.g. {{para|t2}},
{{para|pos3}}) or inline modifiers (`<t:...>`, `<pos:...>`, etc.); and those that take a single term, whose properties
can be specified through non-indexed separate parameters (e.g. {{para|t}} or {{para|pos}}) or inline modifiers. Both
types of templates can optionally have subitems in the term parameter(s), where the subitems are typically (but not
necessarily) separated with commas and each subitem can have its own inline modifiers.
Some examples of templates that take a list of items are {{tl|alter}}/{{tl|alt}}; {{tl|synonyms}}/{{tl|syn}},
{{tl|antonyms}}/{{tl|ant}}, and other "nyms" templates; {{tl|col}}, {{tl|col2}}, {{tl|col3}}, {{tl|col4}} and other
column templates; {{tl|descendant}}/{{tl|desc}}; {{tl|affix}}/{{tl|af}}, {{tl|prefix}}/{{tl|pre}} and related *fix
templates; {{tl|affixusex}}/{{tl|afex}} and related templates; {{tl|IPA}}; {{tl|homophones}}; {{tl|rhymes}}; and several
others.
Examples of templates that take a single item are form-of templates ({{tl|inflection of}}/{{tl|infl of}},
{{tl|form of}}, and specific templates such as {{tl|alt form}}/{{tl|alternative form of}},
{{tl|abbr of}}/{{tl|abbreviation of}}, {{tl|clipping of}}, and many others); for etymology templates
({{tl|bor}}/{{tl|borrowed}}, {{tl|der}}/{{tl|derived}}, etc. as well as `misc_variant` templates like {{tl|ellipsis}},
{{tl|abbrev}}, {{tl|clipping}}, {{tl|reduplication}} and the like); and other templates that take an argument structure
similar to {{tl|l}} or {{tl|m}}.
This module can be thought of as a combination of [[Module:parameters]] (which parses template parameters, and in
particular handles the separate parameter versions of the properties) and `parse_inline_modifiers()` in
[[Module:parse utilities]] (which parses inline modifiers).
The two main entry points are `parse_list_with_inline_modifiers_and_separate_params()` (for templates that take a list
of items) and `parse_term_with_inline_modifiers_and_separate_params()` (for templates that take a single item). However,
there are other functions provided, e.g. to initialize the `param_mods` structure that is passed to the two entry
points.
The typical workflow for using `parse_list_with_inline_modifiers_and_separate_params()` looks as follows (a slightly
simplified version of the code in [[Module:nyms]]):
{
local export = {}
local parameter_utilities_module = "Module:parameter utilities"
...
-- Entry point to be invoked from a template.
function export.show(frame)
local parent_args = frame:getParent().args
-- Parameters that don't have corresponding inline modifiers. Note in particular that the parameter corresponding to
-- the items themselves must be specified this way, and must specify either `allow_holes = true` (if the user can
-- omit terms, typically by specifying the term using |altN= or <alt:...> so that they remain unlinked) or
-- `disallow_holes = true` (if omitting terms is not allowed). (If neither `allow_holes` nor `disallow_holes` is
-- specified, an error is thrown in parse_list_with_inline_modifiers_and_separate_params().)
local params = {
[1] = {required = true, type = "language", default = "und"},
[2] = {list = true, allow_holes = true, required = true, default = "term"},
}
local m_param_utils = require(parameter_utilities_module)
-- This constructs the `param_mods` structure by adding well-known groups of parameters (such as all the parameters
-- associated with based on full_link() in [[Module:links]], with default properties that can be overridden. This is
-- easier and less error-prone than manually specifying the `param_mods` structure (see below for how this would
-- look). Here, we specify the group "link" (consisting of all the link parameters for use with full_link()), group
-- "ref" (which adds the "ref" parameter for specifying references), group "l" (which adds the "l" and "ll"
-- parameters for specifying labels) and group "q" (which adds the "q" and "qq" parameters for specifying regular
-- qualifiers). By default, labels and qualifiers have `separate_no_index` set so that e.g. |q1= is distinct from
-- |q=, the former specifying the left qualifier for the first item and the latter specifying the overall left
-- qualifier. For compatibility, we override the `separate_no_index` setting for the group "q", which causes |q= and
-- |q1= to be the same, and likewise for |qq= and |qq1=. Finally, also for compatibility, we add an "lb" parameter
-- that is an alias of "ll" (in all respects; |lb= is the same as |ll=, |lb1= is the same as |ll1=, <lb:...> is the
-- same as <ll:...>, etc.).
local param_mods = m_param_utils.construct_param_mods {
{group = {"link", "ref", "l"}},
{group = "q", separate_no_index = false},
{param = "lb", alias_of = "ll"},
}
-- This processes the raw arguments in `parent_args`, parses inline modifiers and creates corresponding objects
-- containing the property values specified either through inline modifiers or separate parameters.
local items, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
params = params,
param_mods = param_mods,
raw_args = parent_args,
termarg = 2,
parse_lang_prefix = true,
track_module = "nyms",
lang = 1,
sc = "sc.default",
}
local lang = args[1]
-- Now do the actual implementation of the template. Generally this should be split into a separate function, often
-- in a separate module (if the implementation goes in [[Module:foo]], the template interface code goes in
-- [[Module:foo/templates]]).
...
}
The `param_mods` structure controls the properties that can be specified by the user for a given item, and is
conceptually very similar to the `param_mods` structure used by `parse_inline_modifiers()`. The key is the name of the
parameter (e.g. {"t"}, {"pos"}) and the value is a table with optional elements as follows:
* `item_dest`, `store`: Same as the corresponding fields in the `param_mods` structure passed to
`parse_inline_modifiers()`.
* `type`, `set`, `sublist`, `convert` and associated fields such as `family` and `method`: These control parsing and
conversion of the raw values specified by the user and have the same meaning as in [[Module:parameters]] and also in
`parse_inline_modifiers()` (which delegates the actual conversion to [[Module:parameters]]). These fields — and for
that matter, all fields other than `item_dest`, `store` and `overall` — are forwarded to the `process()` function in
[[Module:parameters]].
* `alias_of`: This parameter is an alias of some other parameter. This spec is recognized only by `process()` in
[[Module:parameters]], and not by `parse_inline_modifiers()`; to set up an alias in `parse_inline_modifiers()`, you
need to make sure (using `item_dest`) that both the alias and aliasee modifiers store their values in the same
location, and you need to copy the remaining properties from the aliasee's spec to the aliasing modifier's spec. All
of this happens automatically if you generate the `param_mods` structure using `construct_param_mods()`.
* `require_index`: This means that the non-indexed parameter version of the property is not recognized. E.g. in the
case of the {"sc"} property, use of the {{para|sc}} parameter would result in an error, while {{para|sc1}} is
recognized and specifies the {"sc"} property for the first item. The default, if neither `require_index` nor
`separate_no_index` is given, is for {{para|sc}} and {{para|sc1}} to mean the same thing (both would specify the
{"sc"} property of the first item). Note that `require_index` and `separate_no_index` are mutually exclusive, and if
either one is specified during processing by `construct_param_mods()`, the other one is automaticallly turned off.
* `separate_no_index`: This means that e.g. the {{para|sc}} parameter is distinct from the {{para|sc1}} parameter
(and thus from the `<sc:...>` inline modifier on the first item). This is typically used to distinguish an overall
version of a property from the corresponding item-specific property on the first item. (In this case, for example,
{{para|sc}} overrides the script code for all items, while {{para|sc1}} overrides the script code only for the
first item.) If not given, and if `require_index` is not given, {{para|sc}} and {{para|sc1}} would have the same
meaning and refer to the item-specific property on the first item. When this is given, the overall value can be
accessed using the `.default` field of the property value in `args`, e.g. in this case `args.sc.default`. Note that
(as mentioned above) `require_index` and `separate_no_index` are mutually exclusive, and if either one is specified
during processing by `construct_param_mods()`, the other one is automaticallly turned off.
* `list`, `allow_holes`, `disallow_holes`: These should '''not''' be given. `list` and `allow_holes` are automatically
set for all parameter specs added to the `params` structure used by `process()` in [[Module:parameters]], and
`disallow_holes` clashes with `allow_holes`.
For the above workflow example, the call to `construct_param_mods()` generates the following `param_mods` structure:
{
local param_mods = {
-- the parameters generated by group "link"
alt = {},
t = {
-- [[Module:links]] expects the gloss in "gloss".
item_dest = "gloss",
},
gloss = {
alias_of = "t",
},
tr = {},
ts = {},
g = {
-- [[Module:links]] expects the genders in "genders".
item_dest = "genders",
type = "genders",
},
pos = {},
ng = {},
lit = {},
id = {},
sc = {
separate_no_index = true,
type = "script",
},
-- the parameters generated by group "ref"
ref = {
item_dest = "refs",
type = "references",
},
-- the parameters generated by group "l"
l = {
type = "labels",
separate_no_index = true,
},
ll = {
type = "labels",
separate_no_index = true,
},
-- the parameters generated by group "q"; note that `separate_no_index = true` would be set, but is overridden
-- (specifying `separate_no_index = false` in the `param_mods` structure is equivalent to not specifying it at all)
q = {
type = "qualifier",
separate_no_index = false,
},
qq = {
type = "qualifier",
separate_no_index = false,
},
infl = {
type = "form of tags",
separate_no_index = true,
},
-- the parameter generated by the individual "lb" parameter spec; note that only `alias_of` was explicitly given,
-- while `item_dest` is automatically set so that inline modifier <lb:...> stores into the same place as <ll:...>,
-- and the other specs are copied from the `ll` spec so `lb` works like `ll` in all regards
lb = {
alias_of = "ll",
item_dest = "ll",
type = "labels",
separate_no_index = true,
},
}
}
]==]
local qualifier_spec = {
type = "qualifier",
separate_no_index = true,
}
local label_spec = {
type = "labels",
separate_no_index = true,
}
local form_of_spec = {
type = "form of tags",
separate_no_index = true,
}
local recognized_param_mod_groups = {
link = {
alt = {},
t = {
-- [[Module:links]] expects the gloss in "gloss".
item_dest = "gloss",
},
gloss = {
alias_of = "t",
},
tr = {},
ts = {},
g = {
-- [[Module:links]] expects the genders in "genders".
item_dest = "genders",
type = "genders",
},
pos = {},
ng = {},
lit = {},
id = {},
sc = {
separate_no_index = true,
type = "script",
},
},
lang = {
lang = {
require_index = true,
type = "language",
},
},
q = {
q = qualifier_spec,
qq = qualifier_spec,
},
a = {
a = label_spec,
aa = label_spec,
},
l = {
l = label_spec,
ll = label_spec,
},
infl = {
infl = form_of_spec,
},
ref = {
ref = {
item_dest = "refs",
type = "references",
},
},
}
local function merge_param_mod_settings(orig, additions)
local merged = shallow_copy(orig)
for k, v in pairs(additions) do
merged[k] = v
if k == "require_index" then
merged.separate_no_index = nil
elseif k == "separate_no_index" then
merged.require_index = nil
end
end
merged.default = nil
merged.group = nil
merged.param = nil
merged.exclude = nil
merged.include = nil
return merged
end
local function verify_type(spec, param, typ1, typ2)
if not spec[param] then
return
end
local val = spec[param]
if type(val) ~= typ1 and (not typ2 or type(val) ~= typ2) then
internal_error(("Parameter `%s` must be a %s%s but saw a %s"):format(param, typ1, typ2 and " or " .. typ2 or "",
type(val)), spec)
end
end
local function verify_well_constructed_spec(spec)
local num_control = (spec.default and 1 or 0) + (spec.group and 1 or 0) + (spec.param and 1 or 0)
if num_control == 0 then
internal_error(
"Spec passed to construct_param_mods() must have either the `default`, `group` or `param` keys set", spec)
end
if num_control > 1 then
internal_error(
"Exactly one of `default`, `group` or `param` must be set in construct_param_mods() spec", spec)
end
if spec.list or spec.allow_holes then
-- FIXME: We need to support list = "foo" for list parameters that are stored in e.g. 2=, foo2=, foo3=, etc.
internal_error("`list` and `allow_holes` may not be set; they are automatically set when constructing the " ..
"corresponding spec in the `params` object passed to [[Module:parameters]]", spec)
end
if spec.disallow_holes then
internal_error("`disallow_holes` may not be set; it conflicts with `allow_holes`, which is automatically " ..
"set when constructing the corresponding spec in the `params` object passed to [[Module:parameters]]", spec)
end
if spec.include and spec.exclude then
internal_error("Saw both `include` and `exclude` in the same spec", spec)
end
if (spec.include or spec.exclude) and not spec.group then
internal_error(
"`include` and `exclude` can only be specified along with `group`, not with `default` or `param`", spec)
end
verify_type(spec, "group", "string", "table")
verify_type(spec, "param", "string", "table")
verify_type(spec, "include", "table")
verify_type(spec, "exclude", "table")
end
--[==[
Construct the `param_mods` structure used in parsing arguments and inline modifiers from a list of specifications.
A sample invocation (a slightly simplified version of the actual invocation associated with {{tl|affix}} and related
templates) looks like this:
{
local param_mods = require("Module:parameter utilities").construct_param_mods {
-- We want to require an index for all params (or use separate_no_index, which also requires an index for the
-- param corresponding to the first item).
{default = true, require_index = true},
{group = {"link", "ref", "lang", "q", "l"}},
-- Override these two to have separate_no_index.
{param = {"lit", "pos"}, separate_no_index = true},
}
}
Each specification either sets the default value for further parameter specs or adds one or more parameters. Parameters
can be added directly using `param`, or groups of predefined parameters can be added using `group`. Specifications are
one of three types:
# Those that set the default properties for future-added parameters. These contain {default = true} as one of the
properties of the spec. Specs are processed in order and you can change the defaults mid-way through.
# Those that add the parameters associated with one or more pre-defined groups. These contain {group = "group"} or
{group = {"group1", "group2", ...}}. The pre-defined parameter groups and their associated properties are listed
below. The pre-defined properties of parameters in a group override properties associated with a {default = true}
spec, and are in turn overridden by any properties given directly in the spec itself. Note as well that setting the
`separate_no_index` property will automatically cause the `require_index` property to be unset and vice-versa, as the
two are mutually exclusive. (This happens in the example above, where the {separate_no_index = true} setting
associated with the params {"lit"} and {"pos"} cancels out the {require_index = true} default setting, as well as less
obviously with the pre-defined {"sc"} property of the {"link"} group, the {"q"} and {"qq"} properties of the {"q"}
group, and the {"l"} and {"ll"} properties of the {"l"} group, all of which have an associated pre-defined property
{separate_no_index = true}, which overrides and cancels out the {require_index = true} default setting. Finally, when
adding the parameters of a group, you can request the only a subset of the parameters be added using either the
`include` or `exclude` properties, each of whose values is a list of parameters that specify (respectively) the
parameters to include (all other parameters of the group are excluded) or to exclude (all other parameters of the
group are included). This is used, for example, in [[Module:romance etymology]] and [[Module:it-etymology]], which
specify {group = "link", exclude = {"tr", "ts", "sc"}} to exclude link parameters that aren't relevant to Latin-script
languages such as the Romance languages, and conversely in [[Module:IPA/templates]], which specifies
{group = "link", include = {"t", "gloss", "pos"}} to include only the specified parameters for use with {{tl|IPA}}.
# Those that add individual parameters. These contain {param = "param"} or {param = {"param1", "param2", ...}}, the
latter syntax used to control a set of parameters together. The resulting spec is formed by initializing the
parameter's settings with any previously-specified default properties (using a spec containing {default = true}) if
the parameter hasn't already been initialized, and then overriding the resulting settings with any settings given
directly in the specification. In the above example, the {"lit"} and {"pos"} parameters were previously initialized
through the {"link"} group (specified in the second of the three specifications) but ended up with
{require_index = true} due to the {default = true} spec (the first of the three specifications). We override these
two parameters to have {separate_no_index = true} (which, as mentioned above, cancels out {require_index = true}).
This is done so that {{tl|affix}} and related templates have {{para|pos}} and {{para|lit}} parameters distinct from
{{para|pos1}} and {{para|lit1}}, which are used to specify an overall part of speech (which applies to all parts of
the affix, as opposed to applying to just one element of the expression) or a literal definition for the entire
expression (instead of just for one element of the expression).
The built-in parameter groups are as follows:
{|class="wikitable"
! Group !! Group meaning !! Parameter !! Parameter meaning !! Default properties
|-
| rowspan=11| `link`
| rowspan=11| link parameters; same as those available on {{tl|l}}, {{tl|m}} and other linking templates
| `alt` || display text, overriding the term's display form || —
|-
| `t` || gloss (translation) of a non-English term || {item_dest = "gloss"}
|-
| `gloss` || gloss (translation); same as `t` || {alias_of = "t"}
|-
| `tr` || transliteration of a non-Latin-script term; only needed if the automatic transliteration is incorrect or unavailable (e.g. in Hebrew, which doesn't have automatic transliteration) || —
|-
| `ts` || transcription of a non-Latin-script term, if the transliteration is markedly different from the actual pronunciation; should not be used for IPA pronunciations || —
|-
| `g` || comma-separated list of genders; whitespace may surround the comma and will be ignored || {item_dest = "genders", type = "genders"}
|-
| `pos` || part of speech for the term || —
|-
| `ng` || arbitrary non-gloss descriptive text for the term || —
|-
| `lit` || literal meaning (translation) of the term || —
|-
| `id` || a sense ID for the term, which links to anchors on the page set by the {{tl|senseid}} template || —
|-
| `sc` || the script code (see [[Wiktionary:Scripts]]) for the script that the term is written in; rarely necessary, as the script is autodetected (in most cases, correctly) || {separate_no_index = true, type = "script"}
|-
| rowspan=2| `q`
| rowspan=2| left and right normal qualifiers (as displayed using {{tl|q}})
| `q` || left normal qualifier || {separate_no_index = true, type = "qualifier"}
|-
| `qq` || right normal qualifier || {separate_no_index = true, type = "qualifier"}
|-
| rowspan=2| `a`
| rowspan=2| left and right accent qualifiers (as displayed using {{tl|a}})
| `a` || comma-separated list of left accent qualifiers; whitespace must not surround the comma || {separate_no_index = true, type = "labels"}
|-
| `aa` || comma-separated list of right accent qualifiers; whitespace must not surround the comma || {separate_no_index = true, type = "labels"}
|-
| rowspan=2| `l`
| rowspan=2| left and right labels (as displayed using {{tl|lb}}, but without categorizing)
| `l` || comma-separated list of left labels; whitespace must not surround the comma || {separate_no_index = true, type = "labels"}
|-
| `ll` || comma-separated list of right labels; whitespace must not surround the comma || {separate_no_index = true, type = "labels"}
|-
| `ref`
| reference(s) (in the format accepted by [[Module:references]]; see also the documentation for the {{para|ref}} parameter to {{tl|IPA}})
| `ref` || one or more references, in the format accepted by [[Module:references]] || {item_dest = "refs", type = "references"}
|-
| `lang`
| language for an individual term (provided for compatibility; it is preferred to specify languages for individual terms using language prefixes instead)
| `lang` || language code (see [[Wiktionary:Languages]]) for the term || {require_index = true, type = "language"}
|}
]==]
function export.construct_param_mods(specs)
local param_mods = {}
local default_specs = {}
for _, spec in ipairs(specs) do
verify_well_constructed_spec(spec)
if spec.default then
-- This will have an extra `default` field in it, but it will be erased by merge_param_mod_settings()
default_specs = spec
else
if spec.group then
local groups = spec.group
if type(groups) ~= "table" then
groups = {groups}
end
local include_set
if spec.include then
include_set = list_to_set(spec.include)
end
local exclude_set
if spec.exclude then
exclude_set = list_to_set(spec.exclude)
end
for _, group in ipairs(groups) do
local group_specs = recognized_param_mod_groups[group]
if not group_specs then
internal_error(("Unrecognized built-in param mod group '%s'"):format(group), spec)
end
for group_param, group_param_settings in pairs(group_specs) do
local include_param
if include_set then
include_param = include_set[group_param]
elseif exclude_set then
include_param = not exclude_set[group_param]
else
include_param = true
end
if include_param then
local merged_settings = merge_param_mod_settings(merge_param_mod_settings(
param_mods[group_param] or default_specs, group_param_settings), spec)
param_mods[group_param] = merged_settings
end
end
end
end
if spec.param then
local params = spec.param
if type(params) ~= "table" then
params = {params}
end
for _, param in ipairs(params) do
local settings = merge_param_mod_settings(param_mods[param] or default_specs, spec)
-- If this parameter is an alias of another parameter, we need to copy the specs from the other
-- parameter, since parse_inline_modifiers() doesn't know about `alias_of` and having the specs
-- duplicated won't cause problems for [[Module:parameters]]. We also need to set `item_dest` to
-- point to the `item_dest` of the aliasee (defaulting to the aliasee's value itself), so that
-- both modifiers write to the same location. Note that this works correctly in the common case of
-- <t:...> with `item_dest = "gloss"` and <gloss:...> with `alias_of = "t"`, because both will end
-- up with `item_dest = "gloss"`.
local aliasee = settings.alias_of
if aliasee then
local aliasee_settings = param_mods[aliasee]
if not aliasee_settings then
internal_error(("Undefined aliasee '%s'"):format(aliasee), spec)
end
for k, v in pairs(aliasee_settings) do
if settings[k] == nil then
settings[k] = v
end
end
if settings.item_dest == nil then
settings.item_dest = aliasee
end
end
param_mods[param] = settings
end
end
end
end
return param_mods
end
-- Return true if `k` is a "built-in" (specially recognized) key in a `param_mod` specification. All other keys
-- are forwarded to the structure passed to [[Module:parameters]].
local function param_mod_spec_key_is_builtin(k)
return k == "item_dest" or k == "overall" or k == "store"
end
--[==[
Convert the properties in `param_mods` into the appropriate structures for use by `process()` in [[Module:parameters]]
and store them in `params`. If `overall_only` is given, only store the properties in `param_mods` that correspond to
overall (non-item-specific) parameters. Currently this only happens when `separate_no_index` is specified.
]==]
function export.augment_params_with_modifiers(params, param_mods, overall_only)
if overall_only then
for param_mod, param_mod_spec in pairs(param_mods) do
if overall_only == "always" or param_mod_spec.separate_no_index then
local param_spec = {}
for k, v in pairs(param_mod_spec) do
if k ~= "separate_no_index" and k ~= "require_index" and not param_mod_spec_key_is_builtin(k) then
param_spec[k] = v
end
end
params[param_mod] = param_spec
end
end
else
local list_with_holes
-- Add parameters for each term modifier.
for param_mod, param_mod_spec in pairs(param_mods) do
local param_spec
for k, v in pairs(param_mod_spec) do
if not param_mod_spec_key_is_builtin(k) then
if param_spec == nil then
param_spec = {list = true}
end
param_spec[k] = v
end
end
if param_spec == nil then
if list_with_holes == nil then
list_with_holes = {list = true, allow_holes = true}
end
param_spec = list_with_holes
elseif param_spec.alias_of == nil then
param_spec.allow_holes = true
end
params[param_mod] = param_spec
end
end
end
--[==[
Return true if `k`, a key in an item, refers to a property of the item (is not one of the specially stored values).
Note that `lang` and `sc` are considered properties of the item, although `lang` is set when there's a language
prefix and both `lang` and `sc` may be set from default values specified in the `data` structure passed into
`parse_list_with_inline_modifiers_and_separate_params()` and `parse_term_with_inline_modifiers_and_separate_params()`.
If you don't want these treated as property keys, you need to check for them yourself.
]==]
function export.item_key_is_property(k)
return k ~= "term" and k ~= "termlang" and k ~= "termlangs" and k ~= "itemno" and k ~= "orig_index" and
k ~= "separator"
end
-- Fetch the argument in `args` corresponding to `index_or_value`, which may be a string of the form "foo.default"
-- (requesting the value of `args["foo"].default`); a string or number (requesting the value at that key); a function of
-- one argument (`args`), which returns the argument value; or the value itself. Return the resulting value and the
-- parameter in `args` that the value came from, or nil if unknown (i.e. a function or direct value was specified).
local function fetch_argument(args, index_or_value)
if not index_or_value then
return index_or_value, nil
end
local index_or_value_type = type(index_or_value)
if index_or_value_type == "string" then
if index_or_value:sub(-8) == ".default" then
local index_without_default = index_or_value:sub(1, -9)
local arg_obj = fetch_argument(args, index_without_default)
if type(arg_obj) ~= "table" then
internal_error(("Requested that the '.default' key of argument `%s` be fetched, but argument value is undefined or not a table"):
format(index_without_default), arg_obj)
end
return arg_obj.default, index_without_default
end
if index_or_value:match("^%d+$") then
index_or_value = tonumber(index_or_value)
end
return args[index_or_value], index_or_value
elseif index_or_value_type == "number" then
return args[index_or_value], index_or_value
elseif is_callable(index_or_value) then
return index_or_value(args), nil
end
return index_or_value, nil
end
function export.generate_obj_maybe_parsing_lang_prefix(data)
local term = data.term
local term_dest = data.term_dest or "term"
local termobj = data.termobj or {}
if data.parse_lang_prefix and term:find(":", nil, true) then
local actual_term, termlangs = parse_term_with_lang {
term = term,
parse_err = data.parse_err,
paramname = data.paramname,
allow_bad = data.allow_bad_lang_prefix,
allow_multiple = data.allow_multiple_lang_prefixes,
lang_cache = data.lang_cache,
}
termobj[term_dest] = actual_term ~= "" and actual_term or nil
if termlangs then
-- If we couldn't parse a language code, don't overwrite an existing setting in `lang`
-- that may have originated from a separate |langN= param.
if data.allow_multiple_lang_prefixes then
termobj.termlangs = termlangs
termobj.lang = termlangs and termlangs[1] or nil
else
termobj.termlang = termlangs
termobj.lang = termlangs
end
end
else
termobj[term_dest] = term ~= "" and term or nil
end
return termobj
end
-- Subfunction of parse_list_with_inline_modifiers_and_separate_params() and
-- parse_term_with_inline_modifiers_and_separate_params(), validating certain argument-related fields that are shared
-- among the two functions.
local function validate_argument_related_fields(data)
if not data.termarg then
internal_error("`data.termarg` must be given, indicating which argument contains the terms to be parsed", data)
end
if not data.param_mods then
internal_error("`data.param_mods` must be given, indicating the allowed inline modifiers and separate " ..
"parameters to copy", data)
end
local subitem_param_handling = data.subitem_param_handling or "only"
if subitem_param_handling ~= "only" and subitem_param_handling ~= "first" and subitem_param_handling ~= "last" then
internal_error("Unrecognized value for `data.subitem_param_handling`, should be 'first', 'last' or 'only'",
subitem_param_handling)
end
if data.raw_args then
if data.processed_args then
internal_error("Only one of `data.raw_args` and `data.processed_args` can be specified", data)
end
if not data.params then
internal_error("When `data.raw_args` is specified, so must `data.params`, so that the raw arguments " ..
"can be parsed", data)
end
if data.params[data.termarg] == nil then
internal_error("There must be a spec in `data.params` corresponding to `data.termarg`", data)
end
else
if not data.processed_args then
internal_error("Either `data.raw_args` or `data.processed_args` must be specified", data)
end
if data.params then
internal_error("When `data.processed_args` is specified, `data.params` should not be specified", data)
end
end
end
local function argval_missing(val)
return val == nil or type(val) == "table" and next(val) == nil
end
-- Subfunction of parse_list_with_inline_modifiers_and_separate_params() and
-- parse_term_with_inline_modifiers_and_separate_params(). After parsing inline modifiers, copy the separate parameters
-- to the generated object (or to the appropriate subobject if there are multiple). `data` contains the following
-- fields:
--
-- `args`: The separate-parameter argument structure.
-- `param_mods`: The structure describing the inline modifiers.
-- `itemno`: The logical item number of the term being processed, or nil if there's only a single term.
-- `termobj`: The object to store the inline modifiers into. If there are subitems, they are in the `terms` field;
-- otherwise the properties are stored directly into `termobj`.
-- `has_subitems`: True if there are subitems.
-- `subitem_separator_map`: If `has_subitems` and this is specified, controls the assignment of the `separator` field
-- in subitems. If not specified or a delimiter is not in the map, it is copied unchanged.
-- `lang`: Language object to store into all items.
-- `sc`: Script object to store into all items, or nil.
-- `subitem_param_handling`: "only", "first" or "last", indicating what to do if there are multiple subitems.
-- `allow_conflicting_inline_mods_and_separate_params`: If true, specifying a value for both an inline modifier and
-- corresponding separate parameter is allowed, and the inline modifier takes precedence. Otherwise, an error
-- occurs.
-- `postprocess_termobj`: Optional function called on all items at the end, to do any postprocessing. Called with one
-- argument, the object to postprocess.
local function copy_separate_params_to_termobj_and_postprocess(data)
local args, param_mods, itemno, termobj = data.args, data.param_mods, data.itemno, data.termobj
local function set_lang_and_sc(termobj)
-- Set these after parsing inline modifiers, not in generate_obj(), otherwise we'll get an error in
-- parse_inline_modifiers() if we try to use <lang:...> or <sc:...> as inline modifiers.
termobj.lang = termobj.lang or data.lang
termobj.sc = termobj.sc or data.sc
end
local function fetch_separate_param(args, paramkey, itemno)
local argval = args[paramkey]
-- Careful with argument values that may be `false`.
if argval and itemno then
argval = argval[itemno]
end
return argval
end
-- Copy separate parameters to a given object.
local function copy_separate_params_to_termobj(fetch_destobj)
for param_mod, param_mod_spec in pairs(param_mods) do
local dest = param_mod_spec.item_dest or param_mod
-- Don't do anything with the `sc` param, which will get overwritten below; we don't
-- want it to cause an error if there are multiple subitems.
if dest ~= "sc" then
local argval = fetch_separate_param(args, param_mod, itemno)
if not argval_missing(argval) then
local destobj = fetch_destobj(param_mod, param_mod_spec, dest)
-- Don't overwrite a value already set by an inline modifier.
if argval_missing(destobj[dest]) then
destobj[dest] = argval
elseif not data.allow_conflicting_inline_mods_and_separate_params then
error(("Can't specify a value for separate parameter %s%s= because there is " ..
"already an inline modifier <%s:...> specifying a value for the term"):format(
param_mod, itemno or "", param_mod))
end
end
end
end
end
if data.has_subitems then
-- If there are any separate indexed parameters, we need to copy them to the first, last or only
-- subitem, depending on the value of `data.subitem_param_handling` (which defaults to 'only',
-- meaning it's an error if there are multiple subitems). Do this before calling
-- postprocess_termobj() because the latter sets .lang and .sc and we want the user to be able to
-- set separate langN= and scN= parameters.
-- If there was no term, `termobj.terms` will not exist; make it exist to make the callers' lives easier.
if not termobj.terms then
termobj.terms = {}
end
-- Compute whether any of the separate indexed params exist for this index.
local any_param_at_index
for param_mod in pairs(param_mods) do
local argval = fetch_separate_param(args, param_mod, itemno)
if not argval_missing(argval) then
any_param_at_index = true
break
end
end
-- If there was no term, but there's a separate parameter, we need to create an empty subitem.
if any_param_at_index and not termobj.terms[1] then
termobj.terms[1] = {}
end
local function fetch_destobj(param_mod, param_mod_spec, dest)
if param_mod_spec.overall then
return termobj
end
if data.subitem_param_handling == "only" and termobj.terms[2] then
error(("Can't specify a value for separate parameter %s%s= because there are " ..
"multiple subitems (%s) in the term; use an inline modifier"):format(
param_mod, itemno or "", #termobj.terms))
end
local termind
-- q/a/l need to go at the beginning and qq/aa/ll/refs at the end, regardless; otherwise, respect
-- `data.subitem_param_handling`.
if dest == "q" or dest == "a" or dest == "l" then
termind = 1
elseif dest == "qq" or dest == "aa" or dest == "ll" or dest == "refs" then
termind = #termobj.terms
elseif data.subitem_param_handling == "only" or data.subitem_param_handling == "first" then
termind = 1
else
termind = #termobj.terms
end
return termobj.terms[termind]
end
copy_separate_params_to_termobj(fetch_destobj)
for i, subitem in ipairs(termobj.terms) do
set_lang_and_sc(subitem)
if subitem.delimiter then
subitem.separator = i == 1 and "" or
data.subitem_separator_map and data.subitem_separator_map[subitem.delimiter] or
subitem.delimiter
end
if data.postprocess_termobj then
data.postprocess_termobj(subitem, data)
end
end
else
-- Copy all the parsed term-specific parameters into `termobj`.
copy_separate_params_to_termobj(function(param_mod, dest) return termobj end)
set_lang_and_sc(termobj)
if data.postprocess_termobj then
data.postprocess_termobj(termobj, data)
end
end
end
local function postprocess_termobj(item, data)
if not (data.disallow_custom_separators or data.use_semicolon) then
if data.has_subitems and item.separator and item.separator:find(",", nil, true) then
data.use_semicolon = true
else
-- If the displayed term (from .term/etc. or .alt) has an embedded comma, use a semicolon to
-- join the terms.
local term_text = item[data.term_dest] or item.alt
if term_text and term_text:find(",", nil, true) then
data.use_semicolon = true
end
end
end
end
--[==[
Parse a list of terms, each of which may have properties specified using inline modifiers or separate parameters. This
function is intended for parsing the arguments of templates like {{tl|syn}}, {{tl|ant}} and related ''*nym'' templates;
alternative-form templates {{tl|alt}}/{{tl|alter}}; affix templates like {{tl|af}}/{{tl|affix}},
{{tl|com}}/{{tl|compound}}, etc.; affix usex templates like {{tl|afex}}/{{tl|affixusex}}; name templates like
{{tl|name translit}}; column templates like {{tl|col}}; pronunciation templates like {{tl|rhyme}}/{{tl|rhymes}} and
{{tl|hmp}}/{{tl|homophones}}; etc. In these templates there are one or more terms specified using numeric parameters, and
associated separate parameters specifying per-term properties such as {{para|t1}}, {{para|t2}}, {{para|t3}}, ... for the
gloss of the first, second, third, ... term respectively. All such properties can also be specified through inline
modifiers attached directly to each term (`<t:...>`, `<pos:...>`, etc.). Normally it is an error if both an inline
modifier and separate parameter for the same value are given, but this can be overridden (in which case inline modifiers
take precedence over separate parameters when both occur).
For an example of a typical workflow involving this function, see the comment at the top of this file.
Some notable properties of this function:
# Processing of the raw frame parent args using `process()` in [[Module:parameters]] can occur either inside of this
function (the usual workflow) or outside of this function (for more complex cases). In the former case the raw parent
args are passed in along with a partially built `params` structure of the sort required by [[Module:parameters]],
containing only the term list itself along with any other parameters that are '''not''' term properties (such as
a language code in {{para|1}} and boolean flags like {{para|nocat}}, {{para|nocap}}, etc.). This structure is
''augmented'' with list parameters, one for each per-term property, and [[Module:parameters]] is invoked. In the
latter case where raw argument processing is done by the caller, they must build the partial `params` structure;
augment it themselves using `augment_params_with_modifiers()`; call [[Module:parameters]] themselves; and pass in the
processed arguments. In both cases, the return value of this function contains three values: a list of objects, one
per term, specifying the term and all properties; the processed arguments structure, so that the non-term-property
arguments can be processed as appropriate; and an object containing miscellaneous global computed properties
(currently only `use_semicolon`; see below).
# Optionally, each term can consist of a number of ''subitems'' separated by delimiters (usually a comma, but the
possible delimiter or delimiters are controllable). Each subitem can have its own inline modifiers. This functionality
is used, for example, by {{tl|col}} and variants, which allow each row to have comma-separated or tilde-separated
subitems. When this feature is invoked, the format of the per-term object changes; instead of directly being an object
describing the term and its properties, it is an object with a `terms` field containing a list of per-subitem objects
along with other top-level fields describing per-term properties. By default, if there are separate parameters
specified along with multiple subitems, an error occurs, but this is controllable; currently, you can request that the
parameters be assigned to the first or last subitem.
# By default, special ''separator'' arguments may be present, mixed in among regular term arguments. Examples of such
separator arguments are (by default; this can be overridden) a bare semicolon, specifying that the terms on either
side should be separated by a semicolon instead of a comma (indicating a higher-level grouping); a bare tilde,
replacing the comma separator with a tilde (indicating that the terms on either side are alternants); and a bare
underscore, replacing the comma separator with a space. Separator arguments are ignored when numbering the separate
parameters. You disable the separator argument handling entirely if it doesn't make sense to have this (e.g. in
{{tl|af}}/{{tl|affix}}, where the separator is always a {{cd|+}} sign).
`data` is an object containing several possible fields.
1. Fields that are required or recommended (usually related to argument processing):
* `raw_args` ('''required''' unless `processed_args` is specified): The raw arguments, normally fetched from
{frame:getParent().args}. They are parsed using `process()` in [[Module:parameters]]. Most callers pass in raw
arguments.
* `processed_args`: The object of parsed arguments returned by `process()` in [[Module:parameters]]. One (but not both)
of `raw_args` and `processed_args` must be set.
* `param_mods` ('''required'''): A structure describing the possible inline modifiers and their properties. See the
introductory comment above. Most often, this is generated using `construct_param_mods()` rather than specified
manually.
* `params` ('''required''' unless `processed_args` is specified): A structure describing the possible parameters,
'''other than''' the ones that are separate-parameter equivalents of inline modifiers. This is automatically
"augmented" with the separate-parameter equivalents of the inline modifiers described in `param_mods` prior to parsing
the raw arguments with [[Module:parameters]]. '''WARNING:''' This structure is destructively modified, both by the
"augmentation" process of adding separate-parameter equivalents of inline modifiers, and by the processing done by
[[Module:parameters]] itself. (Nonetheless, substructures can safely be shared in this structure, and will be
correctly handled.)
* `termarg` ('''required'''): The argument containing the first item with attached inline modifiers to be parsed.
Usually a numeric value such as {1} or {2}.
* `track_module` ('''recommended'''): The name of the calling module, for use in adding tracking pages that are used
internally to track pages containing template invocations with certain properties. Example properties tracked are
missing items with corresponding properties as well as missing items without corresponding properties (which are
skipped entirely). To find out the exact properties tracked and the name of the tracking pages, read the code.
* `lang` ('''recommended'''): The language object for the language of the items, or the name of the argument to fetch
the object from. It is not strictly necessary to specify this, as this function only initializes items based on inline
modifiers and separate arguments and doesn't actually format the resulting items. However, if specified, it is used
for certain purposes:
*# It specifies the default for the `lang` property of returned objects if not otherwise set (e.g. by a language
prefix).
*# It is used to initialize an internal cache for speeding up language-code parsing (primarily useful if the same
language code may appear in several items, such as with {{tl|col}} and related templates).
The value of `lang` can be any of the following:
* If a string of the form "foo.default", it is assumed to be requesting the value of `args["foo"].default`.
* Otherwise, if a string or number, it is assumed to be requesting the value of `args` at that key. Note that if the
string is in the form of a number (e.g. "3"), it is normalized to a number prior to fetching (this also happens with
a spec like "2.default").
* Otherwise, if a function, it is assumed to be a function to return the argument value given `args`, which is passed
to the function as its only argument.
* Otherwise, it is used directly.
* `sc` ('''recommended'''): The script object for the items, or the name of the argument to fetch the object from. The
possible values and their handling are the same as with `lang`. In general, as with `lang`, it is not strictly
necessary to specify this. However, if specified, it is used to supply the default for the `sc` property of returned
items if not otherwise set (e.g. by the {{para|sc<var>N</var>}} parameter or `<sc:...>` inline modifier). The most
common value is {"sc.default"}.
2. Other argument-related fields:
* `process_args_before_parsing`: An optional function to apply further processing to the processed `args` structure
returned by [[Module:parameters]], before parsing inline modifiers. This is passed one argument, the processed
arguments. It should make modifications in-place.
* `term_dest`: The field to store the value of the item itself into, after inline modifiers and (if allowed) language
prefixes are stripped off. Defaults to {"term"}.
* `pre_normalize_modifiers`: As in `parse_inline_modifiers()`.
* `allow_conflicting_inline_mods_and_separate_params`: If specified, don't throw an error if a value is specified for
a given property using both an inline modifier and separate param; in this case, the inline modifier takes precedence.
3. Fields related to language prefixes:
* `parse_lang_prefix`: If true, allow and parse off a language code prefix attached to items followed by a colon, such
as {la:minūtia} or {grc:[[σκῶρ|σκατός]]}. Etymology-only languages are allowed. Inline modifiers can be attached to
such items. The exact syntax allowed is as specified in the `parse_term_with_lang()` function in
[[Module:parse utilities]]. If `allow_multiple_lang_prefixes` is given, a {{cd|+}}-sign-separated list of language
prefixes can be attached to an item. The resulting language object is stored into the `termlang` field, and also into
the `lang` field (or in the case of `allow_multiple_lang_prefixes`, the list of language objects is stored into the
`termlangs` field, and the first specified object is stored in the `lang` field).
* `allow_multiple_lang_prefixes`: If given in conjunction with `parse_lang_prefix`, multiple language code prefixes can
be given, separated by a {{cd|+}} sign. See `parse_lang_prefix` above.
* `allow_bad_lang_prefix`: If given in conjunction with `parse_lang_prefix`, unrecognized language prefixes do not
trigger an error, but are simply ignored (and not stripped off the item). Note that, regardless of whether this is
given, prefixes before a colon do not trigger an error if they do not have the form of a language prefix or if a space
follows the colon. It is not recommended that this be given because typos in language prefixes will not trigger an
error and will tend to remain unfixed.
4. Fields related to custom/special separators:
* `disallow_custom_separators`: If specified, disallow specifying custom separators (semicolon, underscore, tilde; see
the internal `default_special_separators` table, or the `special_separators` field) as an item value to override the
default separator. By default, the previous separator of each item is considered to be an empty string (for the first
item) and otherwise the value of the field `default_separator` (normally a comma + space), unless either the preceding
item is one of the values listed in `special_separators`, such as a bare semicolon (which causes the following item's
previous separator to be a semicolon + space) or an item has an embedded comma in it (which causes ''all'' items other
than the first to have their previous separator be a semicolon + space). The previous separator of each item is set on
the item's `separator` property. Bare semicolons and other separator arguments do not count when indexing items using
separate parameters.
For example, the following is correct:
** {{tl|template|lang|item 1|q1=qualifier 1|;|item 2|q2=qualifier 2}}
If `disallow_custom_separators` is specified, however, the `separator` property is not set and separator arguments are
not recognized.
* `default_separator`: Override the default separator (normally {", "}).
* `special_separators`: Table giving the special/custom separators that can be given, and how they should display. If
not specified, the default in `default_special_separators` is used. This is a table mapping separator values (such as
{"~"}) to the corresponding display string (such as {" ~ "}).
5. Fields related to multiple subitems in a given term:
* `splitchar`: A Lua pattern. If specified, each user-specified argument can consist of multiple delimiter-separated
subitems, each of which may be followed by inline modifiers. In this case, each element in the returned list of items
is no longer an object describing an item, but instead an object with a `terms` field, whose value is a list
describing the subitems (whose format is the same as the normal format of an item in the top-level list when
`splitchar` is not specified). Each subitem object will have a `delimiter` field holding the actual delimiter
occurring before the subitem, which is useful in the case where `splitchar` matches multiple possible characters. In
this case, it is possible to specify that a given modifier can only occur after the last subitem and effectively
modifies the whole collection of subitems by setting `overall = true` on the modifier. In this case, the modifier's
value will be stored in the top-level object (the object with the `terms` field specifying the subitems). Note that
splitting on delimiters will not happen in certain protected sequences (by default comma+whitespace; see below). In
addition, the algorithm to split on delimiters is sensitive to inline modifier syntax and will not be confused by
delimiters inside of inline modifiers or inside of square brackets, which do not trigger splitting (whether or not
contained within protected sequences).
* `escape_fun` and `unescape_fun`: As in `split_escaping()` and `split_alternating_runs_escaping()` in
[[Module:parse utilities]]. They control the protected sequences that won't be split when `splitchar` is specified
(see previous item). By default, `escape_comma_whitespace` and `unescape_comma_whitespace` are used, so that
comma+whitespace sequences won't be split.
* `subitem_param_handling`: How to handle separate parameters that are specified in the presence of multiple subitems.
The possible values are {"only"} (only allow separate parameters if there aren't any subitems, otherwise throw an
error), {"first"} (store the separate parameters in the first subitem) and {"last"} (store the separate parameters
in the last subitem). The default is {"only"}. As a special case, an {{para|scN}} separate parameter will be stored
into all subitems.
* `subitem_separator_map`: Table mapping user-specified delimiters to displayed separators, stored in the `separator`
field of the subitem. If not specified, it defaults to `default_subitem_separator_map`. Note that the presence of an
item in this table does not mean that it can be used as a delimiter; only the delimiters specified using `splitchar`
are recognized. Delimiters not in this map display as-is.
6. Other fields:
* `dont_skip_items`: Normally, items that are completely unspecified (have no term and no properties) are skipped and
not inserted into the returned list of items. (Such items cannot occur if `disallow_holes = true` is set on the term
specification in the `params` structure passed to `process()` in [[Module:parameters]]. It is generally recommended
to do so unless a specific meaning is associated the term value being missing.) If `dont_skip_items` is set, however,
items are never skipped, and completely unspecified items will be returned along with others. (They will not have
the term or any properties set, but will have the normal non-property fields set; see below.)
* `stop_when`: If specified, a function to determine when to prematurely stop processing items. It is passed a single
argument, an object containing the following fields:
** `term`: The raw term, prior to parsing off language prefixes and inline modifiers (since the processing of
`stop_when` happens before parsing the term).
** `any_param_at_index`: True if any separate property parameters exist for this item.
** `orig_index`: Same as `orig_index` below.
** `itemno`: Same as `itemno` below.
** `stored_itemno`: The index where this item will be stored into the returned items table. This may differ from
`itemno` due to skipped items (it will never be different if `dont_skip_items` is set).
The function should return true to stop processing items and return the ones processed so far (not including the item
currently being processed). This is used, for example, in [[Module:alternative forms]], where an unspecified item
signal the end of items and the start of labels.
Three values are returned: the list of items; the processed `args` structure; and an object of miscellaneous computed
global values (currently only `use_semicolon`, indicating that commas were found in individual arguments and so the
default separator should be a semicolon). In each returned item, there will be one field set for each specified property
(either through inline modifiers or separate parameters). If subitems are not allowed, each item directly has fields set
on it for the specified properties. If subitems ''are'' allowed, each item contains a `terms` field, which is a list of
subitem objects, each of which has fields set on it for the specified properties of that subitem. In addition, the
following fields may be set on each item or subitem:
* `term`: The term portion of the item (minus inline modifiers and language prefixes). {nil} if no term was given.
* `orig_index`: The original index into the item in the items table returned by `process()` in [[Module:parameters]].
This may differ from `itemno` if there are raw semiclons and `disallow_custom_separators` is not given.
* `itemno`: The logical index of the item. The index of separate parameters corresponds to this index. This may be
different from `orig_index` in the presence of raw semicolons; see above.
* `termlang`: If there is a language prefix, the corresponding language object is stored here (only if
`parse_lang_prefix` is set and `allow_multiple_lang_prefixes` is not set).
* `termlangs`: If there is are language prefixes and both `parse_lang_prefix` and `allow_multiple_lang_prefixes` are
set, the list of corresponding language objects is stored here.
* `lang`: The language object of the item. This is set when either (a) there is a language prefix parsed off (if
multiple prefixes are allowed, this corresponds to the first one); (b) the `lang` property is allowed and specified;
(c) neither (a) nor (b) apply and the `lang` field of the overall `data` object is set, providing a default value.
* `sc`: The script object of the item. This is set when either (a) the `sc` property is allowed and specified; (b)
`sc` isn't otherwise set and the `sc` field of the overall `data` object is set, providing a default value.
* `delimiter`: If subitems are allowed, this is set on subitems and specifies the delimiter used prior to the given
subitem (e.g. {","}).
* `separator`: The separator to display before the item. Always set on subitems, and set on top-level items if
`disallow_custom_separators` is not given. Controlled by `special_separators` (for top-level items) and
`subitem_separator_map` (for subitems).
]==]
function export.parse_list_with_inline_modifiers_and_separate_params(data)
validate_argument_related_fields(data)
local raw_args, termarg, param_mods, args = data.raw_args, data.termarg, data.param_mods
if raw_args then
local params = data.params
local termarg_spec = params[termarg]
if termarg_spec == true or not termarg_spec.list then
internal_error("Term spec in `data.params` must have `list` set", termarg_spec)
end
if termarg_spec == true or not (termarg_spec.allow_holes or termarg_spec.disallow_holes) then
internal_error("Term spec in `data.params` must have either `allow_holes` or `disallow_holes` set",
termarg_spec)
end
export.augment_params_with_modifiers(params, param_mods)
args = process_params(raw_args, params)
else
args = data.processed_args
end
local process_args_before_parsing = data.process_args_before_parsing
if process_args_before_parsing then
process_args_before_parsing(args)
end
-- Find the maximum index among any of the list parameters.
local term_args = args[termarg]
-- As a special case, the term args might not have a `maxindex` field because they might have
-- been declared with `disallow_holes = true`, so fall back to the actual length of the list
-- using the table_len function, since # can be unpredictable with arbitrary tables.
local maxmaxindex = term_args.maxindex or table_len(term_args)
for _, v in pairs(args) do
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then
maxmaxindex = v.maxindex
end
end
local special_separators = data.special_separators or export.default_special_separators
local items, lang_cache, use_semicolon = {}, data.lang_cache or {}
local lang = fetch_argument(args, data.lang)
if lang then
lang_cache[lang:getCode()] = lang
end
local sc = fetch_argument(args, data.sc)
local term_dest = data.term_dest or "term"
-- FIXME: this is vulnerable to abusive inputs like 1000000=.
local itemno = 0
for i = 1, maxmaxindex do
local term = term_args[i]
if data.disallow_custom_separators or not special_separators[term] then
itemno = itemno + 1
-- Compute whether any of the separate indexed params exist for this index.
local any_param_at_index
for param_mod in pairs(param_mods) do
local argval = args[param_mod]
-- Careful with argument values that may be `false`.
if argval then
argval = argval[itemno]
end
if not argval_missing(argval) then
any_param_at_index = true
break
end
end
if data.stop_when and data.stop_when{
term = term,
-- FIXME, we should just pass in `any_param_at_index` directly.
any_param_at_index = term ~= nil or any_param_at_index,
orig_index = i,
itemno = itemno,
stored_itemno = #items + 1,
} then
break
end
-- If any of the params used for formatting this term is present, create a term and add it to the list.
if not data.dont_skip_items and term == nil and not any_param_at_index then
track("skipped-term", data.track_module)
else
if not term then
track("missing-term", data.track_module)
end
local termobj = {
itemno = itemno,
orig_index = i,
}
if not data.disallow_custom_separators then
termobj.separator = i == 1 and "" or special_separators[term_args[i - 1]]
end
-- Add 1 because first term index starts at 2.
local paramname = termarg + i - 1
if term then
local function generate_obj(term, parse_err)
return export.generate_obj_maybe_parsing_lang_prefix {
term = term,
termobj = data.splitchar and {} or termobj,
term_dest = term_dest,
paramname = paramname,
parse_lang_prefix = data.parse_lang_prefix,
parse_err = parse_err,
allow_bad_lang_prefix = data.allow_bad_lang_prefix,
allow_multiple_lang_prefixes = data.allow_multiple_lang_prefixes,
lang_cache = lang_cache,
}
end
parse_inline_modifiers(term, {
paramname = paramname,
param_mods = param_mods,
generate_obj = generate_obj,
splitchar = data.splitchar,
preserve_splitchar = true,
escape_fun = data.escape_fun,
unescape_fun = data.unescape_fun,
outer_container = data.splitchar and termobj or nil,
pre_normalize_modifiers = data.pre_normalize_modifiers,
})
end
local term_data = {
args = args,
param_mods = param_mods,
itemno = itemno,
termobj = termobj,
term_dest = term_dest,
has_subitems = not not data.splitchar,
lang = lang,
-- As a special case, if the caller defined a scN= separate param, set it on all subitems if there
-- are multiple, falling back to the overall sc= param.
sc = args.sc and args.sc[itemno] or sc,
subitem_param_handling = data.subitem_param_handling,
subitem_separator_map = data.subitem_separator_map or export.default_subitem_separator_map,
allow_conflicting_inline_mods_and_separate_params =
data.allow_conflicting_inline_mods_and_separate_params,
postprocess_termobj = postprocess_termobj,
disallow_custom_separators = data.disallow_custom_separators,
use_semicolon = use_semicolon,
}
copy_separate_params_to_termobj_and_postprocess(term_data)
use_semicolon = term_data.use_semicolon
insert(items, termobj)
end
end
end
if not data.disallow_custom_separators then
-- Set the default separator of all those items for which a separator wasn't explicitly given to the default
-- separator, defaulting to comma + space; but if any items have embedded commas, set the separator to
-- semicolon + space.
for _, item in ipairs(items) do
if not item.separator then
item.separator = use_semicolon and "; " or data.default_separator or ", "
end
end
end
return items, args, {use_semicolon = use_semicolon}
end
--[==[
Parse a single term that may have properties specified through inline modifiers or separate parameters. This differs
from `parse_list_with_inline_modifiers_and_separate_params()` in that the latter is for parsing a list of terms, each of
which may have properties specified through inline modifiers or separate parameters. Both functions optionally support
having multiple subitems in a single term. This function is used e.g. for form-of templates
({{tl|inflection of}}/{{tl|infl of}}, {{tl|form of}}, and specific templates such as
{{tl|alt form}}/{{tl|alternative form of}}, {{tl|abbr of}}/{{tl|abbreviation of}}, {{tl|clipping of}}, and many others);
for etymology templates ({{tl|bor}}/{{tl|borrowed}}, {{tl|der}}/{{tl|derived}}, etc. as well as `misc_variant` templates
like {{tl|ellipsis}}, {{tl|abbrev}}, {{tl|clipping}}, {{tl|reduplication}} and the like); and for other templates with
an argument structure similar to {{tl|l}} or {{tl|m}}. In these templates there is a term specified using a numeric
parameter and associated separate parameters specifying term properties such as {{para|t}} for the gloss or {{para|tr}}
for manual transliteration. All such properties can also be specified through inline modifiers attached directly to each
term (`<t:...>`, `<tr:...>`, etc.). Normally it is an error if both an inline modifier and separate parameter for the
same value are given, but this can be overridden (in which case inline modifiers take precedence over separate
parameters when both occur).
Some notable properties of this function:
# Processing of the raw frame parent args using `process()` in [[Module:parameters]] can occur either inside of this
function (the usual workflow) or outside of this function (for more complex cases). In the former case the raw parent
args are passed in along with a partially built `params` structure of the sort required by [[Module:parameters]],
containing only the term list itself along with any other parameters that are '''not''' term properties (such as
a language code in {{para|1}} and boolean flags like {{para|nocat}}, {{para|nocap}}, etc.). This structure is
''augmented'' with parameters, one for each per-term property, and [[Module:parameters]] is invoked. In the latter
case where raw argument processing is done by the caller, they must build the partial `params` structure; augment it
themselves using `augment_params_with_modifiers()`; call [[Module:parameters]] themselves; and pass in the processed
arguments. In both cases, the return value of this function contains two values, an object specifying the term and all
properties; and the processed arguments structure, so that the non-term-property arguments can be processed as
appropriate.
# Optionally, the term can consist of a number of ''subitems'' separated by delimiters (usually a comma, but the
possible delimiter or delimiters are controllable). Each subitem can have its own inline modifiers. This functionality
is used, for example, by form-of templates. When this feature is invoked, the format of the term object changes;
instead of directly being an object describing the term and its properties, it is an object with a `terms` field
containing a list of per-subitem objects along with other top-level fields describing per-term properties. By default,
if there are separate parameters specified along with multiple subitems, an error occurs, but this is controllable;
currently, you can request that the parameters be assigned to the first or last subitem.
`data` is an object containing several possible fields.
1. Fields that are required or recommended (usually related to argument processing):
* `raw_args` ('''required''' unless `processed_args` is specified): The raw arguments, normally fetched from
{frame:getParent().args}. They are parsed using `process()` in [[Module:parameters]]. Most callers pass in raw
arguments.
* `processed_args`: The object of parsed arguments returned by `process()` in [[Module:parameters]]. One (but not both)
of `raw_args` and `processed_args` must be set.
* `param_mods` ('''required'''): A structure describing the possible inline modifiers and their properties. See the
introductory comment above. Most often, this is generated using `construct_param_mods()` rather than specified
manually.
* `params` ('''required''' unless `processed_args` is specified): A structure describing the possible parameters,
'''other than''' the ones that are separate-parameter equivalents of inline modifiers. This is automatically
"augmented" with the separate-parameter equivalents of the inline modifiers described in `param_mods` prior to parsing
the raw arguments with [[Module:parameters]]. '''WARNING:''' This structure is destructively modified, both by the
"augmentation" process of adding separate-parameter equivalents of inline modifiers, and by the processing done by
[[Module:parameters]] itself. (Nonetheless, substructures can safely be shared in this structure, and will be
correctly handled.)
* `termarg` ('''required'''): The argument containing the item with attached inline modifiers to be parsed. Usually a
numeric value such as {1} or {2}.
* `track_module` ('''recommended'''): The name of the calling module, for use in adding tracking pages that are used
internally to track pages containing template invocations with certain properties.
* `lang` ('''recommended'''): The language object for the language of the item or subitems, or the name of the argument
to fetch the object from. It is not strictly necessary to specify this, as this function only initializes items based
on inline modifiers and separate arguments and doesn't actually format the resulting items. However, if specified, it
is used for certain purposes:
*# It specifies the default for the `lang` property of returned objects if not otherwise set (e.g. by a language
prefix).
*# It is used to initialize an internal cache for speeding up language-code parsing (primarily useful if the same
language code may appear in several subitems).
The value of `lang` can be any of the following:
* If a string or number, it is assumed to be requesting the value of `args` at that key. Note that if the string is in
the form of a number (e.g. "3"), it is normalized to a number prior to fetching.
* Otherwise, if a function, it is assumed to be a function to return the argument value given `args`, which is passed
to the function as its only argument.
* Otherwise, it is used directly.
* `sc` ('''recommended'''): The script object for the item or subitems, or the name of the argument to fetch the object
from. The possible values and their handling are the same as with `lang`. In general, as with `lang`, it is not
strictly necessary to specify this. However, if specified, it is used to supply the default for the `sc` property of
returned items if not otherwise set (e.g. by the {{para|sc}} parameter or `<sc:...>` inline modifier). The most common
value is {"sc"}.
* `make_separate_g_into_list`: Set this to {true} if separate gender parameters exist are are specified using
{{para|g}}, {{para|g2}}, etc. instead of using a single comma-separated {{para|g}} field.
2. Other argument-related fields:
* `adjust_params_before_arg_processing`: An optional function to further adjust the `params` structure prior to
calling `process()` in [[Module:parameters]]. This should be used when there are mismatches between the format of a
given property as an inline modifier and the corresponding property as a separate parameter (as with the {{para|g}}
parameter and {{cd|<g:...>}} modifier, but this particular case is handled by the `make_separate_g_into_list` field).
* `process_args_before_parsing`: An optional function to apply further processing to the processed `args` structure
returned by [[Module:parameters]], before parsing inline modifiers. This is passed one argument, the processed
arguments. It should make modifications in-place.
* `term_dest`: The field to store the value of the item itself into, after inline modifiers and (if allowed) language
prefixes are stripped off. Defaults to {"term"}.
* `pre_normalize_modifiers`: As in `parse_inline_modifiers()`.
* `allow_conflicting_inline_mods_and_separate_params`: If specified, don't throw an error if a value is specified for
a given property using both an inline modifier and separate param; in this case, the inline modifier takes precedence.
3. Fields related to language prefixes:
* `parse_lang_prefix`: If true, allow and parse off a language code prefix attached to items followed by a colon, such
as {la:minūtia} or {grc:[[σκῶρ|σκατός]]}. Etymology-only languages are allowed. Inline modifiers can be attached to
such items. The exact syntax allowed is as specified in the `parse_term_with_lang()` function in
[[Module:parse utilities]]. If `allow_multiple_lang_prefixes` is given, a {{cd|+}}-sign-separated list of language
prefixes can be attached to an item. The resulting language object is stored into the `termlang` field, and also into
the `lang` field (or in the case of `allow_multiple_lang_prefixes`, the list of language objects is stored into the
`termlangs` field, and the first specified object is stored in the `lang` field).
* `allow_multiple_lang_prefixes`: If given in conjunction with `parse_lang_prefix`, multiple language code prefixes can
be given, separated by a {{cd|+}} sign. See `parse_lang_prefix` above.
* `allow_bad_lang_prefix`: If given in conjunction with `parse_lang_prefix`, unrecognized language prefixes do not
trigger an error, but are simply ignored (and not stripped off the item). Note that, regardless of whether this is
given, prefixes before a colon do not trigger an error if they do not have the form of a language prefix or if a space
follows the colon. It is not recommended that this be given because typos in language prefixes will not trigger an
error and will tend to remain unfixed.
4. Fields related to multiple subitems in the term:
* `splitchar`: A Lua pattern. If specified, the user-specified argument can consist of multiple delimiter-separated
subitems, each of which may be followed by inline modifiers. In this case, the first returned value is no longer an
object describing the item, but instead an object with a `terms` field, whose value is a list describing the subitems
(whose format is the same as the normal format of the item when `splitchar` is not specified). Each subitem object
will have a `delimiter` field holding the actual delimiter occurring before the subitem, which is useful in the case
where `splitchar` matches multiple possible characters. In this case, it is possible to specify that a given modifier
can only occur after the last subitem and effectively modifies the whole collection of subitems by setting
`overall = true` on the modifier. In this case, the modifier's value will be stored in the top-level object (the
object with the `terms` field specifying the subitems). Note that splitting on delimiters will not happen in certain
protected sequences (by default comma+whitespace; see below). In addition, the algorithm to split on delimiters is
sensitive to inline modifier syntax and will not be confused by delimiters inside of inline modifiers or inside of
square brackets, which do not trigger splitting (whether or not contained within protected sequences).
* `escape_fun` and `unescape_fun`: As in `split_escaping()` and `split_alternating_runs_escaping()` in
[[Module:parse utilities]]. They control the protected sequences that won't be split when `splitchar` is specified
(see previous item). By default, `escape_comma_whitespace` and `unescape_comma_whitespace` are used, so that
comma+whitespace sequences won't be split.
* `subitem_param_handling`: How to handle separate parameters that are specified in the presence of multiple subitems.
The possible values are {"only"} (only allow separate parameters if there aren't any subitems, otherwise throw an
error), {"first"} (store the separate parameters in the first subitem) and {"last"} (store the separate parameters
in the last subitem). The default is {"only"}. As a special case, an {{para|scN}} separate parameter will be stored
into all subitems.
* `subitem_separator_map`: Table mapping user-specified delimiters to displayed separators, stored in the `separator`
field of the subitem. If not specified, it defaults to `default_subitem_separator_map`. Note that the presence of an
item in this table does not mean that it can be used as a delimiter; only the delimiters specified using `splitchar`
are recognized. Delimiters not in this map display as-is.
Two values are returned, an object describing the item (or subitems) and the processed `args` structure. In the returned
item, there will be one field set for each specified property (either through inline modifiers or separate parameters).
If subitems are not allowed, the item directly has fields set on it for the specified properties. If subitems ''are''
allowed, the item contains a `terms` field, which is a list of subitem objects, each of which has fields set on it for
the specified properties of that subitem. In addition, the following fields may be set on the item or each subitem:
* `term`: The term portion of the item (minus inline modifiers and language prefixes). {nil} if no term was given.
* `termlang`: If there is a language prefix, the corresponding language object is stored here (only if
`parse_lang_prefix` is set and `allow_multiple_lang_prefixes` is not set).
* `termlangs`: If there is are language prefixes and both `parse_lang_prefix` and `allow_multiple_lang_prefixes` are
set, the list of corresponding language objects is stored here.
* `lang`: The language object of the item. This is set when either (a) there is a language prefix parsed off (if
multiple prefixes are allowed, this corresponds to the first one); (b) the `lang` property is allowed and specified;
(c) neither (a) nor (b) apply and the `lang` field of the overall `data` object is set, providing a default value.
* `sc`: The script object of the item. This is set when either (a) the `sc` property is allowed and specified; (b)
`sc` isn't otherwise set and the `sc` field of the overall `data` object is set, providing a default value.
* `delimiter`: If subitems are allowed, this specifies the delimiter used prior to the given subitem (e.g. {","}).
* `separator`: If subitems are allowed, this specifies the displayed form of the delimiter to be shown before a given
subitem. The mapping from user-specified delimiters to displayed separators is handled by `subitem_separator_map`;
see above. The first subitem always has a blank string in the `separator` field.
]==]
function export.parse_term_with_inline_modifiers_and_separate_params(data)
validate_argument_related_fields(data)
local raw_args, termarg, param_mods, args = data.raw_args, data.termarg, data.param_mods
if raw_args then
local params = data.params
local termarg_spec = params[termarg]
if type(termarg_spec) == "table" and termarg_spec.list then
internal_error("Term spec in `data.params` must not have `list` set", termarg_spec)
end
export.augment_params_with_modifiers(params, param_mods, "always")
if data.make_separate_g_into_list then
-- HACK: g= is a list for compatibility, but sublist as an inline parameter.
params.g = {list = true, item_dest = "genders", type = "genders", flatten = true}
end
local adjust_params_before_arg_processing = data.adjust_params_before_arg_processing
if adjust_params_before_arg_processing then
adjust_params_before_arg_processing(params)
end
args = process_params(raw_args, params)
else
args = data.processed_args
end
local process_args_before_parsing = data.process_args_before_parsing
if process_args_before_parsing then
process_args_before_parsing(args)
end
local term, lang_cache = args[termarg], data.lang_cache
local lang = fetch_argument(args, data.lang)
if lang and lang_cache then
lang_cache[lang:getCode()] = lang
end
local sc = fetch_argument(args, data.sc)
local term_dest = data.term_dest or "term"
if not term then
track("missing-term", data.track_module)
end
local termobj, splitchar = {}, data.splitchar
if term then
local function generate_obj(term, parse_err)
return export.generate_obj_maybe_parsing_lang_prefix {
term = term,
termobj = splitchar and {} or termobj,
term_dest = term_dest,
paramname = termarg,
parse_lang_prefix = data.parse_lang_prefix,
parse_err = parse_err,
allow_bad_lang_prefix = data.allow_bad_lang_prefix,
allow_multiple_lang_prefixes = data.allow_multiple_lang_prefixes,
lang_cache = lang_cache,
}
end
parse_inline_modifiers(term, {
paramname = termarg,
param_mods = param_mods,
generate_obj = generate_obj,
splitchar = splitchar,
preserve_splitchar = true,
escape_fun = data.escape_fun,
unescape_fun = data.unescape_fun,
outer_container = splitchar and termobj or nil,
pre_normalize_modifiers = data.pre_normalize_modifiers,
})
end
copy_separate_params_to_termobj_and_postprocess{
args = args,
param_mods = param_mods,
termobj = termobj,
has_subitems = not not splitchar,
lang = lang,
sc = sc,
subitem_param_handling = data.subitem_param_handling,
subitem_separator_map = data.subitem_separator_map or export.default_subitem_separator_map,
allow_conflicting_inline_mods_and_separate_params = data.allow_conflicting_inline_mods_and_separate_params,
}
if splitchar and termobj.terms[2] then
track("parse-term-multiple-subitems", data.track_module)
track("parse-term-multiple-subitems")
end
return termobj, args
end
return export
ood13bkqgv139ip1rcvw68r9hr5w6hh
Buchhandlung
0
1843959
5724497
4919307
2026-06-10T07:02:23Z
OctraBot
3198
5724497
wikitext
text/x-wiki
== ภาษาเยอรมัน ==
=== รากศัพท์ ===
{{compound|de|Buch|Handlung}}
=== การออกเสียง ===
* {{IPA|de|/ˈbuːxˌhandlʊŋ/}}
* {{audio|de|De-Buchhandlung.ogg|a=Germany}}
=== คำนาม ===
{{de-noun|f}}
# [[ร้าน]][[หนังสือ]]
#: {{syn|de|Buchladen<g:m>}}
==== การผันรูป ====
{{de-ndecl|f}}
=== อ่านเพิ่ม ===
* {{R:de:Duden}}
* {{R:de:DWDS}}
{{C|de|หนังสือ|อาคาร|กิจการ}}
24ch96mkdkw9odzmz6t6am2e1ykrkx1
Buchladen
0
1843960
5724496
5415087
2026-06-10T07:02:15Z
OctraBot
3198
5724496
wikitext
text/x-wiki
{{also/auto}}
== ภาษาเยอรมัน ==
=== รากศัพท์ ===
{{compound|de|Buch|Laden}}
=== การออกเสียง ===
* {{IPA|de|/ˈbuːxˌlaːdn̩/|/ˈbuːxˌlaːdən/}}
* {{audio|de|De-Buchladen.ogg|a=Germany}}
=== คำนาม ===
{{de-noun|m,,^}}
# {{lb|de|colloquial}} [[ร้าน]][[หนังสือ]]
#: {{syn|de|Buchhandlung<g:f>}}
==== การผันรูป ====
{{de-ndecl|m,,^}}
==== คำเกี่ยวข้อง ====
{{col|de
|Buchhändler
|Bücherabteilung
|Buchhandel
|Buchverkauf
|Obstladen
|Gemüseladen
|Lebensmittelladen
|Bauchladen
|Plattenladen
|Metallwarenladen
|Haushaltswarenladen
}}
=== อ่านเพิ่ม ===
* {{R:de:DWDS}}
* {{R:de:UniLeipzig}}
* {{R:de:Duden}}
* {{pedia|lang=de}}
{{C|de|หนังสือ|อาคาร|กิจการ}}
gju86ha23s5biph7ud9t620nvsda8m0
fabrika
0
1857987
5724495
5723637
2026-06-10T07:02:08Z
OctraBot
3198
5724495
wikitext
text/x-wiki
== ภาษาคาชุบ ==
=== รูปแบบอื่น ===
* {{alt|csb|fabrëka}}
=== รากศัพท์ ===
{{dercat|csb|la}}
{{bor+|csb|pl|fabryka}}
=== การออกเสียง ===
{{csb-pr|fa'brika,^fabrika}}
=== คำนาม ===
{{csb-noun|f|dim=fabriczka|adj=fabriczny}}
# [[โรงงาน]], [[โรง]][[ผลิต]]
==== ลูกคำ ====
{{col|csb|title=nouns|fabricznik|fabrikant|fabrikantka}}
{{csb-derived verbs|impf_first=1|fabrikowac/sfabrikòwac|-/nafabrikòwac|-/prefabrikòwac}}
==== คำเกี่ยวข้อง ====
{{col|csb|title=adjectives|fabrikancczi}}
{{col|csb|title=adverbs|fabriczno}}
{{col|csb|title=nouns|fabriczuszka|fabrikat}}
=== อ่านเพิ่ม ===
* {{R:csb:Sychta:1967||21|1}}
* {{R:csb:Trepczyk:1994|fabryka}}
* {{R:csb:SPK|fabryka}}
{{C|csb|อาคาร}}
== ภาษาเช็ก ==
=== รากศัพท์ ===
{{bor+|cs|de|Fabrik}}, จาก{{der|cs|la|fābrica}} หรือ{{der|cs|fr|fabrique}}
=== การออกเสียง ===
* {{cs-IPA}}
=== คำนาม ===
{{cs-noun|f|dim=fabrička}}
# {{lb|cs|informal}} [[โรงงาน]], [[โรง]][[ผลิต]]
#: {{syn|cs|továrna|závod}}
==== การผันรูป ====
{{cs-ndecl|f}}
==== คำเกี่ยวข้อง ====
{{col|cs|title=adjectives|fabrický|fabriční}}
=== อ่านเพิ่ม ===
* {{R:cs:PSJC}}
* {{R:cs:SSJC}}
* {{R:cs:IJP}}
== ภาษาซอร์เบียตอนล่าง ==
=== รากศัพท์ ===
{{bor+|dsb|de|Fabrik}}, จาก{{der|dsb|la|fabrica}}
=== การออกเสียง ===
{{dsb-pr}}
=== คำนาม ===
{{dsb-noun|f}}
# [[โรงงาน]], [[โรง]][[ผลิต]]
==== การผันรูป ====
{{dsb-decl-noun-3|fabri|k}}
=== อ่านเพิ่ม ===
* {{R:dsb:Muka}}
* {{R:dsb:Starosta}}
{{topics|dsb|อาคาร|Manufacturing}}
== ภาษาเซอร์โบ-โครเอเชีย ==
{{wp|lang=sh}}
=== รากศัพท์ ===
{{bor+|sh|de|Fabrik}}, หรือ{{bor|sh|la|fabrica}}
=== การออกเสียง ===
* {{sh-IPA|fàbrika}}
* {{hyphenation|sh|fab|ri|ka}}
=== คำนาม ===
{{sh-noun|fàbrika|f}}
# {{lb|sh|บอสเนีย|เซอร์เบีย}} [[โรงงาน]], [[โรง]][[ผลิต]]
#: {{syn|sh|tvórnica|q1=โครเอเชีย}}
==== การผันรูป ====
{{sh-decl-noun
|fabrika|fabrike
|fabrike|fabrika
|fabrici|fabrikama
|fabriku|fabrike
|fabriko|fabrike
|fabrici|fabrikama
|fabrikom|fabrikama
}}
=== ดูเพิ่ม ===
* {{l|sh|tvrtka}}
=== อ่านเพิ่ม ===
* {{R:sh:HJP|fFtgXhM%3D}}
{{C|sh|อาคาร|กิจการ}}
== ภาษาตุรกี ==
=== รากศัพท์ ===
จาก{{inh|tr|ota|فابریقه|tr=fabrika|gloss=โรงงาน}}, จาก{{der|tr|it|fabbrica}}
=== การออกเสียง ===
* {{audio|tr|LL-Q256 (tur)-ToprakM-fabrika.wav}}
=== คำนาม ===
{{tr-noun|yı|lar}}
# [[โรงงาน]], [[โรง]][[ผลิต]]
==== การผันรูป ====
{{tr-infl-noun-v|a}}
=== อ้างอิง ===
* {{R:ota:Redhouse|فابریقه|page=1358}}
== ภาษาลัตเวีย ==
=== คำนาม ===
{{lv-noun|f|4th}}
# [[โรงงาน]], [[โรง]][[ผลิต]]
#: {{syn|lv|rūpnīca}}
==== การผันรูป ====
{{lv-decl-noun|fabrik|a|4th|extrawidth=-60}}
{{topics|lv|อาคาร}}
== ภาษาลาดิโน ==
=== รูปแบบอื่น ===
* {{alter|lad|fábrika}}
=== รากศัพท์ 1 ===
ร่วมเชื้อสายกับ{{cog|es|fábrica}}
==== คำนาม ====
{{lad-noun|g=f|heb=פ׳אבריקה}}<ref name="Folkmasa">{{R:lad:Folkmasa}}</ref>
# [[โรงงาน]], [[โรง]][[ผลิต]]
#: {{hypo|lad|rafinería|vidrería}}
#* {{quote-book|lad|author=Enrique Saporta y Beja|title=En torno de la torre blanca|url=https://books.google.com/books?id=660dAQAAIAAJ|publisher=Editions Vidas Largas
|year=1982|page=141|pageurl=https://books.google.com/books?id=660dAQAAIAAJ&q=fabrika|text=La kuzina estava buyendo de la kalor de los odjakes i de la fornaya. Paresia una '''fabrika''' de komanya.|t=The kitchen was boiling from the heat of the shoves and the fireplaces. It looked like a food '''factory'''.}}
=== รากศัพท์ 2 ===
{{nonlemma}}
==== คำกริยา ====
{{head|lad|รูปกริยา}}
# {{inflection of|lad|fabrikar||3|s|pres|ind}}
# {{inflection of|lad|fabrikar||2|s|pres|imp}}
=== อ้างอิง ===
<references/>
{{C|lad|อาคาร}}
== ภาษาอุซเบก ==
{{wp|lang=uz}}
=== รากศัพท์ ===
{{bor+|uz|ru|фа́брика}}, จาก{{der|uz|la|fabrica}}
=== คำนาม ===
{{uz-noun}}
# [[โรงงาน]], [[โรง]][[ผลิต]], [[โรงสี]]
#: {{syn|uz|zavod}}
==== การผันรูป ====
{{uz-decl-noun}}
==== คำเกี่ยวข้อง ====
* {{l|uz|fabrikant}}
* {{l|uz|fabrikat}}
{{c|uz|อาคาร}}
== ภาษาแอลเบเนีย ==
=== คำนาม ===
{{head|sq|รูปนาม}}
# {{inflection of|sq|fabrikë||def|nom|s|;|indef|nom//acc|p}}
ffmhj4s3ngafsah23kkv9n4l1mrxk99
แม่แบบ:U:es:unadapted
10
2306777
5724481
5663191
2026-06-10T06:47:34Z
OctraBot
3198
5724481
wikitext
text/x-wiki
ตามข้อกำหนดของ {{w|Royal Spanish Academy|ราชบัณฑิตยสถานสเปน}} (RAE) คำศัพท์ต่างประเทศที่ไม่ดัดแปลงควรเขียนด้วยตัวเอนในข้อความที่พิมพ์ด้วยตัวพิมพ์ปกติ และในทางกลับกัน และควรใส่เครื่องหมายอัญประกาศในข้อความที่เขียนด้วยลายมือหรือเมื่อไม่มีตัวเอนให้ใช้ ในทางปฏิบัติ ข้อกำหนดของ RAE นี้ไม่ได้ถูกปฏิบัติตามเสมอไป<!--
--><noinclude>{{documentation}}</noinclude>
aeyz7il021zyuv78jaex5qzxrf68msq
5724482
5724481
2026-06-10T06:47:44Z
OctraBot
3198
5724482
wikitext
text/x-wiki
ตามข้อกำหนดของ{{w|Royal Spanish Academy|ราชบัณฑิตยสถานสเปน}} (RAE) คำศัพท์ต่างประเทศที่ไม่ดัดแปลงควรเขียนด้วยตัวเอนในข้อความที่พิมพ์ด้วยตัวพิมพ์ปกติ และในทางกลับกัน และควรใส่เครื่องหมายอัญประกาศในข้อความที่เขียนด้วยลายมือหรือเมื่อไม่มีตัวเอนให้ใช้ ในทางปฏิบัติ ข้อกำหนดของ RAE นี้ไม่ได้ถูกปฏิบัติตามเสมอไป<!--
--><noinclude>{{documentation}}</noinclude>
7kx9lylj0alry1zfs7o6gat9m26vy63
5724483
5724482
2026-06-10T06:48:33Z
OctraBot
3198
5724483
wikitext
text/x-wiki
ตามข้อกำหนดของ {{w|Royal Spanish Academy}} (RAE) คำศัพท์ต่างประเทศที่ไม่ดัดแปลงควรเขียนด้วยตัวเอนในข้อความที่พิมพ์ด้วยตัวพิมพ์ปกติ และในทางกลับกัน และควรใส่เครื่องหมายอัญประกาศในข้อความที่เขียนด้วยลายมือหรือเมื่อไม่มีตัวเอนให้ใช้ ในทางปฏิบัติ ข้อกำหนดของ RAE นี้ไม่ได้ถูกปฏิบัติตามเสมอไป<!--
--><noinclude>{{documentation}}</noinclude>
8w6aedoc3karbsasiudt3ariby40fbz
ไนต์คลับ
0
2331679
5724437
2026-06-09T13:38:36Z
Mawyuri
18975
สร้างหน้าด้วย "==ภาษาไทย== {{wp}} ===รากศัพท์=== {{bor+|th|en|night club}} ===อ่านออกเสียง=== {{th-pron|ไน้-ขฺลับ}} ===คำนาม=== {{th-noun}} # {{lb|th|colloquial}} [[สถานบันเทิง]]ที่[[เปิด]]ในเวลา[[กลางคืน]]เพื่อการ[[สังสรรค์]]และ[[เต้น]][[รำ]] #: {{syn|th|คลับ}}"
5724437
wikitext
text/x-wiki
==ภาษาไทย==
{{wp}}
===รากศัพท์===
{{bor+|th|en|night club}}
===อ่านออกเสียง===
{{th-pron|ไน้-ขฺลับ}}
===คำนาม===
{{th-noun}}
# {{lb|th|colloquial}} [[สถานบันเทิง]]ที่[[เปิด]]ในเวลา[[กลางคืน]]เพื่อการ[[สังสรรค์]]และ[[เต้น]][[รำ]]
#: {{syn|th|คลับ}}
7j4qqayz2jv4zrxptl5ce0qx3uscjcq
5724440
5724437
2026-06-09T13:43:52Z
Mawyuri
18975
/* รากศัพท์ */ Use non-redlink
5724440
wikitext
text/x-wiki
==ภาษาไทย==
{{wp}}
===รากศัพท์===
{{bor+|th|en|nightclub}}
===อ่านออกเสียง===
{{th-pron|ไน้-ขฺลับ}}
===คำนาม===
{{th-noun}}
# {{lb|th|colloquial}} [[สถานบันเทิง]]ที่[[เปิด]]ในเวลา[[กลางคืน]]เพื่อการ[[สังสรรค์]]และ[[เต้น]][[รำ]]
#: {{syn|th|คลับ}}
hd027jgq9zuxn1ecd2dgpnz8it70sz7
5724490
5724440
2026-06-10T06:56:39Z
OctraBot
3198
5724490
wikitext
text/x-wiki
== ภาษาไทย ==
{{wp}}
=== รากศัพท์ ===
{{bor+|th|en|night club}}
=== อ่านออกเสียง ===
{{th-pron|ไน้-ขฺลับ}}
=== คำนาม ===
{{th-noun}}
# {{lb|th|colloquial}} [[สถานบันเทิง]]ที่[[เปิด]]ในเวลา[[กลางคืน]]เพื่อการ[[สังสรรค์]]และ[[เต้นรำ]]
#: {{syn|th|คลับ}}
24eqai95ywfbmdec8prj46uog7pi239
คลับ
0
2331680
5724438
2026-06-09T13:41:40Z
Mawyuri
18975
สร้างหน้าด้วย "==ภาษาไทย== ===รากศัพท์=== {{bor+|th|en|club}} ===อ่านออกเสียง=== {{th-pron|ขฺลับ}} ===คำนาม=== {{th-noun}} # {{lb|th|colloquial}} [[ชมรม]], [[สโมสร]] # {{lb|th|colloquial}} [[ไนต์คลับ]]"
5724438
wikitext
text/x-wiki
==ภาษาไทย==
===รากศัพท์===
{{bor+|th|en|club}}
===อ่านออกเสียง===
{{th-pron|ขฺลับ}}
===คำนาม===
{{th-noun}}
# {{lb|th|colloquial}} [[ชมรม]], [[สโมสร]]
# {{lb|th|colloquial}} [[ไนต์คลับ]]
ogaostl4mngo2oo2tei27kiqibd3rit
คุยกับผู้ใช้:บังอร หังษาบุตร
3
2331681
5724441
2026-06-10T00:30:37Z
New user message
2698
เพิ่ม[[Template:Welcome|สารต้อนรับ]]ในหน้าคุยของผู้ใช้ใหม่
5724441
wikitext
text/x-wiki
{{Template:Welcome|realName=|name=บังอร หังษาบุตร}}
-- [[ผู้ใช้:New user message|New user message]] ([[คุยกับผู้ใช้:New user message|คุย]]) 07:30, 10 มิถุนายน 2569 (+07)
mlsy3z87ypy00oy5ypxddhv2pp71lsp
二ヶ月
0
2331682
5724442
2026-06-10T02:26:35Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724442
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|に|げつ|yomi=goon,kanon|alt=二箇月}}
=== รากศัพท์ ===
{{ja-compound|二|に|t1=สอง|ヶ|か|pos2=รูปง่ายของ {{ja-r|箇|か}}, คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|にかげつ|acc=2}}
=== คำนาม ===
{{ja-noun|にかげつ}}
# [[สอง]][[เดือน]] {{gl|ระยะเวลา}}
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
i7i1n070hc3nq97y4tok7hcs1gov2lk
มอดูล:ja-counter-table
828
2331683
5724443
2026-06-10T02:28:05Z
OctraBot
3198
สร้างหน้าด้วย "local export = {} local ja_numeral = require("Module:ja-numeral").convert local kana_to_romaji = require("Module:Hrkt-translit").tr local tag_text = require("Module:script utilities").tag_text local full_link = require("Module:links").full_link local embedded_language_links = require("Module:links").embedded_language_links local lang_en = require("Module:languages").getByCode("en") local lang_ja = require("Module:languages").getByCode("ja") local s..."
5724443
Scribunto
text/plain
local export = {}
local ja_numeral = require("Module:ja-numeral").convert
local kana_to_romaji = require("Module:Hrkt-translit").tr
local tag_text = require("Module:script utilities").tag_text
local full_link = require("Module:links").full_link
local embedded_language_links = require("Module:links").embedded_language_links
local lang_en = require("Module:languages").getByCode("en")
local lang_ja = require("Module:languages").getByCode("ja")
local sc = require("Module:scripts").getByCode("Latn")
local sc_ja = require("Module:scripts").getByCode("ja")
local FULLPAGENAME = mw.title.getCurrentTitle().prefixedText
local is_template_page_display = false
if string.match(FULLPAGENAME, "^Template:") then
is_template_page_display = true
end
local function tag_text_en(text)
return tag_text(embedded_language_links{term = text, lang = lang_en, sc = sc}, lang_en, sc)
end
local function tag_text_ja(text)
return tag_text(embedded_language_links{term = text, lang = lang_ja, sc = sc}, lang_ja, sc_ja)
end
local function mention_ja(text, t, tr, pos)
return full_link({lang = lang_ja, sc = sc_ja, track_sc = true,
term = text, show_qualifiers = true, gloss = t, tr = tr, pos = pos})
end
local function mention_or_link(text)
local title = mw.title.new(text)
if title and title.exists then
return mention_ja(text)
else
return tag_text_ja(text)
end
end
local function format_number(number)
local str = tostring(number)
if str == nil or str == "" or not string.match(str, "^%d+$") then
return str
end
local result = ""
local strlen = string.len(str)
for i = 0, math.floor(strlen / 3) - 1 do
result = "," .. string.sub(str, strlen - (i * 3) - 2, strlen - (i * 3)) .. result
end
if strlen % 3 == 0 then
result = string.sub(result, 2, string.len(result))
else
result = string.sub(str, 1, strlen % 3) .. result
end
return result
end
local function _counter_table(counter_lemma, counter_kana, content, counter_t, counter_pos, title, make_navbar_func, is_acc_style, auto_gen)
if content[1] == nil then
error("Zero rows")
end
local no_heading = false
local m_ja_pron
if is_acc_style then
no_heading = true
m_ja_pron = require("Module:ja-pron")
end
local output = mw.html.create("table")
:addClass("wikitable")
:attr("style", "border: 1px "
.. "solid #AAAAAA; border-collapse:collapse;")
:attr("cellpadding", "3")
:attr("rules", "all")
if (not no_heading) then
local headertr = mw.html.create("tr")
output:node(headertr)
local headerth = mw.html.create("th")
:attr("align", "center")
:attr("colspan", "4")
headertr:node(headerth)
local headertitlediv = mw.html.create("div")
if title ~= nil then
if title ~= "" then
headertitlediv:wikitext(title)
end
else
headertitlediv:wikitext("Japanese counter/suffix")
local m_entry, m_t, m_tr, m_pos
if counter_lemma ~= nil and counter_lemma ~= "" then
m_entry = counter_lemma
end
if counter_t ~= nil and counter_t ~= "" then
m_t = counter_t
end
if counter_kana ~= nil and counter_kana ~= "" then
if counter_lemma == counter_kana then
m_tr = kana_to_romaji(counter_kana)
else
m_tr = counter_kana .. ", " .. kana_to_romaji(counter_kana)
end
end
if counter_pos ~= nil and counter_pos ~= "" then
m_pos = counter_pos
end
if (m_entry ~= nil) or (m_t ~= nil) or (m_tr ~= nil) or (m_pos ~= nil) then
headertitlediv:wikitext(": ")
headertitlediv:wikitext(tag_text_en(mention_ja(m_entry, m_t, m_tr, m_pos)))
end
end
if make_navbar_func then
local navbar = make_navbar_func()
if navbar and navbar ~= "" then
local headernavbardiv = mw.html.create("div")
headernavbardiv:attr("style", 'float:left; width:6em;text-align:left;')
headernavbardiv:wikitext(navbar)
headerth:node(headernavbardiv)
end
end
headerth:node(headertitlediv)
end
if content[1] ~= nil then
if content[1] ~= "-" then
error('Argument 1 must be single hyphen "-"')
end
if (not no_heading) then
local subheadertr = mw.html.create("tr")
local numberth = mw.html.create("th")
numberth:wikitext(tag_text_en("[[number|Number]]"))
subheadertr:node(numberth)
local kanjith = mw.html.create("th")
kanjith:wikitext(tag_text_en("[[kanji|Kanji]]"))
subheadertr:node(kanjith)
local kanath = mw.html.create("th")
kanath:wikitext(tag_text_en("[[kana|Kana]]"))
subheadertr:node(kanath)
local romajith = mw.html.create("th")
romajith:wikitext(tag_text_en("[[romaji|Romaji]]"))
subheadertr:node(romajith)
output:node(subheadertr)
end
end
if counter_lemma == nil then
counter_lemma = ""
end
if counter_kana == nil then
counter_kana = ""
end
local rows = {}
do
local i = 1
while true do
if content[i] == nil then
break
end
local number = content[i + 1]
local kanjis_begin = i + 2
local kanjis_end = i + 2
while true do
local kanji = content[kanjis_end]
if kanji == nil or kanji == "-" then
break
end
kanjis_end = kanjis_end + 1
end
local n_kanjis = kanjis_end - kanjis_begin
local readings_begin = kanjis_end + 1
local readings_end = kanjis_end + 1
while true do
local reading = content[readings_end]
if reading == nil or reading == "-" then
break
end
readings_end = readings_end + 1
end
local n_readings = readings_end - readings_begin
local kanjis = {}
if n_kanjis == 0 and number == "?" then
table.insert(kanjis, "何" .. counter_lemma)
elseif n_kanjis == 0 and number == "1000" then
table.insert(kanjis, "千" .. counter_lemma)
table.insert(kanjis, "*一千" .. counter_lemma)
elseif n_kanjis == 0 and string.match(number, "^%d+$") then
if tonumber(number) == 0 then
table.insert(kanjis, "0" .. counter_lemma)
table.insert(kanjis, "零" .. counter_lemma)
else
local numeral = ja_numeral(number)
table.insert(kanjis, numeral .. counter_lemma)
end
elseif n_kanjis > 0 then
for kanji_i = kanjis_begin, kanjis_end - 1 do
local kanji = content[kanji_i]
if kanji ~= "" then
table.insert(kanjis, kanji)
end
end
end
local lemmas = {}
for j = 1, #kanjis do
local kanji = kanjis[j]
local asterisk = false
if string.match(kanji, "^%*") then
asterisk = true
kanji = string.gsub(kanji, "^%*", "")
end
table.insert(lemmas, { kanji = kanji, asterisk = asterisk })
end
local readings = {}
for reading_i = readings_begin, readings_end - 1 do
local reading = content[reading_i]
local asterisk = false
if string.match(reading, "^%*") then
asterisk = true
reading = string.gsub(reading, "^%*", "")
end
if (not is_acc_style) then
table.insert(readings, {kana = reading, asterisk = asterisk})
else
local inline_pattern = "([^<%. ]+)<%s*acc%s*:%s*(.-)%s*>"
if string.match(reading, inline_pattern) then
local kana = string.gsub(reading, inline_pattern, "%1")
local acc = string.gsub(reading, inline_pattern, "%2")
table.insert(readings, {kana = kana, asterisk = asterisk, acc = acc})
else
error("acc is required for readings in acc_counter_table")
end
end
end
table.insert(rows, {number = number, lemmas = lemmas, readings = readings})
i = readings_end
end
end
for _, row in ipairs(rows) do
local number = row.number
local lemmas = row.lemmas
local readings = row.readings
local rowtr = mw.html.create("tr")
local numbertd = mw.html.create("td")
numbertd:attr("align", "right")
if number ~= nil and number ~= "" then
local formatted_number = format_number(number)
numbertd:wikitext(formatted_number)
end
rowtr:node(numbertd)
local kanjitd = mw.html.create("td")
kanjitd:attr("align", "center")
for i, lemma in ipairs(lemmas) do
local kanji = lemma.kanji
if lemma.asterisk then
kanji = string.gsub(kanji, "^%*", "")
kanjitd:wikitext("<sup>*</sup>")
end
kanjitd:wikitext(mention_or_link(kanji))
if i ~= #lemmas then
kanjitd:wikitext(", ")
end
end
rowtr:node(kanjitd)
local kanatd = mw.html.create("td")
local romajitd = mw.html.create("td")
if (not is_acc_style) then
kanatd:attr("align", "center")
romajitd:attr("align", "center")
end
for i, reading in ipairs(readings) do
if reading.asterisk then
if (not is_acc_style) then
kanatd:wikitext("<sup>*</sup>")
end
romajitd:wikitext("*")
end
if (not is_acc_style) then
kanatd:wikitext(tag_text_ja(reading.kana))
local romaji = kana_to_romaji(reading.kana)
romajitd:wikitext(romaji)
if i ~= #readings then
kanatd:wikitext(", ")
romajitd:wikitext(", ")
end
else
local ja_pron_acc, ja_pron_romaji = string.match(m_ja_pron.accent(reading.kana, reading.acc), '(<span lang="ja" class="Jpan">.-) (<span class="Latn"><samp>.-</samp></span>)')
kanatd:wikitext(ja_pron_acc)
romajitd:wikitext(ja_pron_romaji)
if i ~= #readings then
kanatd:wikitext("<br>")
romajitd:wikitext("<br>")
end
end
end
rowtr:node(kanatd)
rowtr:node(romajitd)
output:node(rowtr)
end
if (#rows > 14) and (not no_heading) then
output = mw.html.create("div")
:node(output)
:addClass("list-switcher")
:attr("style", "min-height:18em;")
:attr("data-toggle-category", "counter")
output = mw.html.create("div")
:addClass("list-switcher-wrapper")
:attr("style", "width: fit-content;")
:node(output)
end
return tostring(output)
end
function export.show(frame)
local params = {
[1] = { required=true, allow_empty=true, list=true },
["lemma"] = { },
["kana"] = { },
["t"] = { },
["pos"] = { },
["tl"] = { },
["title"] = { },
["auto_gen"] = { type="boolean" }
}
local args = require("Module:parameters").process(frame.args, params)
local template_name = args["tl"]
local make_navbar_func
if template_name and template_name ~= "" then
make_navbar_func = function()
return frame:expandTemplate{title="Navbar", args={template_name, mini = "y"}}
end
end
return _counter_table(args["lemma"], args["kana"], args[1], args["t"], args["pos"], args["title"], make_navbar_func, false, args["auto_gen"])
end
function export.acc_counter_table(counter_lemma, counter_kana, content, auto_gen)
return _counter_table(counter_lemma, counter_kana, content, nil, nil, nil, nil, true, auto_gen)
end
return export
m4eyusv2qx3eeb3h44gd4educ4zlt79
5724444
5724443
2026-06-10T02:28:36Z
OctraBot
3198
5724444
Scribunto
text/plain
local export = {}
local ja_numeral = require("Module:ja-numeral").convert
local kana_to_romaji = require("Module:Hrkt-translit").tr
local tag_text = require("Module:script utilities").tag_text
local full_link = require("Module:links").full_link
local embedded_language_links = require("Module:links").embedded_language_links
local lang_en = require("Module:languages").getByCode("en")
local lang_ja = require("Module:languages").getByCode("ja")
local sc = require("Module:scripts").getByCode("Latn")
local sc_ja = require("Module:scripts").getByCode("ja")
local FULLPAGENAME = mw.title.getCurrentTitle().prefixedText
local is_template_page_display = false
if string.match(FULLPAGENAME, "^แม่แบบ:") then
is_template_page_display = true
end
local function tag_text_en(text)
return tag_text(embedded_language_links{term = text, lang = lang_en, sc = sc}, lang_en, sc)
end
local function tag_text_ja(text)
return tag_text(embedded_language_links{term = text, lang = lang_ja, sc = sc}, lang_ja, sc_ja)
end
local function mention_ja(text, t, tr, pos)
return full_link({lang = lang_ja, sc = sc_ja, track_sc = true,
term = text, show_qualifiers = true, gloss = t, tr = tr, pos = pos})
end
local function mention_or_link(text)
local title = mw.title.new(text)
if title and title.exists then
return mention_ja(text)
else
return tag_text_ja(text)
end
end
local function format_number(number)
local str = tostring(number)
if str == nil or str == "" or not string.match(str, "^%d+$") then
return str
end
local result = ""
local strlen = string.len(str)
for i = 0, math.floor(strlen / 3) - 1 do
result = "," .. string.sub(str, strlen - (i * 3) - 2, strlen - (i * 3)) .. result
end
if strlen % 3 == 0 then
result = string.sub(result, 2, string.len(result))
else
result = string.sub(str, 1, strlen % 3) .. result
end
return result
end
local function _counter_table(counter_lemma, counter_kana, content, counter_t, counter_pos, title, make_navbar_func, is_acc_style, auto_gen)
if content[1] == nil then
error("Zero rows")
end
local no_heading = false
local m_ja_pron
if is_acc_style then
no_heading = true
m_ja_pron = require("Module:ja-pron")
end
local output = mw.html.create("table")
:addClass("wikitable")
:attr("style", "border: 1px "
.. "solid #AAAAAA; border-collapse:collapse;")
:attr("cellpadding", "3")
:attr("rules", "all")
if (not no_heading) then
local headertr = mw.html.create("tr")
output:node(headertr)
local headerth = mw.html.create("th")
:attr("align", "center")
:attr("colspan", "4")
headertr:node(headerth)
local headertitlediv = mw.html.create("div")
if title ~= nil then
if title ~= "" then
headertitlediv:wikitext(title)
end
else
headertitlediv:wikitext("Japanese counter/suffix")
local m_entry, m_t, m_tr, m_pos
if counter_lemma ~= nil and counter_lemma ~= "" then
m_entry = counter_lemma
end
if counter_t ~= nil and counter_t ~= "" then
m_t = counter_t
end
if counter_kana ~= nil and counter_kana ~= "" then
if counter_lemma == counter_kana then
m_tr = kana_to_romaji(counter_kana)
else
m_tr = counter_kana .. ", " .. kana_to_romaji(counter_kana)
end
end
if counter_pos ~= nil and counter_pos ~= "" then
m_pos = counter_pos
end
if (m_entry ~= nil) or (m_t ~= nil) or (m_tr ~= nil) or (m_pos ~= nil) then
headertitlediv:wikitext(": ")
headertitlediv:wikitext(tag_text_en(mention_ja(m_entry, m_t, m_tr, m_pos)))
end
end
if make_navbar_func then
local navbar = make_navbar_func()
if navbar and navbar ~= "" then
local headernavbardiv = mw.html.create("div")
headernavbardiv:attr("style", 'float:left; width:6em;text-align:left;')
headernavbardiv:wikitext(navbar)
headerth:node(headernavbardiv)
end
end
headerth:node(headertitlediv)
end
if content[1] ~= nil then
if content[1] ~= "-" then
error('Argument 1 must be single hyphen "-"')
end
if (not no_heading) then
local subheadertr = mw.html.create("tr")
local numberth = mw.html.create("th")
numberth:wikitext(tag_text_en("[[number|Number]]"))
subheadertr:node(numberth)
local kanjith = mw.html.create("th")
kanjith:wikitext(tag_text_en("[[kanji|Kanji]]"))
subheadertr:node(kanjith)
local kanath = mw.html.create("th")
kanath:wikitext(tag_text_en("[[kana|Kana]]"))
subheadertr:node(kanath)
local romajith = mw.html.create("th")
romajith:wikitext(tag_text_en("[[romaji|Romaji]]"))
subheadertr:node(romajith)
output:node(subheadertr)
end
end
if counter_lemma == nil then
counter_lemma = ""
end
if counter_kana == nil then
counter_kana = ""
end
local rows = {}
do
local i = 1
while true do
if content[i] == nil then
break
end
local number = content[i + 1]
local kanjis_begin = i + 2
local kanjis_end = i + 2
while true do
local kanji = content[kanjis_end]
if kanji == nil or kanji == "-" then
break
end
kanjis_end = kanjis_end + 1
end
local n_kanjis = kanjis_end - kanjis_begin
local readings_begin = kanjis_end + 1
local readings_end = kanjis_end + 1
while true do
local reading = content[readings_end]
if reading == nil or reading == "-" then
break
end
readings_end = readings_end + 1
end
local n_readings = readings_end - readings_begin
local kanjis = {}
if n_kanjis == 0 and number == "?" then
table.insert(kanjis, "何" .. counter_lemma)
elseif n_kanjis == 0 and number == "1000" then
table.insert(kanjis, "千" .. counter_lemma)
table.insert(kanjis, "*一千" .. counter_lemma)
elseif n_kanjis == 0 and string.match(number, "^%d+$") then
if tonumber(number) == 0 then
table.insert(kanjis, "0" .. counter_lemma)
table.insert(kanjis, "零" .. counter_lemma)
else
local numeral = ja_numeral(number)
table.insert(kanjis, numeral .. counter_lemma)
end
elseif n_kanjis > 0 then
for kanji_i = kanjis_begin, kanjis_end - 1 do
local kanji = content[kanji_i]
if kanji ~= "" then
table.insert(kanjis, kanji)
end
end
end
local lemmas = {}
for j = 1, #kanjis do
local kanji = kanjis[j]
local asterisk = false
if string.match(kanji, "^%*") then
asterisk = true
kanji = string.gsub(kanji, "^%*", "")
end
table.insert(lemmas, { kanji = kanji, asterisk = asterisk })
end
local readings = {}
for reading_i = readings_begin, readings_end - 1 do
local reading = content[reading_i]
local asterisk = false
if string.match(reading, "^%*") then
asterisk = true
reading = string.gsub(reading, "^%*", "")
end
if (not is_acc_style) then
table.insert(readings, {kana = reading, asterisk = asterisk})
else
local inline_pattern = "([^<%. ]+)<%s*acc%s*:%s*(.-)%s*>"
if string.match(reading, inline_pattern) then
local kana = string.gsub(reading, inline_pattern, "%1")
local acc = string.gsub(reading, inline_pattern, "%2")
table.insert(readings, {kana = kana, asterisk = asterisk, acc = acc})
else
error("acc is required for readings in acc_counter_table")
end
end
end
table.insert(rows, {number = number, lemmas = lemmas, readings = readings})
i = readings_end
end
end
for _, row in ipairs(rows) do
local number = row.number
local lemmas = row.lemmas
local readings = row.readings
local rowtr = mw.html.create("tr")
local numbertd = mw.html.create("td")
numbertd:attr("align", "right")
if number ~= nil and number ~= "" then
local formatted_number = format_number(number)
numbertd:wikitext(formatted_number)
end
rowtr:node(numbertd)
local kanjitd = mw.html.create("td")
kanjitd:attr("align", "center")
for i, lemma in ipairs(lemmas) do
local kanji = lemma.kanji
if lemma.asterisk then
kanji = string.gsub(kanji, "^%*", "")
kanjitd:wikitext("<sup>*</sup>")
end
kanjitd:wikitext(mention_or_link(kanji))
if i ~= #lemmas then
kanjitd:wikitext(", ")
end
end
rowtr:node(kanjitd)
local kanatd = mw.html.create("td")
local romajitd = mw.html.create("td")
if (not is_acc_style) then
kanatd:attr("align", "center")
romajitd:attr("align", "center")
end
for i, reading in ipairs(readings) do
if reading.asterisk then
if (not is_acc_style) then
kanatd:wikitext("<sup>*</sup>")
end
romajitd:wikitext("*")
end
if (not is_acc_style) then
kanatd:wikitext(tag_text_ja(reading.kana))
local romaji = kana_to_romaji(reading.kana)
romajitd:wikitext(romaji)
if i ~= #readings then
kanatd:wikitext(", ")
romajitd:wikitext(", ")
end
else
local ja_pron_acc, ja_pron_romaji = string.match(m_ja_pron.accent(reading.kana, reading.acc), '(<span lang="ja" class="Jpan">.-) (<span class="Latn"><samp>.-</samp></span>)')
kanatd:wikitext(ja_pron_acc)
romajitd:wikitext(ja_pron_romaji)
if i ~= #readings then
kanatd:wikitext("<br>")
romajitd:wikitext("<br>")
end
end
end
rowtr:node(kanatd)
rowtr:node(romajitd)
output:node(rowtr)
end
if (#rows > 14) and (not no_heading) then
output = mw.html.create("div")
:node(output)
:addClass("list-switcher")
:attr("style", "min-height:18em;")
:attr("data-toggle-category", "counter")
output = mw.html.create("div")
:addClass("list-switcher-wrapper")
:attr("style", "width: fit-content;")
:node(output)
end
return tostring(output)
end
function export.show(frame)
local params = {
[1] = { required=true, allow_empty=true, list=true },
["lemma"] = { },
["kana"] = { },
["t"] = { },
["pos"] = { },
["tl"] = { },
["title"] = { },
["auto_gen"] = { type="boolean" }
}
local args = require("Module:parameters").process(frame.args, params)
local template_name = args["tl"]
local make_navbar_func
if template_name and template_name ~= "" then
make_navbar_func = function()
return frame:expandTemplate{title="Navbar", args={template_name, mini = "y"}}
end
end
return _counter_table(args["lemma"], args["kana"], args[1], args["t"], args["pos"], args["title"], make_navbar_func, false, args["auto_gen"])
end
function export.acc_counter_table(counter_lemma, counter_kana, content, auto_gen)
return _counter_table(counter_lemma, counter_kana, content, nil, nil, nil, nil, true, auto_gen)
end
return export
pwypsfbpzsgaagnylajnqyc2wt1m7bm
5724447
5724444
2026-06-10T02:31:22Z
OctraBot
3198
5724447
Scribunto
text/plain
local export = {}
local ja_numeral = require("Module:ja-numeral").convert
local kana_to_romaji = require("Module:Hrkt-translit").tr
local tag_text = require("Module:script utilities").tag_text
local full_link = require("Module:links").full_link
local embedded_language_links = require("Module:links").embedded_language_links
local lang_en = require("Module:languages").getByCode("en")
local lang_ja = require("Module:languages").getByCode("ja")
local sc = require("Module:scripts").getByCode("Latn")
local sc_ja = require("Module:scripts").getByCode("ja")
local FULLPAGENAME = mw.title.getCurrentTitle().prefixedText
local is_template_page_display = false
if string.match(FULLPAGENAME, "^แม่แบบ:") then
is_template_page_display = true
end
local function tag_text_en(text)
return tag_text(embedded_language_links{term = text, lang = lang_en, sc = sc}, lang_en, sc)
end
local function tag_text_ja(text)
return tag_text(embedded_language_links{term = text, lang = lang_ja, sc = sc}, lang_ja, sc_ja)
end
local function mention_ja(text, t, tr, pos)
return full_link({lang = lang_ja, sc = sc_ja, track_sc = true,
term = text, show_qualifiers = true, gloss = t, tr = tr, pos = pos})
end
local function mention_or_link(text)
local title = mw.title.new(text)
if title and title.exists then
return mention_ja(text)
else
return tag_text_ja(text)
end
end
local function format_number(number)
local str = tostring(number)
if str == nil or str == "" or not string.match(str, "^%d+$") then
return str
end
local result = ""
local strlen = string.len(str)
for i = 0, math.floor(strlen / 3) - 1 do
result = "," .. string.sub(str, strlen - (i * 3) - 2, strlen - (i * 3)) .. result
end
if strlen % 3 == 0 then
result = string.sub(result, 2, string.len(result))
else
result = string.sub(str, 1, strlen % 3) .. result
end
return result
end
local function _counter_table(counter_lemma, counter_kana, content, counter_t, counter_pos, title, make_navbar_func, is_acc_style, auto_gen)
if content[1] == nil then
error("Zero rows")
end
local no_heading = false
local m_ja_pron
if is_acc_style then
no_heading = true
m_ja_pron = require("Module:ja-pron")
end
local output = mw.html.create("table")
:addClass("wikitable")
:attr("style", "border: 1px "
.. "solid #AAAAAA; border-collapse:collapse;")
:attr("cellpadding", "3")
:attr("rules", "all")
if (not no_heading) then
local headertr = mw.html.create("tr")
output:node(headertr)
local headerth = mw.html.create("th")
:attr("align", "center")
:attr("colspan", "4")
headertr:node(headerth)
local headertitlediv = mw.html.create("div")
if title ~= nil then
if title ~= "" then
headertitlediv:wikitext(title)
end
else
headertitlediv:wikitext("Japanese counter/suffix")
local m_entry, m_t, m_tr, m_pos
if counter_lemma ~= nil and counter_lemma ~= "" then
m_entry = counter_lemma
end
if counter_t ~= nil and counter_t ~= "" then
m_t = counter_t
end
if counter_kana ~= nil and counter_kana ~= "" then
if counter_lemma == counter_kana then
m_tr = kana_to_romaji(counter_kana)
else
m_tr = counter_kana .. ", " .. kana_to_romaji(counter_kana)
end
end
if counter_pos ~= nil and counter_pos ~= "" then
m_pos = counter_pos
end
if (m_entry ~= nil) or (m_t ~= nil) or (m_tr ~= nil) or (m_pos ~= nil) then
headertitlediv:wikitext(": ")
headertitlediv:wikitext(tag_text_en(mention_ja(m_entry, m_t, m_tr, m_pos)))
end
end
if make_navbar_func then
local navbar = make_navbar_func()
if navbar and navbar ~= "" then
local headernavbardiv = mw.html.create("div")
headernavbardiv:attr("style", 'float:left; width:6em;text-align:left;')
headernavbardiv:wikitext(navbar)
headerth:node(headernavbardiv)
end
end
headerth:node(headertitlediv)
end
if content[1] ~= nil then
if content[1] ~= "-" then
error('Argument 1 must be single hyphen "-"')
end
if (not no_heading) then
local subheadertr = mw.html.create("tr")
local numberth = mw.html.create("th")
numberth:wikitext(tag_text_en("[[เลข]]/[[จำนวน]]"))
subheadertr:node(numberth)
local kanjith = mw.html.create("th")
kanjith:wikitext(tag_text_en("[[คันจิ]]"))
subheadertr:node(kanjith)
local kanath = mw.html.create("th")
kanath:wikitext(tag_text_en("[[คานะ]]"))
subheadertr:node(kanath)
local romajith = mw.html.create("th")
romajith:wikitext(tag_text_en("[[โรมาจิ]]"))
subheadertr:node(romajith)
output:node(subheadertr)
end
end
if counter_lemma == nil then
counter_lemma = ""
end
if counter_kana == nil then
counter_kana = ""
end
local rows = {}
do
local i = 1
while true do
if content[i] == nil then
break
end
local number = content[i + 1]
local kanjis_begin = i + 2
local kanjis_end = i + 2
while true do
local kanji = content[kanjis_end]
if kanji == nil or kanji == "-" then
break
end
kanjis_end = kanjis_end + 1
end
local n_kanjis = kanjis_end - kanjis_begin
local readings_begin = kanjis_end + 1
local readings_end = kanjis_end + 1
while true do
local reading = content[readings_end]
if reading == nil or reading == "-" then
break
end
readings_end = readings_end + 1
end
local n_readings = readings_end - readings_begin
local kanjis = {}
if n_kanjis == 0 and number == "?" then
table.insert(kanjis, "何" .. counter_lemma)
elseif n_kanjis == 0 and number == "1000" then
table.insert(kanjis, "千" .. counter_lemma)
table.insert(kanjis, "*一千" .. counter_lemma)
elseif n_kanjis == 0 and string.match(number, "^%d+$") then
if tonumber(number) == 0 then
table.insert(kanjis, "0" .. counter_lemma)
table.insert(kanjis, "零" .. counter_lemma)
else
local numeral = ja_numeral(number)
table.insert(kanjis, numeral .. counter_lemma)
end
elseif n_kanjis > 0 then
for kanji_i = kanjis_begin, kanjis_end - 1 do
local kanji = content[kanji_i]
if kanji ~= "" then
table.insert(kanjis, kanji)
end
end
end
local lemmas = {}
for j = 1, #kanjis do
local kanji = kanjis[j]
local asterisk = false
if string.match(kanji, "^%*") then
asterisk = true
kanji = string.gsub(kanji, "^%*", "")
end
table.insert(lemmas, { kanji = kanji, asterisk = asterisk })
end
local readings = {}
for reading_i = readings_begin, readings_end - 1 do
local reading = content[reading_i]
local asterisk = false
if string.match(reading, "^%*") then
asterisk = true
reading = string.gsub(reading, "^%*", "")
end
if (not is_acc_style) then
table.insert(readings, {kana = reading, asterisk = asterisk})
else
local inline_pattern = "([^<%. ]+)<%s*acc%s*:%s*(.-)%s*>"
if string.match(reading, inline_pattern) then
local kana = string.gsub(reading, inline_pattern, "%1")
local acc = string.gsub(reading, inline_pattern, "%2")
table.insert(readings, {kana = kana, asterisk = asterisk, acc = acc})
else
error("acc is required for readings in acc_counter_table")
end
end
end
table.insert(rows, {number = number, lemmas = lemmas, readings = readings})
i = readings_end
end
end
for _, row in ipairs(rows) do
local number = row.number
local lemmas = row.lemmas
local readings = row.readings
local rowtr = mw.html.create("tr")
local numbertd = mw.html.create("td")
numbertd:attr("align", "right")
if number ~= nil and number ~= "" then
local formatted_number = format_number(number)
numbertd:wikitext(formatted_number)
end
rowtr:node(numbertd)
local kanjitd = mw.html.create("td")
kanjitd:attr("align", "center")
for i, lemma in ipairs(lemmas) do
local kanji = lemma.kanji
if lemma.asterisk then
kanji = string.gsub(kanji, "^%*", "")
kanjitd:wikitext("<sup>*</sup>")
end
kanjitd:wikitext(mention_or_link(kanji))
if i ~= #lemmas then
kanjitd:wikitext(", ")
end
end
rowtr:node(kanjitd)
local kanatd = mw.html.create("td")
local romajitd = mw.html.create("td")
if (not is_acc_style) then
kanatd:attr("align", "center")
romajitd:attr("align", "center")
end
for i, reading in ipairs(readings) do
if reading.asterisk then
if (not is_acc_style) then
kanatd:wikitext("<sup>*</sup>")
end
romajitd:wikitext("*")
end
if (not is_acc_style) then
kanatd:wikitext(tag_text_ja(reading.kana))
local romaji = kana_to_romaji(reading.kana)
romajitd:wikitext(romaji)
if i ~= #readings then
kanatd:wikitext(", ")
romajitd:wikitext(", ")
end
else
local ja_pron_acc, ja_pron_romaji = string.match(m_ja_pron.accent(reading.kana, reading.acc), '(<span lang="ja" class="Jpan">.-) (<span class="Latn"><samp>.-</samp></span>)')
kanatd:wikitext(ja_pron_acc)
romajitd:wikitext(ja_pron_romaji)
if i ~= #readings then
kanatd:wikitext("<br>")
romajitd:wikitext("<br>")
end
end
end
rowtr:node(kanatd)
rowtr:node(romajitd)
output:node(rowtr)
end
if (#rows > 14) and (not no_heading) then
output = mw.html.create("div")
:node(output)
:addClass("list-switcher")
:attr("style", "min-height:18em;")
:attr("data-toggle-category", "counter")
output = mw.html.create("div")
:addClass("list-switcher-wrapper")
:attr("style", "width: fit-content;")
:node(output)
end
return tostring(output)
end
function export.show(frame)
local params = {
[1] = { required=true, allow_empty=true, list=true },
["lemma"] = { },
["kana"] = { },
["t"] = { },
["pos"] = { },
["tl"] = { },
["title"] = { },
["auto_gen"] = { type="boolean" }
}
local args = require("Module:parameters").process(frame.args, params)
local template_name = args["tl"]
local make_navbar_func
if template_name and template_name ~= "" then
make_navbar_func = function()
return frame:expandTemplate{title="Navbar", args={template_name, mini = "y"}}
end
end
return _counter_table(args["lemma"], args["kana"], args[1], args["t"], args["pos"], args["title"], make_navbar_func, false, args["auto_gen"])
end
function export.acc_counter_table(counter_lemma, counter_kana, content, auto_gen)
return _counter_table(counter_lemma, counter_kana, content, nil, nil, nil, nil, true, auto_gen)
end
return export
nstvje22lnw5w9et4bjkt34bgs2dm0j
5724450
5724447
2026-06-10T02:36:58Z
OctraBot
3198
5724450
Scribunto
text/plain
local export = {}
local ja_numeral = require("Module:ja-numeral").convert
local kana_to_romaji = require("Module:Hrkt-translit").tr
local tag_text = require("Module:script utilities").tag_text
local full_link = require("Module:links").full_link
local embedded_language_links = require("Module:links").embedded_language_links
local lang_en = require("Module:languages").getByCode("en")
local lang_ja = require("Module:languages").getByCode("ja")
local sc = require("Module:scripts").getByCode("Latn")
local sc_ja = require("Module:scripts").getByCode("ja")
local FULLPAGENAME = mw.title.getCurrentTitle().prefixedText
local is_template_page_display = false
if string.match(FULLPAGENAME, "^แม่แบบ:") then
is_template_page_display = true
end
local function tag_text_en(text)
return tag_text(embedded_language_links{term = text, lang = lang_en, sc = sc}, lang_en, sc)
end
local function tag_text_ja(text)
return tag_text(embedded_language_links{term = text, lang = lang_ja, sc = sc}, lang_ja, sc_ja)
end
local function mention_ja(text, t, tr, pos)
return full_link({lang = lang_ja, sc = sc_ja, track_sc = true,
term = text, show_qualifiers = true, gloss = t, tr = tr, pos = pos})
end
local function mention_or_link(text)
local title = mw.title.new(text)
if title and title.exists then
return mention_ja(text)
else
return tag_text_ja(text)
end
end
local function format_number(number)
local str = tostring(number)
if str == nil or str == "" or not string.match(str, "^%d+$") then
return str
end
local result = ""
local strlen = string.len(str)
for i = 0, math.floor(strlen / 3) - 1 do
result = "," .. string.sub(str, strlen - (i * 3) - 2, strlen - (i * 3)) .. result
end
if strlen % 3 == 0 then
result = string.sub(result, 2, string.len(result))
else
result = string.sub(str, 1, strlen % 3) .. result
end
return result
end
local function _counter_table(counter_lemma, counter_kana, content, counter_t, counter_pos, title, make_navbar_func, is_acc_style, auto_gen)
if content[1] == nil then
error("Zero rows")
end
local no_heading = false
local m_ja_pron
if is_acc_style then
no_heading = true
m_ja_pron = require("Module:ja-pron")
end
local output = mw.html.create("table")
:addClass("wikitable")
:attr("style", "border: 1px "
.. "solid #AAAAAA; border-collapse:collapse;")
:attr("cellpadding", "3")
:attr("rules", "all")
if (not no_heading) then
local headertr = mw.html.create("tr")
output:node(headertr)
local headerth = mw.html.create("th")
:attr("align", "center")
:attr("colspan", "4")
headertr:node(headerth)
local headertitlediv = mw.html.create("div")
if title ~= nil then
if title ~= "" then
headertitlediv:wikitext(title)
end
else
headertitlediv:wikitext("คำลักษณนาม/ปัจจัย ภาษาญี่ปุ่น")
local m_entry, m_t, m_tr, m_pos
if counter_lemma ~= nil and counter_lemma ~= "" then
m_entry = counter_lemma
end
if counter_t ~= nil and counter_t ~= "" then
m_t = counter_t
end
if counter_kana ~= nil and counter_kana ~= "" then
if counter_lemma == counter_kana then
m_tr = kana_to_romaji(counter_kana)
else
m_tr = counter_kana .. ", " .. kana_to_romaji(counter_kana)
end
end
if counter_pos ~= nil and counter_pos ~= "" then
m_pos = counter_pos
end
if (m_entry ~= nil) or (m_t ~= nil) or (m_tr ~= nil) or (m_pos ~= nil) then
headertitlediv:wikitext(": ")
headertitlediv:wikitext(tag_text_en(mention_ja(m_entry, m_t, m_tr, m_pos)))
end
end
if make_navbar_func then
local navbar = make_navbar_func()
if navbar and navbar ~= "" then
local headernavbardiv = mw.html.create("div")
headernavbardiv:attr("style", 'float:left; width:6em;text-align:left;')
headernavbardiv:wikitext(navbar)
headerth:node(headernavbardiv)
end
end
headerth:node(headertitlediv)
end
if content[1] ~= nil then
if content[1] ~= "-" then
error('Argument 1 must be single hyphen "-"')
end
if (not no_heading) then
local subheadertr = mw.html.create("tr")
local numberth = mw.html.create("th")
numberth:wikitext(tag_text_en("[[เลข]]/[[จำนวน]]"))
subheadertr:node(numberth)
local kanjith = mw.html.create("th")
kanjith:wikitext(tag_text_en("[[คันจิ]]"))
subheadertr:node(kanjith)
local kanath = mw.html.create("th")
kanath:wikitext(tag_text_en("[[คานะ]]"))
subheadertr:node(kanath)
local romajith = mw.html.create("th")
romajith:wikitext(tag_text_en("[[โรมาจิ]]"))
subheadertr:node(romajith)
output:node(subheadertr)
end
end
if counter_lemma == nil then
counter_lemma = ""
end
if counter_kana == nil then
counter_kana = ""
end
local rows = {}
do
local i = 1
while true do
if content[i] == nil then
break
end
local number = content[i + 1]
local kanjis_begin = i + 2
local kanjis_end = i + 2
while true do
local kanji = content[kanjis_end]
if kanji == nil or kanji == "-" then
break
end
kanjis_end = kanjis_end + 1
end
local n_kanjis = kanjis_end - kanjis_begin
local readings_begin = kanjis_end + 1
local readings_end = kanjis_end + 1
while true do
local reading = content[readings_end]
if reading == nil or reading == "-" then
break
end
readings_end = readings_end + 1
end
local n_readings = readings_end - readings_begin
local kanjis = {}
if n_kanjis == 0 and number == "?" then
table.insert(kanjis, "何" .. counter_lemma)
elseif n_kanjis == 0 and number == "1000" then
table.insert(kanjis, "千" .. counter_lemma)
table.insert(kanjis, "*一千" .. counter_lemma)
elseif n_kanjis == 0 and string.match(number, "^%d+$") then
if tonumber(number) == 0 then
table.insert(kanjis, "0" .. counter_lemma)
table.insert(kanjis, "零" .. counter_lemma)
else
local numeral = ja_numeral(number)
table.insert(kanjis, numeral .. counter_lemma)
end
elseif n_kanjis > 0 then
for kanji_i = kanjis_begin, kanjis_end - 1 do
local kanji = content[kanji_i]
if kanji ~= "" then
table.insert(kanjis, kanji)
end
end
end
local lemmas = {}
for j = 1, #kanjis do
local kanji = kanjis[j]
local asterisk = false
if string.match(kanji, "^%*") then
asterisk = true
kanji = string.gsub(kanji, "^%*", "")
end
table.insert(lemmas, { kanji = kanji, asterisk = asterisk })
end
local readings = {}
for reading_i = readings_begin, readings_end - 1 do
local reading = content[reading_i]
local asterisk = false
if string.match(reading, "^%*") then
asterisk = true
reading = string.gsub(reading, "^%*", "")
end
if (not is_acc_style) then
table.insert(readings, {kana = reading, asterisk = asterisk})
else
local inline_pattern = "([^<%. ]+)<%s*acc%s*:%s*(.-)%s*>"
if string.match(reading, inline_pattern) then
local kana = string.gsub(reading, inline_pattern, "%1")
local acc = string.gsub(reading, inline_pattern, "%2")
table.insert(readings, {kana = kana, asterisk = asterisk, acc = acc})
else
error("acc is required for readings in acc_counter_table")
end
end
end
table.insert(rows, {number = number, lemmas = lemmas, readings = readings})
i = readings_end
end
end
for _, row in ipairs(rows) do
local number = row.number
local lemmas = row.lemmas
local readings = row.readings
local rowtr = mw.html.create("tr")
local numbertd = mw.html.create("td")
numbertd:attr("align", "right")
if number ~= nil and number ~= "" then
local formatted_number = format_number(number)
numbertd:wikitext(formatted_number)
end
rowtr:node(numbertd)
local kanjitd = mw.html.create("td")
kanjitd:attr("align", "center")
for i, lemma in ipairs(lemmas) do
local kanji = lemma.kanji
if lemma.asterisk then
kanji = string.gsub(kanji, "^%*", "")
kanjitd:wikitext("<sup>*</sup>")
end
kanjitd:wikitext(mention_or_link(kanji))
if i ~= #lemmas then
kanjitd:wikitext(", ")
end
end
rowtr:node(kanjitd)
local kanatd = mw.html.create("td")
local romajitd = mw.html.create("td")
if (not is_acc_style) then
kanatd:attr("align", "center")
romajitd:attr("align", "center")
end
for i, reading in ipairs(readings) do
if reading.asterisk then
if (not is_acc_style) then
kanatd:wikitext("<sup>*</sup>")
end
romajitd:wikitext("*")
end
if (not is_acc_style) then
kanatd:wikitext(tag_text_ja(reading.kana))
local romaji = kana_to_romaji(reading.kana)
romajitd:wikitext(romaji)
if i ~= #readings then
kanatd:wikitext(", ")
romajitd:wikitext(", ")
end
else
local ja_pron_acc, ja_pron_romaji = string.match(m_ja_pron.accent(reading.kana, reading.acc), '(<span lang="ja" class="Jpan">.-) (<span class="Latn"><samp>.-</samp></span>)')
kanatd:wikitext(ja_pron_acc)
romajitd:wikitext(ja_pron_romaji)
if i ~= #readings then
kanatd:wikitext("<br>")
romajitd:wikitext("<br>")
end
end
end
rowtr:node(kanatd)
rowtr:node(romajitd)
output:node(rowtr)
end
if (#rows > 14) and (not no_heading) then
output = mw.html.create("div")
:node(output)
:addClass("list-switcher")
:attr("style", "min-height:18em;")
:attr("data-toggle-category", "counter")
output = mw.html.create("div")
:addClass("list-switcher-wrapper")
:attr("style", "width: fit-content;")
:node(output)
end
return tostring(output)
end
function export.show(frame)
local params = {
[1] = { required=true, allow_empty=true, list=true },
["lemma"] = { },
["kana"] = { },
["t"] = { },
["pos"] = { },
["tl"] = { },
["title"] = { },
["auto_gen"] = { type="boolean" }
}
local args = require("Module:parameters").process(frame.args, params)
local template_name = args["tl"]
local make_navbar_func
if template_name and template_name ~= "" then
make_navbar_func = function()
return frame:expandTemplate{title="Navbar", args={template_name, mini = "y"}}
end
end
return _counter_table(args["lemma"], args["kana"], args[1], args["t"], args["pos"], args["title"], make_navbar_func, false, args["auto_gen"])
end
function export.acc_counter_table(counter_lemma, counter_kana, content, auto_gen)
return _counter_table(counter_lemma, counter_kana, content, nil, nil, nil, nil, true, auto_gen)
end
return export
hb70ffngcmnxcadoieei199mbb4m6nq
มอดูล:ja-numeral
828
2331684
5724445
2026-06-10T02:29:03Z
OctraBot
3198
สร้างหน้าด้วย "local export = {} local exponentarr = { { num=10, numeral="十", ichiprefix=false }, { num=100, numeral="百", ichiprefix=false }, { num=1000, numeral="千", ichiprefix=false }, { num=10000, numeral="万", ichiprefix=true }, { num=100000000, numeral="億", ichiprefix=true }, { num=1000000000000, numeral="兆", ichiprefix=true }, { num=10000000000000000, numeral="京", ichiprefix=true }, { num=100000000000000000000, numeral="垓", ichiprefix..."
5724445
Scribunto
text/plain
local export = {}
local exponentarr = {
{ num=10, numeral="十", ichiprefix=false },
{ num=100, numeral="百", ichiprefix=false },
{ num=1000, numeral="千", ichiprefix=false },
{ num=10000, numeral="万", ichiprefix=true },
{ num=100000000, numeral="億", ichiprefix=true },
{ num=1000000000000, numeral="兆", ichiprefix=true },
{ num=10000000000000000, numeral="京", ichiprefix=true },
{ num=100000000000000000000, numeral="垓", ichiprefix=true }
}
local numarr = { "一", "二", "三", "四", "五", "六", "七", "八", "九" }
function export.convert(num)
if num == nil then
error("Nil")
end
num = tonumber(num)
if num == nil then
error("Nil")
end
if num == 0 then
return "零"
end
if num == math.huge or num == (1 - math.huge) then
error("Infinity not supported")
end
if num ~= num then
error("NaN not supported")
end
if num ~= math.floor(num) then
error("Decimals not supported")
end
if num < 0 then
error("Negative number not supported")
end
local function convertrecursive(numeral, val)
if val == 0 then
return numeral
end
if val < 10 then
return numeral .. numarr[val]
end
local biggestexponent = exponentarr[#exponentarr]
for i, exponent in ipairs(exponentarr) do
if val < exponent.num then
biggestexponent = exponentarr[i - 1]
break
end
end
local multiple = math.floor(val / biggestexponent.num)
local multiplenumeral = numarr[multiple]
if multiplenumeral == nil then
return convertrecursive("", multiple)
.. biggestexponent.numeral
.. convertrecursive(numeral,
val - biggestexponent.num * multiple)
elseif multiple == 1 and not biggestexponent.ichiprefix then
return convertrecursive(
numeral .. biggestexponent.numeral,
val - biggestexponent.num * multiple)
else
return convertrecursive(
numeral .. multiplenumeral .. biggestexponent.numeral,
val - biggestexponent.num * multiple)
end
end
return convertrecursive("", num)
end
function export.show(frame)
local params = { [1] = { required=true, type="number" } }
local args = require("Module:parameters").process(frame.args, params)
return export.convert(args[1])
end
return export
c6fhgd0zjmgj0k1uktilx3uu9lahcxd
แม่แบบ:Navbar
10
2331685
5724446
2026-06-10T02:30:05Z
OctraBot
3198
สร้างหน้าด้วย "<includeonly>{{#if:{{{nodiv|}}}| <span|<div}} class="noprint plainlinks navbar" style="background:none; padding:0; font-weight:normal;{{{fontstyle|}}}; font-size:xx-small; {{{style|}}}"><!-- -->{{#if:{{{mini|}}}{{{plain|}}}|<!--nothing-->|<!--else: -->This box: }}<!-- -->{{#if:{{{brackets|}}}|[}}<!-- -->{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!-- -->{{#if:{{{mini|}}}|v|view}}</spa..."
5724446
wikitext
text/x-wiki
<includeonly>{{#if:{{{nodiv|}}}| <span|<div}} class="noprint plainlinks navbar" style="background:none; padding:0; font-weight:normal;{{{fontstyle|}}}; font-size:xx-small; {{{style|}}}"><!--
-->{{#if:{{{mini|}}}{{{plain|}}}|<!--nothing-->|<!--else:
-->This box: }}<!--
-->{{#if:{{{brackets|}}}|[}}<!--
-->[[{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!--
-->{{#if:{{{mini|}}}|v|view}}</span>]]<!--
--> <span style="font-size:80%;">•</span> [[{{TALKPAGENAME:{{transcluded pagename|{{{1}}}}}}}|<span title="Discuss this template" style="{{{fontstyle|}}}">{{#if:{{{mini|}}}|d|talk}}</span>]]<!--
-->{{#if:{{{noedit|}}}|<!--nothing-->|<!--else:
--> <span style="font-size:80%;">•</span> [{{fullurl:{{transcluded pagename|{{{1}}}}}|action=edit}}<span title="Edit this template" style="{{{fontstyle|}}};">{{#if:{{{mini|}}}|e|edit}}</span>]<!--
-->}}<!--
-->{{#if:{{{brackets|}}}|]}}<!--
-->{{#if:{{{nodiv|}}}|<!--then:
--></span> |<!--else:
--></div>}}</includeonly><noinclude>{{documentation}}</noinclude>
0x1dwgz3z5mz2s4y46vuy4442u1r9pp
5724452
5724446
2026-06-10T02:41:10Z
OctraBot
3198
5724452
wikitext
text/x-wiki
<includeonly>{{#if:{{{nodiv|}}}| <span|<div}} class="noprint plainlinks navbar" style="background:none; padding:0; font-weight:normal;{{{fontstyle|}}}; font-size:xx-small; {{{style|}}}"><!--
-->{{#if:{{{mini|}}}{{{plain|}}}|<!--nothing-->|<!--else:
-->This box: }}<!--
-->{{#if:{{{brackets|}}}|[}}<!--
-->[[{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!--
-->{{#if:{{{mini|}}}|ด|ดู}}</span>]]<!--
--> <span style="font-size:80%;">•</span> [[{{TALKPAGENAME:{{transcluded pagename|{{{1}}}}}}}|<span title="Discuss this template" style="{{{fontstyle|}}}">{{#if:{{{mini|}}}|พ|พูดคุย}}</span>]]<!--
-->{{#if:{{{noedit|}}}|<!--nothing-->|<!--else:
--> <span style="font-size:80%;">•</span> [{{fullurl:{{transcluded pagename|{{{1}}}}}|action=edit}}<span title="Edit this template" style="{{{fontstyle|}}};">{{#if:{{{mini|}}}|ก|แก้ไข}}</span>]<!--
-->}}<!--
-->{{#if:{{{brackets|}}}|]}}<!--
-->{{#if:{{{nodiv|}}}|<!--then:
--></span> |<!--else:
--></div>}}</includeonly><noinclude>{{documentation}}</noinclude>
4vn4ooylgmkynhcsadqhp3fgcdheign
แม่แบบ:transcluded pagename
10
2331686
5724448
2026-06-10T02:32:53Z
OctraBot
3198
นำเข้าจาก enwikt
5724448
wikitext
text/x-wiki
{{#switch: {{NAMESPACE: {{{1}}} }}
|#default = {{FULLPAGENAME: {{{1}}} }} <!-- eg "User:Foo" -->
|{{ns:0}} =
{{#ifeq: {{NAMESPACE: {{{1}}} }} | {{NAMESPACE: แม่แบบ{{{1}}} }}
| แม่แบบ:{{{1}}} <!-- no leading colon, eg "Foo" -->
| {{PAGENAME: {{{1}}} }} <!-- leading colon, eg ":Foo", so we want the article -->
}}
}}<noinclude>
{{documentation}}
</noinclude>
p82pd0a2b7mth21ru1maycnt9k99tjw
แม่แบบ:ja-number-counter:ヶ月
10
2331687
5724449
2026-06-10T02:36:04Z
OctraBot
3198
นำเข้าจาก enwikt
5724449
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:ヶ月
|lemma=ヶ月
|kana=かげつ
|t=[[เดือน]]
|-|1|-|いっかげつ
|-|2|-|にかげつ
|-|3|-|さんかげつ
|-|4|-|よんかげつ
|-|5|-|ごかげつ
|-|6|-|ろっかげつ
|-|7|-|ななかげつ|しちかげつ
|-|8|-|はっかげつ|はちかげつ
|-|9|-|きゅうかげつ
|-|10|-|じっかげつ|じゅっかげつ
|-|11|-|じゅういっかげつ
|-|12|-|じゅうにかげつ
|-|13|-|じゅうさんかげつ
|-|20|-|にじっかげつ|にじゅっかげつ
|-|21|-|にじゅういっかげつ
|-|100|-|ひゃっかげつ
|-|1000|-|せんかげつ|*いっせんかげつ
|-|10000|-|いちまんかげつ
|-|100000000|-|いちおくかげつ
|-|0|-|ゼロかげつ|れいかげつ
|-|?|-|なんかげつ
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:かけつ]]</noinclude>[[Category:ja:Months]]
pct95nd7ig20jynjgcalu9g78wo87vh
5724458
5724449
2026-06-10T02:48:30Z
OctraBot
3198
5724458
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:ヶ月
|lemma=ヶ月
|kana=かげつ
|t=[[เดือน]]
|-|1|-|いっかげつ
|-|2|-|にかげつ
|-|3|-|さんかげつ
|-|4|-|よんかげつ
|-|5|-|ごかげつ
|-|6|-|ろっかげつ
|-|7|-|ななかげつ|しちかげつ
|-|8|-|はっかげつ|はちかげつ
|-|9|-|きゅうかげつ
|-|10|-|じっかげつ|じゅっかげつ
|-|11|-|じゅういっかげつ
|-|12|-|じゅうにかげつ
|-|13|-|じゅうさんかげつ
|-|20|-|にじっかげつ|にじゅっかげつ
|-|21|-|にじゅういっかげつ
|-|100|-|ひゃっかげつ
|-|1000|-|せんかげつ|*いっせんかげつ
|-|10000|-|いちまんかげつ
|-|100000000|-|いちおくかげつ
|-|0|-|ゼロかげつ|れいかげつ
|-|?|-|なんかげつ
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:かけつ]]</noinclude>{{topics|ja|Months}}
6cjgqmginaieu3gnwrq7pifzgabla5k
一ヶ月
0
2331688
5724451
2026-06-10T02:39:41Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724451
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|いつ|k1=いっ|げつ|alt=一ヵ月,一カ月,一か月,一箇月,一ケ月,1ヶ月,1ヶ月,1ヵ月,1ヵ月,1カ月,1カ月,1か月,1か月,1箇月,1箇月,1ケ月,1ケ月|yomi=kanon}}
=== รากศัพท์ ===
{{ja-compound|一|いち|t1=หนึ่ง|ヶ|か|pos2=รูปง่ายของ {{ja-r|箇|か}}, คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|いっかげつ|acc=3}}
=== คำนาม ===
{{ja-noun|いっかげつ}}
# [[หนึ่ง]][[เดือน]] (ระยะเวลา)
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
asbtjrz6gt1llhfzzx2j1ugj19l1i77
三ヶ月
0
2331689
5724453
2026-06-10T02:42:18Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724453
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|さん|げつ|yomi=on|alt=三箇月}}
=== รากศัพท์ ===
{{ja-com|三|さん|t1=three|ヶ|か|pos2=รูปง่ายของ {{ja-r|箇|か}}, คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|さんかげつ|acc=3}}
=== คำนาม ===
{{ja-noun|さんかげつ}}
# [[สาม]][[เดือน]] {{gl|ระยะเวลา}}
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
tepdniewhr913uuzm0l97hjk89xudn3
5724454
5724453
2026-06-10T02:42:31Z
OctraBot
3198
/* รากศัพท์ */
5724454
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|さん|げつ|yomi=on|alt=三箇月}}
=== รากศัพท์ ===
{{ja-com|三|さん|t1=สาม|ヶ|か|pos2=รูปง่ายของ {{ja-r|箇|か}}, คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|さんかげつ|acc=3}}
=== คำนาม ===
{{ja-noun|さんかげつ}}
# [[สาม]][[เดือน]] {{gl|ระยะเวลา}}
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
1iztzd4mecnnlswa73zkeyab40nowbq
四ヶ月
0
2331690
5724455
2026-06-10T02:43:35Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724455
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|よん|げつ|yomi=kun,on|alt=四箇月}}
=== รากศัพท์ ===
{{ja-compound|四|よん|t1=สี่|ヶ|か|pos2=คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|よんかげつ|acc=3}}
=== คำนาม ===
{{ja-noun|よんかげつ}}
# [[สี่]][[เดือน]] (ระยะเวลา)
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
{{topics|ja|เวลา}}
fzg8zgoo7bvf5o2bfj60n76a6k1gf6e
yonkagetsu
0
2331691
5724456
2026-06-10T02:43:46Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724456
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
=== การถอดเป็นอักษรโรมัน ===
{{ja-romaji}}
# {{ja-romanization of|よんかげつ}}
1k6a6fz4tkbmem48hpac34dxss1p9nv
五ヶ月
0
2331692
5724457
2026-06-10T02:44:27Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724457
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab|ご|げつ|yomi=on|alt=五箇月}}
=== รากศัพท์ ===
{{ja-compound|五|ご|t1=ห้า|ヶ|か|pos2=คำลักษณนามของเดือน|月|げつ|t3=เดือน}}
=== การออกเสียง ===
{{ja-pron|ごかげつ|acc=2}}
=== คำนาม ===
{{ja-noun|ごかげつ}}
# [[ห้า]][[เดือน]] (ระยะเวลา)
==== คำเกี่ยวข้อง ====
{{ja-number-counter:ヶ月}}
{{topics|ja|เวลา}}
axc99bkx0uah39qjjv6uuocity43m6t
แม่แบบ:ja-number-counter:日
10
2331693
5724459
2026-06-10T02:50:08Z
OctraBot
3198
นำเข้าจาก enwikt
5724459
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:日
|lemma=日
|kana=
|title=[[วัน]], วันที่
|-|1|-|いちにち
|-|(1st day of the month)|一日|-|ついたち|いっぴ
|-|2|-|ふつか
|-|3|-|みっか
|-|4|-|よっか
|-|5|-|いつか
|-|6|-|むいか
|-|7|-|なのか|なぬか
|-|8|-|ようか
|-|9|-|ここのか
|-|10|-|とおか
|-|11|-|じゅういちにち
|-|12|-|じゅうににち
|-|13|-|じゅうさんにち
|-|14|-|じゅうよっか
|-|15|-|じゅうごにち
|-|16|-|じゅうろくにち
|-|17|-|じゅうしちにち|じゅうななにち
|-|18|-|じゅうはちにち
|-|19|-|じゅうくにち
|-|20|-|はつか
|-|21|-|にじゅういちにち
|-|22|-|にじゅうににち
|-|23|-|にじゅうさんにち
|-|24|-|にじゅうよっか|にじゅうよんにち
|-|25|-|にじゅうごにち
|-|26|-|にじゅうろくにち
|-|27|-|にじゅうしちにち|にじゅうななにち
|-|28|-|にじゅうはちにち
|-|29|-|にじゅうくにち
|-|30|-|さんじゅうにち|みそか
|-|31|-|さんじゅういちにち
|-|100|-|ひゃくにち
|-|1000|-|せんにち|*いっせんにち
|-|10000|-|いちまんにち
|-|100000000|-|いちおくにち
|-|0|-|ゼロにち|れいにち
|-|?|-|なんにち
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:にち]]</noinclude>{{topics|ja|Time}}
2hri76wvp2kcrwfnravj3e9zgtqrwve
5724460
5724459
2026-06-10T02:51:09Z
OctraBot
3198
5724460
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:日
|lemma=日
|kana=
|title=[[วัน]]/วันที่
|-|1|-|いちにち
|-|(1st day of the month)|一日|-|ついたち|いっぴ
|-|2|-|ふつか
|-|3|-|みっか
|-|4|-|よっか
|-|5|-|いつか
|-|6|-|むいか
|-|7|-|なのか|なぬか
|-|8|-|ようか
|-|9|-|ここのか
|-|10|-|とおか
|-|11|-|じゅういちにち
|-|12|-|じゅうににち
|-|13|-|じゅうさんにち
|-|14|-|じゅうよっか
|-|15|-|じゅうごにち
|-|16|-|じゅうろくにち
|-|17|-|じゅうしちにち|じゅうななにち
|-|18|-|じゅうはちにち
|-|19|-|じゅうくにち
|-|20|-|はつか
|-|21|-|にじゅういちにち
|-|22|-|にじゅうににち
|-|23|-|にじゅうさんにち
|-|24|-|にじゅうよっか|にじゅうよんにち
|-|25|-|にじゅうごにち
|-|26|-|にじゅうろくにち
|-|27|-|にじゅうしちにち|にじゅうななにち
|-|28|-|にじゅうはちにち
|-|29|-|にじゅうくにち
|-|30|-|さんじゅうにち|みそか
|-|31|-|さんじゅういちにち
|-|100|-|ひゃくにち
|-|1000|-|せんにち|*いっせんにち
|-|10000|-|いちまんにち
|-|100000000|-|いちおくにち
|-|0|-|ゼロにち|れいにち
|-|?|-|なんにち
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:にち]]</noinclude>{{topics|ja|Time}}
2pzvxlxz51asedia8usfu1xiemm74wx
5724461
5724460
2026-06-10T02:51:29Z
OctraBot
3198
5724461
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:日
|lemma=日
|kana=
|title=[[วัน]]/วันที่
|-|1|-|いちにち
|-|(วันที่ 1 ของเดือน)|一日|-|ついたち|いっぴ
|-|2|-|ふつか
|-|3|-|みっか
|-|4|-|よっか
|-|5|-|いつか
|-|6|-|むいか
|-|7|-|なのか|なぬか
|-|8|-|ようか
|-|9|-|ここのか
|-|10|-|とおか
|-|11|-|じゅういちにち
|-|12|-|じゅうににち
|-|13|-|じゅうさんにち
|-|14|-|じゅうよっか
|-|15|-|じゅうごにち
|-|16|-|じゅうろくにち
|-|17|-|じゅうしちにち|じゅうななにち
|-|18|-|じゅうはちにち
|-|19|-|じゅうくにち
|-|20|-|はつか
|-|21|-|にじゅういちにち
|-|22|-|にじゅうににち
|-|23|-|にじゅうさんにち
|-|24|-|にじゅうよっか|にじゅうよんにち
|-|25|-|にじゅうごにち
|-|26|-|にじゅうろくにち
|-|27|-|にじゅうしちにち|にじゅうななにち
|-|28|-|にじゅうはちにち
|-|29|-|にじゅうくにち
|-|30|-|さんじゅうにち|みそか
|-|31|-|さんじゅういちにち
|-|100|-|ひゃくにち
|-|1000|-|せんにち|*いっせんにち
|-|10000|-|いちまんにち
|-|100000000|-|いちおくにち
|-|0|-|ゼロにち|れいにち
|-|?|-|なんにち
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:にち]]</noinclude>{{topics|ja|Time}}
52sk3nsc9uljor416lx9ypx3lwglnbg
5724469
5724461
2026-06-10T04:29:56Z
OctraBot
3198
5724469
wikitext
text/x-wiki
{{#invoke:ja-counter-table|show
|tl=ja-number-counter:日
|lemma=日
|kana=
|title=[[วัน]]/วันที่ ในภาษาญี่ปุ่น
|-|1|-|いちにち
|-|(วันที่ 1 ของเดือน)|一日|-|ついたち|いっぴ
|-|2|-|ふつか
|-|3|-|みっか
|-|4|-|よっか
|-|5|-|いつか
|-|6|-|むいか
|-|7|-|なのか|なぬか
|-|8|-|ようか
|-|9|-|ここのか
|-|10|-|とおか
|-|11|-|じゅういちにち
|-|12|-|じゅうににち
|-|13|-|じゅうさんにち
|-|14|-|じゅうよっか
|-|15|-|じゅうごにち
|-|16|-|じゅうろくにち
|-|17|-|じゅうしちにち|じゅうななにち
|-|18|-|じゅうはちにち
|-|19|-|じゅうくにち
|-|20|-|はつか
|-|21|-|にじゅういちにち
|-|22|-|にじゅうににち
|-|23|-|にじゅうさんにち
|-|24|-|にじゅうよっか|にじゅうよんにち
|-|25|-|にじゅうごにち
|-|26|-|にじゅうろくにち
|-|27|-|にじゅうしちにち|にじゅうななにち
|-|28|-|にじゅうはちにち
|-|29|-|にじゅうくにち
|-|30|-|さんじゅうにち|みそか
|-|31|-|さんじゅういちにち
|-|100|-|ひゃくにち
|-|1000|-|せんにち|*いっせんにち
|-|10000|-|いちまんにち
|-|100000000|-|いちおくにち
|-|0|-|ゼロにち|れいにち
|-|?|-|なんにち
}}<noinclude>[[Category:Japanese auto-table templates|number-counter:にち]]</noinclude>{{topics|ja|Time}}
2ko71vcwk1sfoumioyfj2r16d1vkd1l
一日
0
2331694
5724462
2026-06-10T03:20:20Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724462
wikitext
text/x-wiki
== ภาษาจีน ==
{{zh-forms}}
=== การออกเสียง ===
{{zh-pron
|m=一rì
|c=jat1 jat6
|h=pfs=yit-ngit
|mb=cì-nì
|md=siŏh-nĭk/ék-nĭk
|md_note=siŏh-nĭk - vernacular; ék-nĭk - literary
|mn=zz,kh,tn,tc,yl,hc,sx,mg:chi̍t-ji̍t/xm,qz,tp,tn,hc,lk,km,jj,ph:chi̍t-li̍t/tc:chi̍t-gi̍t
|mn-t=zêg8 rig8
|w=sh,sz:7iq gniq8
|cat=n
}}
=== คำนาม ===
{{head|zh|คำนาม}}
# {{lb|zh|literary|or|dialectal}} [[หนึ่ง]][[วัน]]
# {{lb|zh|literary}} [[วันใดวันหนึ่ง]][[ใน]][[อนาคต]]
# {{lb|zh|literary}} [[เมื่อวานนี้]]
# {{lb|zh|Teochew}} [[กลางวัน]], วัน
==== คำพ้องความ ====
* {{s|หนึ่งวัน}} {{q|literary}} {{zh-l|一旦}}, {{zh-l|一天}}
* {{s|เมื่อวานนี้}} {{zh-l|昨天}}
* {{s|กลางวัน}}
{{zh-dial|白天}}
==== ลูกคำ ====
{{col3|zh|一日為師,終身為父|一日三秋|一日不見,如隔三秋|冰凍三尺,非一日之寒|一日千里|一日一蘋果,醫生遠離我|有朝一日}}
=== คำสันธาน ===
{{head|zh|คำสันธาน}}
# {{lb|zh|Cantonese}} [[ตราบ]][[เท่า]][[ที่]];
#* {{quote-av|zh|year=1999|title=zh:喜劇之王<t:{{w|King of Comedy (film)|King of Comedy}}>|actor=w:Karen Mok|role=zh:杜娟兒}}
#*: {{zh-x|聽 唔 聽 到{dou3-2} 呀?聽 唔 聽 到{dou3-2} 呀?一日 未 嗌 c{k}u{a}t{t1},一日 都 要 演 落去,呢{ni1}啲 就係 我 成{seng4}日 同 你哋 講 嘅 專業。|Did you guys hear that? '''As long as''' [the director] hasn't called “cut”, one has to continue acting. This is what I've always been telling you – professionalism.|C}}
{{C|zh|เวลา|หนึ่ง}}
== ภาษาญี่ปุ่น ==
=== รากศัพท์ 1 ===
{{ja-kanjitab|yomi=juku|ついたち2|alt=朔日,朔,1日}}
{{IPAchar|/tuki tati/}} → {{IPAchar|/t͡suitat͡ɕi/}}
แรกเริ่มประสมจาก {{compound|ja|sort=ついたち|月|tr1=tsuki|t1=ดวงจันทร์; เดือน|立ち|tr2=tachi|t2=การยืน; การเริ่ม, การปรากฏ|pos2={{m|ja|連用形|tr=ren'yōkei||รูปต่อเนื่อง}}ของคำกริยา {{m|ja|立つ|tr=tatsu||ยืน; เริ่ม, ปรากฏ}}}}<ref name="KDJ">{{R:Kokugo Dai Jiten}}</ref><ref name="DJR">{{R:Daijirin}}</ref><ref name="DJS">{{R:Daijisen}}</ref>
==== การออกเสียง ====
{{ja-pron|ついたち|acc=4|acc_ref=DJR,NHK}}
{{ja-odaka-deaccent-exception|ついたち}}
==== คำนาม ====
{{ja-noun|ついたち}}
# [[วัน]][[แรก]][[ของ]][[เดือน]] (ปฏิทินสุริยคติหรือจันทรคติ)
===== หมายเหตุการใช้ =====
ついたち เป็นการออกเสียงที่สามัญที่สุดสำหรับความหมาย “วันแรกของเดือน” เมื่ออ้างถึงวันที่
===== ลูกคำ =====
{{col|ja
|{{ja-r|朔日%丸|ついたち%がん}}: a common kind of [[contraceptive]] in the {{w|Edo period}}, taken on the first of every month
|{{ja-r|朔日%草|ついたち%そう}}: alternate name for {{ja-r|福%寿%草|ふく%じゅ%そう}}: [[pheasant's eye]] or [[adonis]]
|{{ja-r|朔日%降り|ついたち%ぶり}}: [[rainfall]] or [[snowfall]] on the first day of the month
|{{ja-r|朔日%松|ついたち%まつ}}: a ceremonial potted pine tree placed at the household gate at the New Year
|{{ja-r|朔日%道|ついたち%みち}}, {{ja-r|朔日%路|ついたち%みち}}: a ceremonial clearing of a path to the family grave in preparation for the {{w|Bon Festival}}
}}
==== ดูเพิ่ม ====
{{ja-number-counter:日}}
=== รากศัพท์ 2 ===
{{ja-kanjitab|いち|にち|yomi=goon|alt=1日}}
จาก{{der|ja|ltc|sort=いちにち|一日|tr=ʔiɪt̚ ȵiɪt̚|lit=one + day}}; เทียบการออกเสียง{{cog|hak|-}}สมัยใหม่ ''yit-ngit''
เนื่องจากเป็นการออกเสียงแบบ[[呉音#Japanese|โกอง]] จึงเป็นไปได้ว่าเป็นคำยืมตั้งแต่สมัยเริ่มแรก
==== การออกเสียง ====
{{ja-pron|いちにち|acc=4|acc_ref=DJR,NHK|acc2=0|acc2_ref=DJR}}
* When used as a modifier, the term takes pitch accent pattern 0.
{{ja-odaka-deaccent-exception|いちにち}}
==== คำนาม ====
{{ja-noun|いちにち}}
# [[หนึ่ง]][[วัน]], 24 [[ชั่วโมง]]
#: {{ja-usex|'''一%日'''を過ごす|'''いち%にち''' を すごす|to spend a day}}
#* {{quote-book
|ja
|location=Tokyo
|publisher=w:Hakusensha
|genre=fiction
|author={{w|lang=ja|安孫子三和|Abiko, Miwa}}
|title={{lw|ja|みかん絵日記|みかん・絵日記}}
|trans-title={{w|Mikan Enikki|Mikan Picture Diary}}
|date=Dec 12 1997
|volume=2
|page=14
|chapter=ja:みかん・絵日記 おはなし⑦
|trans-chapter=Mikan Picture Diary: Story #7
}}
#*: {{ja-usex|充%実した'''一%日'''でしたね♡お父さん|^じゅう%じつした '''いち%にち''' でした ね ♡ おとう-さん|What a fun-filled '''day''' ♡ right honey?}}
# [[กลางวัน]], ช่วงเวลาตั้งแต่ดวงอาทิตย์ขึ้นถึงดวงอาทิตย์ตก
# {{lb|ja|sort=いちにち|metaphor}} [[ช่วง]][[เวลา]][[สั้น]] ๆ
#: {{ja-usex|ローマは'''一%日'''にして成らず|^ローマ は '''いち%にち''' に して ならず|Rome wasn't built in '''a day'''}}
# [[วันใดวันหนึ่ง]][[ที่]][[ไม่]][[ระบุ]]
# วันแรกของเดือน
===== หมายเหตุการใช้ =====
いちにち เป็นการออกเสียงที่ค่อนข้างสามัญมากกว่า いちじつ (รากศัพท์ 3) ในความหมายเดียวกัน และอาจมีความต่างในรูปแบบการใช้ไปตามภาษาถิ่น
ついたち (รากศัพท์ 1) เป็นการออกเสียงที่สามัญที่สุดสำหรับความหมาย “วันแรกของเดือน” เมื่ออ้างถึงวันที่
===== ลูกคำ =====
{{col|ja
|{{ja-r|一%日 一%善|いち%にち いち%ぜん}}
|{{ja-r|一%日 一%日|いち%にち いち%にち}}
|{{ja-r|一%日 一%夜|いち%にち いち%や}}
|{{ja-r|一%日 置き|いち%にち おき}}
|{{ja-r|一%日%経|いち%にち%きょう}}: dead memorial service where many gather to transcribe a [[sutra]] in one day
|{{ja-r|一%日 三%秋|いち%にち さん%しゅう}}
|{{ja-r|一%日 千%秋|いち%にち せん%しゅう}}
|{{ja-r|一%日%路|いち%にち%じ}}
|{{ja-r|一%日%中|いち%にち%じゅう}}
|{{ja-r|一%日 片%時|いち%にち へん%じ}}
|{{ja-r|一%日 増し|いち%にち まし}}
}}
==== ดูเพิ่ม ====
{{ja-number-counter:日}}
=== รากศัพท์ 3 ===
{{ja-kanjitab|いち|じつ|yomi=o|alt=1日}}
แรกสุดจาก{{der|ja|ltc|sort=いちにち|一日|tr=ʔiɪt̚ ȵiɪt̚|lit=หนึ่ง + วัน}}; เทียบการออกเสียง{{cog|nan|-}}สมัยใหม่ ''chi̍t-ji̍t''
เนื่องจากตัวแรกออกเสียงแบบ[[呉音#Japanese|โกอง]] และตัวที่สองออกเสียงแบบ[[漢音#Japanese|คังอง]], จึงเป็นไปได้ว่าเป็นการออกเสียงที่ผิดเพี้ยนไปจากคำยืมสมัยแรกเริ่ม
==== การออกเสียง ====
{{ja-pron|いちじつ|acc=4|acc_ref=DJR|acc2=0|acc2_ref=DJR,NHK}}
* When used as a modifier, the term takes pitch accent pattern 0.
{{ja-odaka-deaccent-exception|いちじつ}}
==== คำนาม ====
{{ja-noun|いちじつ}}
# {{lb|ja|literary}} หนึ่งวัน, 24 ชั่วโมง
# {{lb|ja|literary}} กลางวัน, ช่วงเวลาตั้งแต่ดวงอาทิตย์ขึ้นถึงดวงอาทิตย์ตก
# {{lb|ja|literary}} {{lb|ja|sort=いちにち|metaphor}} ช่วงเวลาสั้น ๆ
===== หมายเหตุการใช้ =====
いちにち (รากศัพท์ 2) เป็นการออกเสียงที่ค่อนข้างสามัญมากกว่าในความหมายเดียวกัน และอาจมีความต่างในรูปแบบการใช้ไปตามภาษาถิ่น
ついたち (รากศัพท์ 1) เป็นการออกเสียงที่สามัญที่สุดสำหรับความหมาย “วันแรกของเดือน” เมื่ออ้างถึงวันที่
===== ลูกคำ =====
{{col|ja
|{{ja-r|一%日 三%秋|いち%じつ さん%しゅう}}
|{{ja-r|一%日 千%秋|いち%じつ せん%しゅう}}
|{{ja-r|一%日 の%長|いち%じつ の%ちょう}}
}}
=== รากศัพท์ 4 ===
{{ja-kanjitab|いつ|k1=いっ|ひ|k2=ぴ|yomi=j|alt=1日}}
{{compound|ja|sort=いっぴ|一|tr1=ichi|t1=หนึ่ง|pos1=[[音読み#Japanese|อนโยมิ]], การออกเสียงที่รับมาจากภาษาจีน|日|tr2=hi|t2=วัน|pos2=[[訓読み#Japanese|คุนโยมิ]], การออกเสียงพื้นเมืองของภาษาญี่ปุ่น}}<ref name="DJR">{{R:Daijirin}}</ref>
==== การออกเสียง ====
{{ja-pron|いっぴ|acc=1|acc_ref=DJR}}
==== คำนาม ====
{{ja-noun|いっぴ|hhira=いつぴ}}
# {{lb|ja|sort=いっぴ|rare}} วันแรกของเดือน
===== หมายเหตุการใช้ =====
การออกเสียงเช่นนี้ค่อนข้างพบได้ยาก และอาจมีความต่างในรูปแบบการใช้ไปตามภาษาถิ่น
==== ดูเพิ่ม ====
{{ja-number-counter:日}}
=== รากศัพท์ 5 ===
{{ja-kanjitab|ひと|ひ|yomi=k|alt=1日}}
{{compound|ja|sort=ひとひ|一|tr1=hito|t1=หนึ่ง|日|tr2=hi|t2=วัน}};<ref name="KDJ">{{R:Kokugo Dai Jiten}}</ref><ref name="DJR">{{R:Daijirin}}</ref><ref name="DJS">{{R:Daijisen}}</ref> ปรากฏใน ''{{w|The Tale of Genji}}'' ตั้งแต่ต้นคริสต์ศตวรรษ 1000
==== การออกเสียง ====
{{ja-pron|ひとひ|acc=2|dev=1|acc_ref=DJR,NHK}}
==== คำนาม ====
{{ja-noun|ひとひ}}
# {{lb|ja|obsolete}} หนึ่งวัน, 24 ชั่วโมง
# {{lb|ja|obsolete}} กลางวัน, ช่วงเวลาตั้งแต่ดวงอาทิตย์ขึ้นถึงดวงอาทิตย์ตก
=== รากศัพท์ 6 ===
{{ja-kanjitab|yomi=kun,irr|ひと|ひ|k2=え|alt=1日}}
{{IPAchar|/hitohi/}} → {{IPAchar|/hitohe/}} → {{IPAchar|/hitoe/}}
การออกเสียงผิดเพี้ยนไปจาก ひとひ (รากศัพท์ 5)<ref name="KDJ">{{R:Kokugo Dai Jiten}}</ref>
==== การออกเสียง ====
{{ja-pron|ひとえ|dev=1}}
==== คำนาม ====
{{ja-noun|ひとえ|hhira=ひとへ}}
# {{lb|ja|sort=ひとえ|rare|obsolete}} {{syn of|ja|一日|tr=hitohi}}
===== หมายเหตุการใช้ =====
ความหมายทั้งหมดเหมือนกับ ひとひ (รากศัพท์ 5)
=== อ้างอิง ===
<references/>
:* {{R:Kanjipedia Kotoba|0000242300|〈一日〉}}
{{cln|ja|words with multiple readings}}
== ภาษาโอกินาวะ ==
=== คันจิ ===
{{ryu-kanji}}
=== การออกเสียง ===
{{ryu-readings
|kun=ちーたち
}}
=== รากศัพท์ ===
{{ryu-kanjitab|yomi=juku|ちーたち2}}
ปรากฏครั้งแรกใน {{l|und|취타지|ts=tsʰuj.tʰa.tsi}} (Haytong Ceykwukki, 1501)
แรกเริ่มประสมจาก {{compound|ryu|sort=ちーたち|月|tr1=chii|t1=ดวงจันทร์; เดือน|立ち|tr2=tachi|t2=การยืน; การเริ่ม, การปรากฏ|pos2={{m|ryu|連用形|tr=ren'yōkei||รูปต่อเนื่อง}}ของคำกริยา {{m|ryu|立ちゅん|tr=tatsu||ยืน; เริ่ม, ปรากฏ}}}}
=== การออกเสียง ===
* {{IPA|ryu|/t͡ɕiːtat͡ɕi/}}
=== คำนาม ===
{{ryu-noun|ちーたち2}} {{attention|ryu|added missing headword template- not sure what else this needs}}
# [[วัน]][[แรก]][[ของ]][[เดือน]] (ปฏิทินสุริยคติหรือจันทรคติ)
gtwgd70a9d8fylcy3py07xbjuvvfd40
いちじつ
0
2331695
5724463
2026-06-10T03:22:58Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724463
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
=== คำนาม ===
{{ja-noun}}
# {{ja-def|一日}} หนึ่งวัน; วันแรกของเดือน
# {{ja-def|一実}} (''พุทธ'') ความจริงแท้หนึ่งเดียว
7lzweuxjdmtyikx6hsitl0689o6jdpf
1日
0
2331696
5724468
2026-06-10T03:49:45Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724468
wikitext
text/x-wiki
== ภาษาญี่ปุ่น ==
{{ja-kanjitab}}
{{ja-see|一日}}
l4cbj02sevu67ykipdr0h09xls3jdng
nightclubs
0
2331697
5724473
2026-06-10T06:22:28Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด เรียงลำดับหัวเรื่องภาษา
5724473
wikitext
text/x-wiki
== ภาษาสเปน ==
=== คำนาม ===
{{head|es|รูปนาม}}
# {{plural of|es|nightclub}}
== ภาษาอังกฤษ ==
=== คำนาม ===
{{head|en|รูปนาม}}
# {{plural of|en|nightclub}}
=== คำกริยา ===
{{head|en|รูปกริยา}}
# {{inflection of|en|nightclub||s-verb-form}}
=== คำสลับอักษร ===
* {{anagrams|en|a=bcghilnstu|clubnights|club nights}}
mo9ok9ofbkbiqedg17il0aize77is3c
night club
0
2331698
5724474
2026-06-10T06:23:51Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724474
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== คำนาม ===
{{en-noun}}
# {{alternative form of|en|nightclub}}
#* {{quote-journal|en|date=2013-06-08|volume=407|issue=8839|page=52|magazine=w:The Economist
|title=[http://www.economist.com/news/international/21579039-chinas-growing-empire-ports-abroad-mainly-about-trade-not-aggression-new-masters The new masters and commanders]
|passage=From the ground, Colombo’s port does not look like much. Those entering it are greeted by wire fences, walls dating back to colonial times and security posts. For mariners leaving the port after lonely nights on the high seas, the delights of the B52 '''Night Club''' and Stallion Pub lie a stumble away.}}
jndj3n366ery150arjz06ef8n2eeyz0
5724475
5724474
2026-06-10T06:25:14Z
OctraBot
3198
/* ภาษาอังกฤษ */
5724475
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== คำนาม ===
{{en-noun}}
# {{alternative form of|en|nightclub}}
#* {{quote-journal|en|date=2013-06-08|volume=407|issue=8839|page=52|magazine=w:The Economist
|title=[http://www.economist.com/news/international/21579039-chinas-growing-empire-ports-abroad-mainly-about-trade-not-aggression-new-masters The new masters and commanders]
|passage=From the ground, Colombo’s port does not look like much. Those entering it are greeted by wire fences, walls dating back to colonial times and security posts. For mariners leaving the port after lonely nights on the high seas, the delights of the B52 '''Night Club''' and Stallion Pub lie a stumble away.|t=ตั้งแต่เริ่มต้น ท่าเรือโคลัมโบดูไม่ค่อยน่าสนใจเท่าไหร่ ผู้ที่เข้ามาจะพบกับรั้วลวดหนาม กำแพงที่สร้างมาตั้งแต่สมัยอาณานิคม และป้อมรักษาความปลอดภัย สำหรับกะลาสีเรือที่ออกจากท่าเรือหลังจากค่ำคืนอันโดดเดี่ยวกลางทะเล ความสนุกสนานของไนต์คลับ B52 และผับ Stallion อยู่ไม่ไกลนัก}}
kll5njru2n996lq89rpfe22ygiyb0pz
nightclubes
0
2331699
5724479
2026-06-10T06:45:57Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724479
wikitext
text/x-wiki
== ภาษาสเปน ==
=== คำนาม ===
{{head|es|รูปนาม}}
# {{plural of|es|nightclub}}
a9oxe9r7fdco6ufcg9ty76jjhnnv7dm
แม่แบบ:es-unadapted
10
2331700
5724480
2026-06-10T06:46:20Z
OctraBot
3198
นำเข้าจาก enwikt
5724480
wikitext
text/x-wiki
#REDIRECT [[Template:U:es:unadapted]]
gpk0i87tjz1sudcd15f4gm5pkaup2hc
nightclubber
0
2331701
5724484
2026-06-10T06:52:14Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด เรียงลำดับหัวเรื่องภาษา
5724484
wikitext
text/x-wiki
== ภาษาฝรั่งเศส ==
=== คำนาม ===
{{fr-noun|m}}
# {{l|en|nightclubber}}
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
{{ety|en|:af|nightclub|-er|text=+|tree=1}}
=== คำนาม ===
{{en-noun}}
# คนที่ไปเที่ยว[[ไนต์คลับ]]
{{C|en|บุคคล}}
6gv9r208njh9vxprhwfq9fjdxnqzshl
5724485
5724484
2026-06-10T06:52:26Z
OctraBot
3198
5724485
wikitext
text/x-wiki
== ภาษาฝรั่งเศส ==
=== คำนาม ===
{{fr-noun|m}}
# คนที่ไปเที่ยว[[ไนต์คลับ]]
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
{{ety|en|:af|nightclub|-er|text=+|tree=1}}
=== คำนาม ===
{{en-noun}}
# คนที่ไปเที่ยว[[ไนต์คลับ]]
{{C|en|บุคคล}}
8qc15qszofmtr47ymfm34ba6rgijeym
nightclubbers
0
2331702
5724486
2026-06-10T06:52:36Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด เรียงลำดับหัวเรื่องภาษา
5724486
wikitext
text/x-wiki
== ภาษาฝรั่งเศส ==
=== คำนาม ===
{{head|fr|รูปนาม|g=m}}
# {{plural of|fr|nightclubber}}
== ภาษาอังกฤษ ==
=== คำนาม ===
{{head|en|รูปนาม}}
# {{plural of|en|nightclubber}}
4az5vsu18ipxpsehsyoz0aslhbk81qb
nightclubby
0
2331703
5724487
2026-06-10T06:53:16Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724487
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
จาก{{suffix|en|nightclub|y}}
=== คำคุณศัพท์ ===
{{en-adj}}
# {{lb|en|informal}} มีลักษณะคล้ายคลึงหรือชวนให้นึกถึง[[ไนต์คลับ]]
#: {{ux|en|The place had a '''nightclubby''' atmosphere.}}
pbfnpnklf19fge04lxhv9k4l5ppa4sz
nightclub-goer
0
2331704
5724488
2026-06-10T06:54:32Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724488
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
จาก{{compound|en|nightclub|goer}}
=== คำนาม ===
{{en-noun}}
# คนที่ไปเที่ยว[[ไนต์คลับ]]
#* {{quote-book|en|title=Forces of power|author=William L. Taub|year=1979|ISBN=0448157756|page=8–9|passage=Her act became the hottest ticket in the country, and getting into the Ramona Room had become as difficult for the '''nightclub-goer''' as it had been for Jo in the first place.}}
{{C|en|บุคคล}}
8xkk8msk2xkcnepk787ap7dxcc93asq
nightclublike
0
2331705
5724489
2026-06-10T06:55:51Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด
5724489
wikitext
text/x-wiki
== ภาษาอังกฤษ ==
=== รากศัพท์ ===
จาก{{suffix|en|nightclub|like}}
=== คำคุณศัพท์ ===
{{en-adj}}
# มีลักษณะคล้ายคลึงหรือมีลักษณะเฉพาะของ[[ไนต์คลับ]]
#* {{quote-journal|en|date=July 31, 2007|author=Jane L. Levere|title=Once Stodgy, Hotel Bars Revitalize Image|work=New York Times|url=http://www.nytimes.com/2007/07/31/business/31bar.html
|passage=The Conrad in Miami has closed its Noir Bar, which had a South Beach, '''nightclublike''' atmosphere, and is replacing it with a brighter, lighter bar.}}
nnorn5rvvo4nt1rdkr8t5v7qpycdjif
หมวดหมู่:en:กิจการ
14
2331706
5724494
2026-06-10T07:01:08Z
OctraBot
3198
สร้างหมวดหมู่อัตโนมัติ
5724494
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
ใบเสร็จรับเงิน
0
2331707
5724498
2026-06-10T07:07:22Z
OctraBot
3198
สร้างหน้าด้วย "== ภาษาไทย == === รากศัพท์ === {{com+|th|ใบเสร็จ|รับ|เงิน}} === การออกเสียง === {{th-pron|ไบ-เส็ด-รับ-เงิ็น}} === คำนามม === {{th-noun|ใบ}} # {{synonym of|th|ใบเสร็จ}}"
5724498
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{com+|th|ใบเสร็จ|รับ|เงิน}}
=== การออกเสียง ===
{{th-pron|ไบ-เส็ด-รับ-เงิ็น}}
=== คำนามม ===
{{th-noun|ใบ}}
# {{synonym of|th|ใบเสร็จ}}
rt6rs6hnvqajan5qsxwai2fvxn38oej
fandoms
0
2331708
5724499
2026-06-10T07:08:14Z
OctraBot
3198
นำเข้าจาก enwikt เก็บกวาด เรียงลำดับหัวเรื่องภาษา
5724499
wikitext
text/x-wiki
== ภาษาสเปน ==
=== คำนาม ===
{{head|es|รูปนาม|g=m-p}}
# {{noun form of|es|fandom||p}}
== ภาษาอังกฤษ ==
=== คำนาม ===
{{head|en|รูปนาม}}
# {{plural of|en|fandom}}
q3d1i9he8svr7phgu6wj66ey70iuur1
ไข่หวาน
0
2331709
5724500
2026-06-10T07:18:14Z
OctraBot
3198
เก็บกวาด
5724500
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|ไข่|หวาน}}
=== การออกเสียง ===
{{th-pron|ไข่-หฺวาน}}
=== คำนาม ===
{{th-noun}}
# [[ชื่อ]][[ขนม]][[อย่าง]][[หนึ่ง]][[ทำ]][[โดย]][[ต่อย]][[ไข่]][[ใส่]][[ลง]][[ใน]][[น้ำเชื่อม]][[ร้อน]] ๆ [[แล้ว]][[ต้ม]][[ให้]][[สุก]] [[มัก]]ใส่[[ขิง]][[ด้วย]]
# ไข่[[ที่]]ต้มในน้ำเชื่อม[[หรือ]][[น้ำกะทิ]][[ของ]][[ขนมหวาน]][[ชนิด]][[อื่น]] [[เช่น]] [[บัวลอย]] [[แกงบวด]]
mi68zy7irfvgzucoujwv2xq20e0q1mw
5724501
5724500
2026-06-10T07:20:33Z
OctraBot
3198
/* คำนาม */
5724501
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|ไข่|หวาน}}
=== การออกเสียง ===
{{th-pron|ไข่-หฺวาน}}
=== คำนาม ===
{{th-noun}}
# [[ชื่อ]][[ขนม]][[อย่าง]][[หนึ่ง]][[ทำ]][[โดย]][[ต่อย]][[ไข่]][[ใส่]][[ลง]][[ใน]][[น้ำเชื่อม]][[ร้อน]] ๆ [[แล้ว]][[ต้ม]][[ให้]][[สุก]] [[มัก]]ใส่[[ขิง]][[ด้วย]]
# ไข่[[ที่]]ต้มในน้ำเชื่อม[[หรือ]][[น้ำกะทิ]][[ของ]][[ขนมหวาน]][[ชนิด]][[อื่น]] [[เช่น]] [[บัวลอย]] [[แกงบวด]] [[รวมมิตร]]
k0h5urh5y7zbbjqz53332jti56kd80l
5724508
5724501
2026-06-10T07:39:15Z
OctraBot
3198
/* รากศัพท์ */
5724508
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{com+|th|ไข่|หวาน}}
=== การออกเสียง ===
{{th-pron|ไข่-หฺวาน}}
=== คำนาม ===
{{th-noun}}
# [[ชื่อ]][[ขนม]][[อย่าง]][[หนึ่ง]][[ทำ]][[โดย]][[ต่อย]][[ไข่]][[ใส่]][[ลง]][[ใน]][[น้ำเชื่อม]][[ร้อน]] ๆ [[แล้ว]][[ต้ม]][[ให้]][[สุก]] [[มัก]]ใส่[[ขิง]][[ด้วย]]
# ไข่[[ที่]]ต้มในน้ำเชื่อม[[หรือ]][[น้ำกะทิ]][[ของ]][[ขนมหวาน]][[ชนิด]][[อื่น]] [[เช่น]] [[บัวลอย]] [[แกงบวด]] [[รวมมิตร]]
re6huyq6508j2rvysvmijq7rjha5tx4
อ่อนหวาน
0
2331710
5724502
2026-06-10T07:31:02Z
OctraBot
3198
สร้างหน้าด้วย "== ภาษาไทย == === รากศัพท์ === {{compound|th|อ่อน|หวาน}} === การออกเสียง === {{th-pron|อ่อน-หฺวาน}} === คำคุณศัพท์ === {{th-adj}} # [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเพลงเป็นต้น) # [[งาม]][[ละมุนละไม]] # [[มี]]รสชาติ..."
5724502
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|อ่อน|หวาน}}
=== การออกเสียง ===
{{th-pron|อ่อน-หฺวาน}}
=== คำคุณศัพท์ ===
{{th-adj}}
# [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเพลงเป็นต้น)
# [[งาม]][[ละมุนละไม]]
# [[มี]][[รสชาติ]][[หวาน]][[น้อย]]
=== คำกริยา ===
{{th-adv}}
# ไพเราะ, น่าฟัง (ใช้กับการพูดหรือการร้องเป็นต้น)
ncg8vol6x67wukbithw6jsierrojya2
5724504
5724502
2026-06-10T07:32:29Z
OctraBot
3198
5724504
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|อ่อน|หวาน}}
=== การออกเสียง ===
{{th-pron|อ่อน-หฺวาน}}
=== คำคุณศัพท์ ===
{{th-adj}}
# [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเพลงเป็นต้น)
# [[งาม]][[ละมุนละไม]]
#: {{ux|th|หน้าตาอ่อนหวาน}}
#: {{ux|th|กิริยาอ่อนหวาน}}
# [[มี]][[รสชาติ]][[หวาน]][[น้อย]]
#: {{ux|th|แกงนี้อ่อนหวานเกินไป}}
=== คำกริยา ===
{{th-adv}}
# ไพเราะ, น่าฟัง (ใช้กับการพูดหรือการร้องเป็นต้น)
#: {{ux|th|เขาเป็นคนพูดจาอ่อนหวาน}}
elnyd2pdvmrie3sspe3ona2ilo8d4a1
5724505
5724504
2026-06-10T07:33:16Z
OctraBot
3198
/* คำคุณศัพท์ */
5724505
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|อ่อน|หวาน}}
=== การออกเสียง ===
{{th-pron|อ่อน-หฺวาน}}
=== คำคุณศัพท์ ===
{{th-adj}}
# [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเพลงเป็นต้น)
# [[งาม]][[ละมุนละไม]]
#: {{ux|th|หน้าตาอ่อนหวาน}}
#: {{ux|th|กิริยาอ่อนหวาน}}
# [[มี]][[รสชาติ]][[หวาน]][[น้อย]]
#: {{ux|th|แกงนี้อ่อนหวานไปหน่อย}}
=== คำกริยา ===
{{th-adv}}
# ไพเราะ, น่าฟัง (ใช้กับการพูดหรือการร้องเป็นต้น)
#: {{ux|th|เขาเป็นคนพูดจาอ่อนหวาน}}
mz6hsk0bdy1s2u7s4yw9blitro645p3
5724506
5724505
2026-06-10T07:37:32Z
OctraBot
3198
/* คำคุณศัพท์ */
5724506
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{compound|th|อ่อน|หวาน}}
=== การออกเสียง ===
{{th-pron|อ่อน-หฺวาน}}
=== คำคุณศัพท์ ===
{{th-adj}}
# [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเสียงเป็นต้น)
# [[งาม]][[ละมุนละไม]]
#: {{ux|th|หน้าตาอ่อนหวาน}}
#: {{ux|th|กิริยาอ่อนหวาน}}
# [[มี]][[รสชาติ]][[หวาน]][[น้อย]]
#: {{ux|th|แกงนี้อ่อนหวานไปหน่อย}}
=== คำกริยา ===
{{th-adv}}
# ไพเราะ, น่าฟัง (ใช้กับการพูดหรือการร้องเป็นต้น)
#: {{ux|th|เขาเป็นคนพูดจาอ่อนหวาน}}
pdxn2wtrwu63n9vk84uvkv9ldkodelt
5724507
5724506
2026-06-10T07:38:58Z
OctraBot
3198
/* รากศัพท์ */
5724507
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{com+|th|อ่อน|หวาน}}
=== การออกเสียง ===
{{th-pron|อ่อน-หฺวาน}}
=== คำคุณศัพท์ ===
{{th-adj}}
# [[ไพเราะ]], [[น่า]][[ฟัง]] (ใช้กับคำพูดหรือเสียงเป็นต้น)
# [[งาม]][[ละมุนละไม]]
#: {{ux|th|หน้าตาอ่อนหวาน}}
#: {{ux|th|กิริยาอ่อนหวาน}}
# [[มี]][[รสชาติ]][[หวาน]][[น้อย]]
#: {{ux|th|แกงนี้อ่อนหวานไปหน่อย}}
=== คำกริยา ===
{{th-adv}}
# ไพเราะ, น่าฟัง (ใช้กับการพูดหรือการร้องเป็นต้น)
#: {{ux|th|เขาเป็นคนพูดจาอ่อนหวาน}}
9uwq5y18pi11hi3w032dgccpdiq30qa
ความอ่อนหวาน
0
2331711
5724503
2026-06-10T07:31:06Z
OctraBot
3198
สร้างคำอัตโนมัติ
5724503
wikitext
text/x-wiki
== ภาษาไทย ==
=== รากศัพท์ ===
{{prefix|th|ความ|อ่อนหวาน}}
=== การออกเสียง ===
{{th-pron|คฺวาม-อ่อน-หฺวาน}}
=== คำนาม ===
{{th-noun}}
# {{abstract noun of|th|อ่อนหวาน}}
461r4lh1f0fq9xc04hjobtbc0uk676w