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 " +&lrm; " 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 " +&lrm; " 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 &lrm; is what [[Module:affix]] has always done default_separator = data.allow_semicolon_separator and " +&lrm; " 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 = " +&lrm; ", 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 = " +&lrm; ", 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 = " +&lrm; ", 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|}}}|&nbsp;<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:&#32;}}<!-- -->{{#if:{{{brackets|}}}|&#91;}}<!-- -->{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!-- -->{{#if:{{{mini|}}}|v|view}}</spa..." 5724446 wikitext text/x-wiki <includeonly>{{#if:{{{nodiv|}}}|&nbsp;<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:&#32;}}<!-- -->{{#if:{{{brackets|}}}|&#91;}}<!-- -->[[{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!-- -->{{#if:{{{mini|}}}|v|view}}</span>]]<!-- -->&nbsp;<span style="font-size:80%;">•</span>&nbsp;[[{{TALKPAGENAME:{{transcluded pagename|{{{1}}}}}}}|<span title="Discuss this template" style="{{{fontstyle|}}}">{{#if:{{{mini|}}}|d|talk}}</span>]]<!-- -->{{#if:{{{noedit|}}}|<!--nothing-->|<!--else: -->&nbsp;<span style="font-size:80%;">•</span>&nbsp;[{{fullurl:{{transcluded pagename|{{{1}}}}}|action=edit}}<span title="Edit this template" style="{{{fontstyle|}}};">{{#if:{{{mini|}}}|e|edit}}</span>]<!-- -->}}<!-- -->{{#if:{{{brackets|}}}|]}}<!-- -->{{#if:{{{nodiv|}}}|<!--then: --></span>&nbsp;|<!--else: --></div>}}</includeonly><noinclude>{{documentation}}</noinclude> 0x1dwgz3z5mz2s4y46vuy4442u1r9pp 5724452 5724446 2026-06-10T02:41:10Z OctraBot 3198 5724452 wikitext text/x-wiki <includeonly>{{#if:{{{nodiv|}}}|&nbsp;<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:&#32;}}<!-- -->{{#if:{{{brackets|}}}|&#91;}}<!-- -->[[{{transcluded pagename|{{{1}}}}}|<span title="View this template" style="{{{fontstyle|}}}"><!-- -->{{#if:{{{mini|}}}|ด|ดู}}</span>]]<!-- -->&nbsp;<span style="font-size:80%;">•</span>&nbsp;[[{{TALKPAGENAME:{{transcluded pagename|{{{1}}}}}}}|<span title="Discuss this template" style="{{{fontstyle|}}}">{{#if:{{{mini|}}}|พ|พูดคุย}}</span>]]<!-- -->{{#if:{{{noedit|}}}|<!--nothing-->|<!--else: -->&nbsp;<span style="font-size:80%;">•</span>&nbsp;[{{fullurl:{{transcluded pagename|{{{1}}}}}|action=edit}}<span title="Edit this template" style="{{{fontstyle|}}};">{{#if:{{{mini|}}}|ก|แก้ไข}}</span>]<!-- -->}}<!-- -->{{#if:{{{brackets|}}}|]}}<!-- -->{{#if:{{{nodiv|}}}|<!--then: --></span>&nbsp;|<!--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