Wiksiyonaryo
tlwiktionary
https://tl.wiktionary.org/wiki/Wiksiyonaryo:Unang_Pahina
MediaWiki 1.47.0-wmf.24
case-sensitive
Midya
Natatangi
Usapan
Tagagamit
Usapang tagagamit
Wiksiyonaryo
Usapang Wiksiyonaryo
Talaksan
Usapang talaksan
MediaWiki
Usapang MediaWiki
Padron
Usapang padron
Tulong
Usapang tulong
Kategorya
Usapang kategorya
TimedText
TimedText talk
Module
Module talk
Event
Event talk
libro
0
3002
178355
178326
2026-10-23T00:50:31Z
GinawaSaHapon
3989
/* Espanyol */
178355
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
kefsc2uolwzi04fmbyd2ehfnkp72iby
178362
178355
2026-10-23T05:39:01Z
GinawaSaHapon
3989
/* Pangngalan */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178362
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
b5n1vrvf3mmxxzzfj2nqem1rpe6xemd
178363
178362
2026-10-23T05:39:47Z
GinawaSaHapon
3989
/* Etimolohiya 1 */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178363
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
kefsc2uolwzi04fmbyd2ehfnkp72iby
178364
178363
2026-10-23T05:40:00Z
GinawaSaHapon
3989
/* Espanyol */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178364
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
{{wp|es:}}
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
04jv19sxzjr5vpulwlpwpbuilnfr3g3
178366
178364
2026-10-23T05:44:36Z
GinawaSaHapon
3989
/* {{=es=}} */
178366
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
{{wp|es:}}
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
ma1yz6imegld5mcelz4mvs37y37o64e
178367
178366
2026-10-23T05:45:05Z
GinawaSaHapon
3989
/* {{=es=}} */
178367
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
{{ety|es|nl=1}}
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
ouglntsvwrvr103xetq1rfo3xze004s
178372
178367
2026-10-23T06:22:00Z
GinawaSaHapon
3989
/* Etimolohiya 2 */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178372
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
grye5krpdjkk11qyeolg1otectljh59
178379
178372
2026-10-23T06:53:26Z
GinawaSaHapon
3989
178379
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
=={{=osp=}}==
===Alternatibong pagbaybay===
* {{alter|osp|liuro}}
===Etimolohiya===
{{etymon|osp|:lbor|la:liber<alt:librum><id:peel>}}
{{lbor|osp|la|liber|librum}}.
===Pagbigkas===
* {{IPA|osp|/ˈliβɾo/}}
===Pangngalan===
{{osp-noun|m}}
# [[aklat]]
#* {{quote-book|osp|year=c. 1200|author=Almerich|title=[[w:Fazienda de Ultramar|Fazienda de Ultramar]]|section=f. 20v
|passage=dixo el nŕo ſenor a moẏſen qui peccare en mi deſfer loe de mio '''libro'''. Agora ue e di ami pueblo cuemo fable {{...}}
|norm=Dixo el nuestro Sennor a Moysen “Qui peccare en mí, desfer-lo-é de mío '''libro'''. Agora ve e di a mi pueblo cuemo fablé {{...}}”
|translation=Sinabi ng ating Panginoon kay Moises, "Kung sinuman ang nagkasala sa akin, aking buburahin sa '''aklat''' ko. Ngayon, humayo ka at sabihin mo sa aking bayan ang sinabi ko sa iyo. {{...}}”}}
====Anak na kataga====
{{topN}}
* {{desc|lad|livro//ליב'רו}}
* {{desc|es|libro}} {{see desc}}
{{bottomN}}
qwlkox58m419gfjnb1mj57ztoa8ziuo
178382
178379
2026-10-23T07:13:10Z
GinawaSaHapon
3989
/* Pangngalan */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178382
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# {{senseid|tl|aklat}} [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{senseid|tl|iskrip}} {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{senseid|tl|pagtutuos}} {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{senseid|tl|anatomiya}} {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro}} {{q|iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro}} {{q|ng baka at katulad}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
=={{=osp=}}==
===Alternatibong pagbaybay===
* {{alter|osp|liuro}}
===Etimolohiya===
{{etymon|osp|:lbor|la:liber<alt:librum><id:peel>}}
{{lbor|osp|la|liber|librum}}.
===Pagbigkas===
* {{IPA|osp|/ˈliβɾo/}}
===Pangngalan===
{{osp-noun|m}}
# [[aklat]]
#* {{quote-book|osp|year=c. 1200|author=Almerich|title=[[w:Fazienda de Ultramar|Fazienda de Ultramar]]|section=f. 20v
|passage=dixo el nŕo ſenor a moẏſen qui peccare en mi deſfer loe de mio '''libro'''. Agora ue e di ami pueblo cuemo fable {{...}}
|norm=Dixo el nuestro Sennor a Moysen “Qui peccare en mí, desfer-lo-é de mío '''libro'''. Agora ve e di a mi pueblo cuemo fablé {{...}}”
|translation=Sinabi ng ating Panginoon kay Moises, "Kung sinuman ang nagkasala sa akin, aking buburahin sa '''aklat''' ko. Ngayon, humayo ka at sabihin mo sa aking bayan ang sinabi ko sa iyo. {{...}}”}}
====Anak na kataga====
{{topN}}
* {{desc|lad|livro//ליב'רו}}
* {{desc|es|libro}} {{see desc}}
{{bottomN}}
0wx7d6pxfl8byvnoa7qu8fookdc1sgq
178383
178382
2026-10-23T07:14:22Z
GinawaSaHapon
3989
/* Pangngalan */ (using [[wikt:en:MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]])
178383
wikitext
text/x-wiki
=={{=tl=}}==
[[Talaksan:Delphine, Madame de Staël, Paris, 1803 04.jpg|thumb|mga libro (kahulugan 1)]]
===Alternatibong pagbaybay===
* {{alt|tl|libdo||obsolete}}
===Etimolohiya===
{{ety|tl|:bor|es:libro|tree=1}}
{{bor+|tl|es|libro}} na may paglipat sa diin, mula sa {{der|tl|la|liber|librum}}.
===Pagbigkas===
{{tl-pr|libró}}
===Pangngalan===
{{tl-noun|libró|b=+}}
# {{senseid|tl|aklat}} [[aklat]]
# {{lb|tl|colloquial}} [[talaan]] {{q|ng [[taya]], bayad, atbp.}}
#: {{syn|tl|aklat-talaan|libro-de-rehistro}}
# {{senseid|tl|iskrip}} {{lb|tl|theater}} [[iskrip]] ng isang [[dula]], [[opera]], o [[musikal]]
#: {{syn|tl|libreto}}
# {{senseid|tl|pagtutuos}} {{lb|tl|accounting}} [[kronolohiko|kronolohikong]] talaan ng mga [[bayad]] o [[resibo]]
#: {{syn|tl|libro de-kuwenta|aklat-tuosan|ledyer|dyornal}}
# {{senseid|tl|anatomiya}} {{lb|tl|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}} na karaniwang [[sangkap]] ng [[kare-kare]], [[goto]], atbp.
#: {{syn|tl|tuwalya|omasum}}
====Hinangong kataga====
{{col3|tl|libruhin|pagsasalibro}}
====Kaugnay na kataga====
{{col3|tl|libreto|libreriya|libreta|libro mayor|tenedor-de-libros}}
===Magbasa pa===
* {{R:Pambansang Diksiyonaryo}}
* {{R:Vocabulario de la lengua tagala 1613|389|Libro) Libdo (pc) C. qualquiera yalo entienden en eſpañol corupto}}
=={{=es=}}==
===Pagbigkas===
{{es-pr}}
===Etimolohiya 1===
{{etymon|es|:inh|osp:libro|tree=1}}
{{inh+|es|osp|libro}}, isang {{lbor|es|la|liber||aklat|nocap=1}}. May kaugnayan sa {{cog|ast|llibru}}, {{cog|ca|llibre}}, {{cog|fr|livre}}, {{cog|gl|libro}}, {{cog|it|libro}}{{,}} at {{cog|pt|livro}}.
====Pangngalan====
{{es-noun|m}}
{{wp|es:}}
# [[aklat]]
#: {{syn|es|códice|tomo|volumen}}
# [[iskrip]] ng isang [[dula]] o [[opera]]; {{l|tl|libro|id=iskrip}}; [[libreto]]
#: {{syn|es|libreto}}
# {{lb|es|figurative}} anumang [[lathalain]] na nagbibigay ng [[gabay]] o [[panuto]]
# {{lb|es|anatomy}} ikatlong bahagi ng [[sikmura]] ng isang [[ruminante]] {{q|[[baka]], [[usa]], atbp.}}; {{l|tl|libro|id=anatomiya}}
#: {{syn|es|librillo|omaso}}
# [[buwis]] na kinokolekta ng [[estado]]
=====Hiponimo=====
{{col|es
|gran libro
|libro blanco
|libro de acuerdos
|libro de asiento
|libro de becerro
|libro de bolsillo
|libro de caballerías
|libro de cabecera
|libro de caja
|libro de contabilidad
|libro de cuentas ajustadas
|libro de cuentos
|libro de escolaridad
|libro de estilo
|libro de familia
|libro de fondo
|libro de frases
|libro de hechizos
|libro de honor
|libro de horas
|libro de inventarios
|libro de la vida
|libro de las sombras
|libro de lo salvado
|libro de mano
|libro de memoria
|libro de misa
|Libro de Mormón
|libro de música
|libro de oro
|libro mayor
|libro de surtido
|libro de texto
|libro de visitas
|libro diario
|libro electrónico
|libro sagrado
}}
=====Hinangong kataga=====
{{col|es
|audiolibro
|cantar a libro abierto
|de libro
|hablar como un libro
|librito
|librote
|libraco
|librería
|libreta
|libro cerrado<t:saradong aklat><ll:idyoma>
|libro abierto
|libro de caballerías
|pulmón en libro
|teneduría de libros
|tragalibros
}}
=====Kaugnay na kataga=====
{{col|es
|librero
|libreto
}}
=====Anak na kataga=====
{{topN}}
* {{desc|cbk|libro}}
* {{desc|bcl|libro|bor=1}}
* {{desc|ceb|libro|bor=1}}
* {{desc|nhe|libro|bor=1}}
* {{desc|ivb|libro|bor=1}}
* {{desc|pbg|liuru|bor=1}}
* {{desc|qu|liwru|bor=1}}
* {{desc|tl|libro|bor=1}}
* {{desc|bor=1|nhi|libro}}
{{bottomN}}
====Tingnan din====
* {{l|es|tomo}}
===Etimolohiya 2===
====Pandiwa====
{{head|es|verb form}}
# {{es-verb form of|librar}}
===Sanggunian===
* {{R:es:DCECH|libro|643|vol=G–Ma}}
===Magbasa pa===
* {{R:es:DRAE}}
==Esperanto==
===Pangngalan===
<!--{{infl|eo|pangngalan}}-->
{{eo-noun}}
# [[aklat]]
=={{=osp=}}==
===Alternatibong pagbaybay===
* {{alter|osp|liuro}}
===Etimolohiya===
{{etymon|osp|:lbor|la:liber<alt:librum><id:peel>}}
{{lbor|osp|la|liber|librum}}.
===Pagbigkas===
* {{IPA|osp|/ˈliβɾo/}}
===Pangngalan===
{{osp-noun|m}}
# [[aklat]]
#* {{quote-book|osp|year=c. 1200|author=Almerich|title=[[w:Fazienda de Ultramar|Fazienda de Ultramar]]|section=f. 20v
|passage=dixo el nŕo ſenor a moẏſen qui peccare en mi deſfer loe de mio '''libro'''. Agora ue e di ami pueblo cuemo fable {{...}}
|norm=Dixo el nuestro Sennor a Moysen “Qui peccare en mí, desfer-lo-é de mío '''libro'''. Agora ve e di a mi pueblo cuemo fablé {{...}}”
|translation=Sinabi ng ating Panginoon kay Moises, "Kung sinuman ang nagkasala sa akin, aking buburahin sa '''aklat''' ko. Ngayon, humayo ka at sabihin mo sa aking bayan ang sinabi ko sa iyo. {{...}}”}}
====Anak na kataga====
{{topN}}
* {{desc|lad|livro//ליב'רו}}
* {{desc|es|libro}} {{see desc}}
{{bottomN}}
j1g61irqj6jg6unfncmwrhn4tud0682
Padron:es-noun
10
5436
178356
173249
2026-10-23T00:51:20Z
GinawaSaHapon
3989
178356
wikitext
text/x-wiki
{{#invoke:es-headword|show|nouns}}<!--
--><noinclude>{{documentation}}</noinclude>
4e1tgl0j5flhm53oqpnogop8knl20r0
Module:headword/data
828
31076
178360
174825
2026-10-23T02:11:34Z
GinawaSaHapon
3989
178360
Scribunto
text/plain
local headword_page_module = "Module:headword/page"
local list_to_set = require("Module:table").listToSet
local data = {}
------ 1. Lists which are converted into sets. ------
--[==[ var:
Large pages where we disable label tracking, red link checking and similar.
]==]
data.large_pages = list_to_set {
-- pages that consistently hit timeouts
"a",
-- pages that sometimes hit timeouts
"A",
"baba",
"de",
"e",
"i",
"lima",
"o",
"u",
"и",
"山",
"子",
"月",
"一",
"人",
}
--[==[ var:
Map from singular to plural, and from plural to itself, for recognized parts of speech with irregular plurals. Most of
these are invariable plurals, e.g. `kanji` is its own plural; but we also have `mora` plural `morae`.
]==]
data.irregular_plurals = list_to_set({
"cmavo",
"cmene",
"fu'ivla",
"gismu",
"Han tu",
"hanja",
"hanzi",
"jyutping",
"kana",
"kanji",
"lujvo",
"phrasebook",
"pinyin",
"rafsi",
}, function(_, item)
return item
end)
local irregular_plurals = data.irregular_plurals
-- Irregular non-zero plurals AND any regular plurals where the singular ends in "s",
-- because the module assumes that inputs ending in "s" are plurals. The singular and
-- plural both need to be added, as the module will generate a default plural if
-- the input doesn't match a key in this table.
for sg, pl in next, {
mora = "morae"
} do
irregular_plurals[sg], irregular_plurals[pl] = pl, pl
end
--[==[ var:
Recognized lemmas. If the part of speech in {{tl|head}} is set to one of these or its singular equivalent, the category
'LANG lemmas' will automatically be added. If the part of speech is not a singular or plural lemma or non-lemma form and
is not an abbreviation that expands to a recognized lemma or non-lemma form, the page will be added to various tracking
categories:
* [[Special:WhatLinksHere/Wiktionary:Tracking/headword/unrecognized pos]]
* [[Special:WhatLinksHere/Wiktionary:Tracking/headword/unrecognized pos/LANG]]
* [[Special:WhatLinksHere/Wiktionary:Tracking/headword/unrecognized pos/pos/POS]]
* [[Special:WhatLinksHere/Wiktionary:Tracking/headword/unrecognized pos/pos/POS/LANG]]
]==]
data.lemmas = list_to_set{
"daglat", -- "abbreviations",
"akronimo", -- "acronyms",
"pang-uri", -- "adjectives",
"adnominal", -- "adnominals",
"adposisyon",
"pang-abay", -- "adverbs",
"panlapi", -- "affixes",
"ambiposisyon",
"artikulo", -- "articles", --Dahil hindi hinihiwalay ng Tagalog ang articles and determiners, determiners will have "pantukoy" while articles will have "artikulo"
"kabilaan", -- "circumfixes",
"sirkumposisyon",
"pampangkat",
"cmavo",
"klaster na cmavo",
"cmene",
"anyong nagsasama",
"pangatnig", -- "conjunctions",
"pamilang",
"pantukoy", --"determiners",
"tuldik", -- "diacritical marks",
"digrapo", -- "digraphs",
"pang-uring pahambing na magkatulad", --"equative adjectives",
"fu'ivla",
"gismu",
"sulat Han", -- "Han characters",
"Han tu",
"hanja",
"hanzi",
"ideopono",
"idyoma", -- "idioms",
"gitlapi", -- "infixes",
"inisyalismo", -- "initialisms",
"tandang iterasyon",
"gitnaan",
"padamdam", -- "interjections",
"kana",
"kanji",
"titik", -- "letters",
"pang-angkop", -- "ligatures",
"logogramo", --"logograms"
"lujvo",
"morae",
"morpema", -- "morphemes",
"di-bahagi",
"pangngalan", -- "nouns",
"bilang", -- "numbers",
"simbolong pamilang", --"numeral symbols",
"pamilang", --"numerals",
"partikulo", -- "particles",
"parirala", -- "phrases",
"posposisyon",
"pariralang posposisyon",
"predikatibo",
"unlapi", -- "prefixes",
"pariralang preposisyon", --"prepositional phrases",
"pang-ukol", -- "prepositions",
"prepandiwa",
"pang-abay na pronominal", -- "pronominal adverbs",
"panghalip", -- "pronouns",
"pangngalang pantangi", -- "proper nouns",
"salawikain", -- "proverbs",
"bantas", -- "punctuation marks",
"pamanggit", -- "relatives",
"ugat", -- "roots",
"tangkay", -- "stems",
"hulapi", -- "suffixes",
"pantig", -- "syllables",
"simbolo", -- "symbols",
"pandiwa", -- "verbs",
}
--[==[ var:
Recognized non-lemma forms. If the part of speech in {{tl|head}} is set to one of these or its singular equivalent, the
category 'LANG non-lemma forms' will automatically be added. If the part of speech is not a singular or plural lemma or
non-lemma form and is not an abbreviation that expands to a recognized lemma or non-lemma form, the page will be added
to various tracking categories; see the documentation of `data.lemmas`.
]==]
data.nonlemmas = list_to_set{
"anyong aktibong pandiwari", --"active participle forms",
"aktibong pandiwari", --"active participles",
"pandiwaring pang-uri", --"adjectival participles",
"anyong kaukulan ng pang-uri", --"adjective case forms",
"anyong pang-uri", --"adjective forms",
"anyong pambabae ng pang-uri", --"adjective feminine forms",
"anyong maramihan ng pang-uri", --"adjective plural forms",
"anyong pang-abay", --"adverb forms",
"pandiwaring pang-abay", --"adverbial participles",
"pandiwaring tagaganap",
"anyong artikulo", --"article forms",
"anyong kabilaan", --"circumfix forms",
"anyong pinagsama",
"anyong pahambing na pang-uri", --"comparative adjective forms",
"pang-uring pahambing", -- "comparative adjectives",
"anyong pahambing na pang-abay", -- "comparative adverb forms",
"pang-abay na pahambing", -- "comparative adverbs",
"anyong pangatnig", --"conjunction forms",
"kontraksiyon", --"contractions",
"konpandiwa",
"anyong pahambing na pantukoy", --"determiner comparative forms",
"anyong pantukoy", --"determiner forms",
"anyong pasukdol na pantukoy", --"determiner superlative forms",
"pangngalang pinaliit", -- "diminutive nouns",
"pang-uring palamang", --"elative adjectives",
"anyong pang-uring pahambing na magkatulad", -- "equative adjective forms",
"pang-uring pahambing na magkatulad", --"equative adjectives",
"pandiwaring panghinaharap", --"future participles",
"herundiyo", --"gerunds",
"anyong pawatas", --"infinitive forms",
"pawatas", -- "infinitives",
"anyong padamdam", --"interjection forms",
"jyutping",
"maling baybay", --"misspellings",
"pandiwaring negatibo", --"negative participles",
"pandiwaring pangngalan", --"nominal participles",
"anyong kaukulan ng pangngalan", --"noun case forms",
"anyong panggawa ng pangngalan",
"anyong pangngalang dalawahan", --"noun dual forms",
"anyong pangngalan", --"noun forms",
"anyong pangngalang kaunti", --"noun paucal forms",
"anyong pangngalang maramihan", -- "noun plural forms",
"anyong pangngalang paari", --"noun possessive forms",
"anyong pangngalang isahan", --"noun singulative forms",
"anyong pamilang", --"numeral forms",
"pandiwari", -- "participles",
"anyong pandiwari", --"participle forms",
"anyong partikulo", --"particle forms",
"pasibong pandiwari", --"passive participles",
"aktibong pandiwaring pangnakaraan", -- "past active participles",
"pandiwaring pang-abay na pangnakaraan", --"past adverbial participles",
"pandiwaring pangnakaraan", -- "past participles",
"anyong pandiwaring pangnakaraan", -- "past participle forms",
"anyong pasibong pandiwaring pangnakaraan", --"past passive participles",
"aktibong pandiwaring perpekto", --"perfect active participles",
"pandiwaring perpekto", --"perfect participles",
"pasibong pandiwaring perpekto", --"perfect passive participles",
"pinyin",
"maramihan", -- "plurals",
"anyong posposisyon",
"anyong unlapi", --"prefix forms",
"pang-ukol na kontraksiyon", --"preposition contractions",
"anyong pang-ukol", --"preposition forms",
"panghalip na pang-ukol", -- "prepositional pronouns",
"aktibong pandiwaring pangkasalukuyan", --" present active participles"
"aktibong pandiwaring pang-abay na pangkasalukuyan", --"present adverbial participles",
"anyong pandiwaring pangkasalukuyan", --"present participles",
"pasibong pandiwaring pangkasalukuyan", --"present passive participles",
"anyong prepandiwa",
"anyong panghalip", --"pronoun forms",
"anyong panghalip paari", --"pronoun possessive forms",
"anyong pangngalang pantangi", --"proper noun forms",
"anyong pangngalang pantanging maramihan", --"proper noun plural forms",
"rafsi",
"romanisasyon", --"romanizations",
"anyong ugat", --"root forms",
"isahan", --"singulatives",
"anyong hulapi", --"suffix forms",
"anyong pang-uring pasukdol", --"superlative adjective forms",
"pang-uring pasukdol", -- "superlative adjectives",
"anyong pang-abay na pasukdol", --"superlative adverb forms",
"pang-abay na pasukdol", -- "superlative adverbs",
"anyong pandiwa", --"verb forms",
"pandiwang pangngalan", -- "verbal nouns",
}
--[==[ var:
List of languages that will not have links to separate parts of the headword.
]==]
data.no_multiword_links = list_to_set{
"zh",
}
--[==[ var:
List of languages that will not have `LANG multiword terms` categories added. There are various reasons why languages
are in this list: (a) words are written without spaces between them; (b) syllables are written with spaces between them;
(c) variant reconstructions are notated with a tilde surrounded by spaces; (d) the language is a sign language, where
pagenames are multiword descriptions of the gesture(s) required to make an individual sign; (e) some other weirdnesses.
]==]
data.no_multiword_cat = list_to_set{
-------- Languages without spaces between words (sometimes spaces between phrases) --------
"blt", -- Tai Dam
"ja", -- Japanese
"khb", -- Lü
"km", -- Khmer
"lo", -- Lao
"mnw", -- Mon
"my", -- Burmese
"nan", -- Min Nan (some words in Latin script; hyphens between syllables)
"nan-hbl", -- Hokkien (some words in Latin script; hyphens between syllables)
"nod", -- Northern Thai
"ojp", -- Old Japanese
"shn", -- Shan
"sou", -- Southern Thai
"tdd", -- Tai Nüa
"th", -- Thai
"tts", -- Isan
"twh", -- Tai Dón
"txg", -- Tangut
"zh", -- Chinese (all varieties with Chinese characters)
"zkt", -- Khitan
-------- Languages with spaces between syllables --------
"ahk", -- Akha
"aou", -- A'ou
"atb", -- Zaiwa
"byk", -- Biao
"cdy", -- Chadong
--"duu", -- Drung; not sure
--"hmx-pro", -- Proto-Hmong-Mien
--"hnj", -- Green Hmong; not sure
"huq", -- Tsat
"ium", -- Iu Mien
--"lis", -- Lisu; not sure
"mtq", -- Muong
--"mww", -- White Hmong; not sure
"onb", -- Lingao
--"sit-gkh", -- Gokhy; not sure
--"swi", -- Sui; not sure
"tbq-lol-pro", -- Proto-Loloish
"tdh", -- Thulung
"ukk", -- Muak Sa-aak
"vi", -- Vietnamese
"yig", -- Wusa Nasu
"zng", -- Mang
-------- Languages with ~ with surrounding spaces used to separate variants --------
"mkh-ban-pro", -- Proto-Bahnaric
"sit-pro", -- Proto-Sino-Tibetan; listed above
-------- Other weirdnesses --------
"mul", -- Translingual; gestures, Morse code, etc.
"aot", -- Atong (India); bullet is a letter
-------- All sign languages --------
"ads",
"aed",
"aen",
"afg",
"ase",
"asf",
"asp",
"asq",
"asw",
"bfi",
"bfk",
"bog",
"bqn",
"bqy",
"bvl",
"bzs",
"cds",
"csc",
"csd",
"cse",
"csf",
"csg",
"csl",
"csn",
"csq",
"csr",
"doq",
"dse",
"dsl",
"ecs",
"esl",
"esn",
"eso",
"eth",
"fcs",
"fse",
"fsl",
"fss",
"gds",
"gse",
"gsg",
"gsm",
"gss",
"gus",
"hab",
"haf",
"hds",
"hks",
"hos",
"hps",
"hsh",
"hsl",
"icl",
"iks",
"ils",
"inl",
"ins",
"ise",
"isg",
"isr",
"jcs",
"jhs",
"jls",
"jos",
"jsl",
"jus",
"kgi",
"kvk",
"lbs",
"lls",
"lsl",
"lso",
"lsp",
"lst",
"lsy",
"lws",
"mdl",
"mfs",
"mre",
"msd",
"msr",
"mzc",
"mzg",
"mzy",
"nbs",
"ncs",
"nsi",
"nsl",
"nsp",
"nsr",
"nzs",
"okl",
"pgz",
"pks",
"prl",
"prz",
"psc",
"psd",
"psg",
"psl",
"pso",
"psp",
"psr",
"pys",
"rms",
"rsl",
"rsm",
"sdl",
"sfb",
"sfs",
"sgg",
"sgx",
"slf",
"sls",
"sqk",
"sqs",
"ssp",
"ssr",
"svk",
"swl",
"syy",
"tse",
"tsm",
"tsq",
"tss",
"tsy",
"tza",
"ugn",
"ugy",
"ukl",
"uks",
"vgt",
"vsi",
"vsl",
"vsv",
"xki",
"xml",
"xms",
"ygs",
"ysl",
"zib",
"zsl",
}
--[==[ var:
List of languages where a hyphen is not considered a word separator for the `LANG multiword terms` category. There are
numerous reasons why languages are in this list; by each language should be listed the reason for inclusion.
]==]
data.hyphen_not_multiword_sep = list_to_set{
"akk", -- Akkadian; hyphens between syllables
"akl", -- Aklanon; hyphens for mid-word glottal stops
"ber-pro", -- Proto-Berber; morphemes separated by hyphens
"ceb", -- Cebuano; hyphens for mid-word glottal stops
"cnk", -- Khumi Chin; hyphens used in single words
"cpi", -- Chinese Pidgin English; Chinese-derived words with hyphens between syllables
"de", -- German; too many false positives
"esx-esk-pro", -- hyphen used to separate morphemes
"fi", -- Finnish; hyphen used to separate components in compound words if the final and initial vowels match, respectively
"gd", -- Scottish Gaelic; too many false positives like [[a-chianaibh]], [[a-nìos]], [[an-dè]] and other adverbs in a- and an-
"hil", -- Hiligaynon; hyphens for mid-word glottal stops
"hnn", -- Hanunoo; too many false positives
"ilo", -- Ilocano; hyphens for mid-word glottal stops
"kne", -- Kankanaey; hyphens for mid-word glottal stops
"lcp", -- Western Lawa; dash as syllable joiner
"lwl", -- Eastern Lawa; dash as syllable joiner
"mfa", -- Pattani Malay in Thai script; dash as syllable joiner
"mkh-vie-pro", -- Proto-Vietic; morphemes separated by hyphens
"msb", -- Masbatenyo; too many false positives
"tl", -- Tagalog; too many false positives
"war", -- Waray-Waray; too many false positives
"yo", -- Yoruba; hyphens used to show lengthened nasal vowels
}
--[==[ var:
List of languages that will not have `LANG masculine nouns` and similar categories added. Generally, these languages are
lacking gender but use the gender field for other purposes. (This is a massive hack and should be changed.)
]==]
data.no_gender_cat = list_to_set{
-- Languages without gender but which use the gender field for other purposes
"ja",
"th",
}
--[==[ var:
List of languages where [[Module:headword]] should not attempt to generate a transliteration even if the term is written
in a non-Latin script. FIXME: Notate reasons why each language is in this list.
]==]
data.notranslit = list_to_set{
"ams",
"az",
"bbc",
"bug",
"cdo",
"cia",
"cjm",
"cjy",
"cmn",
"cnp",
"cpi",
"cpx",
"csp",
"czh",
"czo",
"gan",
"hak",
"hnm",
"hsn",
"ja",
"kzg",
"lad",
"ltc",
"luh",
"lzh",
"mnp",
"ms",
"mul",
"mvi",
"nan",
"nan-dat",
"nan-hbl",
"nan-hlh",
"nan-lnx",
"nan-tws",
"nan-zhe",
"nan-zsh",
"och",
"oj",
"okn",
"ryn",
"rys",
"ryu",
"sh",
"sjc",
"tgt",
"th",
"tkn",
"tly",
"txg",
"und",
"vi",
"wuu",
"xug",
"yoi",
"yox",
"yue",
"za",
"zh",
"zhx-sic",
"zhx-tai",
}
--[==[ var:
List of languages that will default to `sccat` being true, i.e. categories like `LANG POS in SCRIPT script` will
automatically be generated. This can be overridden using {{para|sccat|0}} in {{tl|head}} or setting `sccat` to
`false` in Lua.
]==]
data.default_sccat = list_to_set{
"inc-apa",
"inc-ash",
"kfr",
"ks",
"mr",
"mwr",
"inc-oaw",
"inc-ohi",
"omr",
"inc-opa",
"phr",
"pi",
"pra",
"sa",
"skr",
"sd",
}
--[==[ var:
List of script codes for which a script-tagged display title will be added.
]==]
data.toBeTagged = list_to_set{
"Ahom",
"Arab",
"fa-Arab",
"glk-Arab",
"kk-Arab",
"ks-Arab",
"ku-Arab",
"mzn-Arab",
"ms-Arab",
"ota-Arab",
"pa-Arab",
"ps-Arab",
"sd-Arab",
"tt-Arab",
"ug-Arab",
"ur-Arab",
"Armi",
"Armn",
"Avst",
"Bali",
"Bamu",
"Batk",
"Beng",
"as-Beng",
"Bopo",
"Brah",
"Brai",
"Bugi",
"Buhd",
"Cakm",
"Cans",
"Cari",
"Cham",
"Cher",
"Copt",
"Cprt",
"Cyrl",
"Cyrs",
"Deva",
"Dsrt",
"Egyd",
"Egyp",
"Ethi",
"Geok",
"Geor",
"Glag",
"Goth",
"Grek",
"Polyt",
"polytonic",
"Gujr",
"Guru",
"Hang",
"Hani",
"Hano",
"Hebr",
"Hira",
"Hluw",
"Ital",
"Java",
"Kali",
"Kana",
"Khar",
"Khmr",
"Knda",
"Kthi",
"Lana",
"Laoo",
"Latn",
"Latf",
"Latg",
"Latnx",
"Latinx",
"pjt-Latn",
"Lepc",
"Limb",
"Linb",
"Lisu",
"Lyci",
"Lydi",
"Mand",
"Mani",
"Marc",
"Merc",
"Mero",
"Mlym",
"Mong",
"mnc-Mong",
"sjo-Mong",
"xwo-Mong",
"Mtei",
"Mymr",
"Narb",
"Nkoo",
"Nshu",
"Ogam",
"Olck",
"Orkh",
"Orya",
"Osma",
"Ougr",
"Palm",
"Phag",
"Phli",
"Phlv",
"Phnx",
"Plrd",
"Prti",
"Rjng",
"Runr",
"Samr",
"Sarb",
"Saur",
"Sgnw",
"Shaw",
"Shrd",
"Sinh",
"Sora",
"Sund",
"Sylo",
"Syrc",
"Tagb",
"Tale",
"Talu",
"Taml",
"Tang",
"Tavt",
"Telu",
"Tfng",
"Tglg",
"Thaa",
"Thai",
"Tibt",
"Ugar",
"Vaii",
"Xpeo",
"Xsux",
"Yiii",
"Zmth",
"Zsym",
"Ipach",
"Music",
"Rumin",
}
--[==[ var:
Parts of speech which will not be categorised in categories like `English terms spelled with É` if the term is the
character in question (e.g. the letter entry for English [[é]]). This contrasts with entries like the French adjective
[[m̂]], which is a one-letter word spelled with the letter.
]==]
data.pos_not_spelled_with_self = list_to_set{
"tuldik", -- "diacritical marks",
"sulat Han", -- "Han characters",
"Han tu",
"hanja",
"hanzi",
"tandang iterasyon",
"kana",
"kanji",
"titik", -- "letters",
"pang-angkop", -- "ligatures",
"logogramo", --"logograms"
"morae",
"simbolong pambilang", --"numeral symbols",
"pambilang", --"numerals",
"bantas", --"punctuation marks",
"pantig", -- "syllables",
"simbolo", -- "symbols",
}
------ 2. Lists not converted into sets. ------
--[==[ var:
Recognized aliases for parts of speech (param 2=). Key is the short form and value is the canonical singular (not
pluralized) form. It is singular so the same table can be used in [[Module:form of]] for the {{para|p}}/{{para|POS}}
param and [[Module:links]] for the pos= param. Note that any part of speech, abbreviated or not, can be suffixed with
`f` to generate the corresponding non-lemma form part of speech, such as `adjf`, `af` or `adjectivef` for
`adjective form`, and `nounf` or `nf` for `noun form`. This expansion happens even when it does not make sense for the
given part of speech (e.g. `pclf` expands to `particle form` and `symf` expands to `symbol form`), and currently also,
at least in [[Module:headword]] (but not [[Module:links]]), even if the part before the `f` is not a recognized part of
speech or abbreviation (hence `nerf` expands to `ner form`).
]==]
data.pos_aliases = {
a = "pang-uri",
adj = "pang-uri",
pnr = "pang-uri", --diksiyonaryo.ph abbr
adv = "pang-abay",
pnb = "pang-abay", --diksiyonaryo.ph abbr
art = "artikulo",
det = "pantukoy",
pnt = "pantukoy", --diksiyonaryo.ph abbr
compadj = "pang-uring pahambing",
compadv = "pang-abay na pahambing",
conj = "pangatnig",
conv = "konpandiwa",
int = "padamdam",
interj = "padamdam",
intj = "padamdam",
pdd = "padamdam", --diksiyonaryo.ph abbr
n = "pangngalan",
png = "pangngalan", --diksiyonaryo.ph abbr
-- the next two support Algonquian languages; see also vii/vai/vti/vta below
na = "pangngalang buhay",
ni = "pangngalang di-buhay",
num = "pambilang",
part = "pandiwari",
pcl = "partikulo",
phr = "parirala",
pn = "pangngalang pantangi",
postp = "posposisyon",
pref = "unlapi",
prep = "pang-ukol",
prepphr = "pariralang pang-ukol",
prespart = "pandiwaring pangnakaraan",
pron = "panghalip",
pnh = "panghalip", --diksiyonaryo.ph abbr
prop = "pangngalang pantangi",
proper = "pangngalang pantangi",
propn = "pangngalang pantangi",
rom = "romanisasyon",
romanisation = "romanisasyon",
romanisations = "romanisasyon",
suf = "hulapi",
supadj = "pang-uring pasukdol",
supadv = "pang-abay na pasukdol",
sym = "simbolo",
v = "pandiwa",
vb = "pandiwa",
pnd = "pandiwa", --diksiyonaryo.ph abbr
vi = "pandiwang intrasitibo",
vt = "pandiwang transitibo",
-- the next four support Algonquian languages
vii = "pandiwang intransitibong di-buhay",
vai = "pandiwang intransitibong buhay",
vti = "pandiwang transitibong di-buhay",
vta = "pandiwang transitibong buhay",
pnl = "panlapi", --diksiyonaryo.ph abbr
-- redirect EN to TL
abbreviation = "daglat",
acronym = "akronimo",
adjective = "pang-uri",
adverb = "pang-abay",
article = "artikulo",
circumfix = "kabilaan",
["comparative adjective"] = "pang-uring pahambing",
["comparative adverb"] = "pang-abay na pahambing",
conjunction = "pangatnig",
determiner = "pantukoy",
["diacritical mark"] = "tuldik",
digraph = "digrapo",
["equative adjective"] = "pang-uring pahambing na magkatulad",
["Han character"] = "sulat Han",
["idiom"] = "sawikain",
infix = "gitlapi",
initialism = "inisyalismo",
interjection = "padamdam",
letter = "titik",
logograms = "logogramo",
morpheme = "morpema",
noun = "pangngalan",
number = "bilang",
numeral = "pambilang",
["numeral symbols"] = "simbolong pambilang",
participle = "pandiwari",
particle = "partikulo",
phrase = "parirala",
["proper noun"] = "pangngalang pantangi",
prefix = "unlapi",
preposition = "pang-ukol",
["prepositional phrase"] = "pariralang pang-ukol",
["pronominal adverbs"] = "pang-abay na panghalip",
pronoun = "panghalip",
proverb = "salawikain",
["punctuation marks"] = "bantas",
romanization = "romanisasyon",
relatives = "pamanggit",
root = "ugat",
stem = "tangkay",
suffix = "hulapi",
["superlative adjective"] = "pang-uring pasukdol",
["superlative adverb"] = "pang-abay na pasukdol",
syllable = "pantig",
symbol = "simbolo",
verb = "pandiwa",
["intransitive verb"] = "pandiwang intransitibo",
["transitive verb"] = "pandiwang transitibo",
["transitive and intransitive verb"] = "pandiwang transitibo at intransitibo",
--nonlemmas
["active participle forms"] = "anyong aktibong pandiwari",
["active participles"] = "pasibong pandiwari",
["adjectival participles"] = "pandiwaring pang-uri",
["adjective case form"] = "anyong kaukulan ng pang-uri",
["adjective form"] = "anyong pang-uri",
["adjective feminine form"] = "anyong pang-uring pambabae",
["adjective plural form"] = "anyong pang-uring maramihan",
["adverb form"] = "anyong pang-abay",
["adverbial participles"] = "pandiwaring pang-abay",
--"agent participles",
["article form"] = "anyong pantukoy",
["circumfix form"] = "anyong kabilaan",
--"combined form",
["comparative adjective form"] = "anyong pang-uring pahambing",
["comparative adjectives"] = "pang-uring pahambing",
["comparative adverb form"] = "anyong pang-abay na pahambing",
["comparative adverbs"] = "pang-abay na pahambing",
["conjunction form"] = "anyong pangatnig",
["contractions"] = "kontraksiyon",
--"converbs",
["determiner comparative form"] = "anyong pantukoy na pahambing",
["determiner form"] = "anyong pantukoy",
["determiner superlative form"] = "anyong pantukoy na pasukdol",
["diminutive nouns"] = "pangngalang pampaliit",
["elative adjectives"] = "pang-uring palamang",
["equative adjective form"] = "anyong pang-uring pahambing na magkatulad",
["equative adjectives"] = "pang-uring pahambing na magkatulad",
["future participles"] = "pandiwaring panghinaharap",
["gerunds"] = "herundiyo",
["infinitive form"] = "anyong pawatas",
["infinitives"] = "pawatas",
["interjection form"] = "anyong padamdam",
--"jyutping",
["misspellings"] = "maling baybay",
["negative participles"] = "pandiwaring negatibo",
["nominal participles"] = "pandiwaring pangngalan",
["noun case form"] = "anyong kaukulan ng pangngalan",
--"noun construct form",
["noun dual form"] = "anyong pangngalang dalawahan",
["noun form"] = "anyong pangngalan",
["noun paucal form"] = "anyong pangngalang kaunti",
["noun plural form"] = "anyong pangngalang maramihan",
["noun possessive form"] = "anyong pangngalang paari",
["noun singulative form"] = "anyong pangngalang isahan",
["numeral form"] = "anyong pambilang",
["participles"] = "pandiwari",
["participle form"] = "anyong pandiwari",
["particle form"] = "anyong partikulo",
["passive participles"] = "pasibong pandiwari",
["past active participles"] = "aktibong pandiwaring pangnakaraan",
["past adverbial participles"] = "pandiwaring pang-abay na pangnakaraan",
["past participles"] = "pandiwaring pangnakaraan",
["past participle form"] = "anyong pandiwaring pangnakaraan",
["past passive participles"] = "anyong pasibong pandiwaring pangnakaraan",
["perfect active participles"] = "aktibong pandiwaring perpekto",
["perfect participles"] = "pandiwaring perpekto",
["perfect passive participles"] = "pasibong pandiwaring perpekto",
--"pinyin",
["plurals"] = "maramihan",
--"postposition form",
["prefix form"] = "anyong unlapi",
["preposition contractions"] = "pang-ukol na kontraksiyon",
["preposition form"] = "anyong pang-ukol",
["prepositional pronouns"] = "panghalip na pang-ukol",
["present active participles"] = "aktibong pandiwaring pangkasalukuyan",
["present adverbial participles"] = "pandiwaring pang-abay na pangkasalukuyan",
["present participles"] = "anyong pandiwaring pangkasalukuyan",
["present passive participles"] = "pasibong pandiwaring pangkasalukuyang",
--"preverb form",
["pronoun form"] = "anyong panghalip",
["pronoun possessive form"] = "anyong panghalip paari",
["proper noun form"] = "anyong pangngalang pantangi",
["proper noun plural form"] = "anyong pangngalang pantanging maramihan",
--"rafsi",
["romanizations"] = "romanisasyon",
["root form"] = "anyong ugat",
["singulatives"] = "isahan",
["suffix form"] = "anyong hulapi",
["superlative adjective form"] = "anyong pang-uring pasukdol",
["superlative adjectives"] = "pang-uring pasukdol",
["superlative adverb form"] = "anyong pang-abay na pasukdol",
["superlative adverbs"] = "pang-abay na pasukdol",
["verb form"] = "anyong pandiwa",
["verbal nouns"] = "pandiwang pangngalan",
}
--[==[ var:
Map of parts of speech for which categories like `German masculine nouns` or `Russian imperfective verbs` will be
generated if the headword is of the appropriate gender/number. The map is used to canonicalize parts of speech for
categorization purposes; specifically, proper nouns categorizes like nouns.
]==]
data.pos_for_gender_number_cat = {
["pangngalan"] = "pangngalan",
["pangngalang pantangi"] = "pangngalan",
["hulapi"] = "hulapi",
-- We include verbs because impf and pf are valid "genders".
["pandiwa"] = "pandiwa",
}
--[==[ var:
Lower limit for a "long" word in a particular language. Used to categorize terms into e.g.
[[:Category:Long English words]] automatically. Languages with no mapping here do not get categorized.
]==]
data.long_word_thresholds = {
["af"] = 20,
["bg"] = 20,
["cy"] = 25,
["de"] = 20,
["en"] = 25,
["es"] = 20,
["fr"] = 20,
["ka"] = 20,
["sv"] = 20,
["tl"] = 25,
}
------ 3. Page-wide processing (so that it only needs to be done once per page). ------
data.page = require(headword_page_module).process_page()
-- Set some page properties directly on `data` for ease of use.
data.pagename = data.page.pagename
data.encoded_pagename = data.page.encoded_pagename
return data
pxbjk7pr0fyk66zm0aw57oxy38h9n61
Module:columns
828
31154
178368
171132
2026-10-23T05:48:56Z
GinawaSaHapon
3989
178368
Scribunto
text/plain
local export = {}
local collation_module = "Module:collation"
local debug_track_module = "Module:debug/track"
local decorations_module = "Module:decorations"
local headword_data_module = "Module:headword/data"
local JSON_module = "Module:JSON"
local languages_module = "Module:languages"
local links_module = "Module:links"
local pages_module = "Module:pages"
local parameter_utilities_module = "Module:parameter utilities"
local parameters_module = "Module:parameters"
local parse_utilities_module = "Module:parse utilities"
local qualifier_module = "Module:qualifier"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local yesno_module = "Module:yesno"
local m_str_utils = require(string_utilities_module)
local concat = table.concat
local html = mw.html.create
local is_substing = mw.isSubsting
local insert = table.insert
local rmatch = m_str_utils.match
local remove = table.remove
local sub = string.sub
local trim = m_str_utils.trim
local u = m_str_utils.char
local dump = mw.dumpObject
local function track(page)
require(debug_track_module)("columns/" .. page)
return true
end
local function deepEquals(...)
deepEquals = require(table_module).deepEquals
return deepEquals(...)
end
local function term_already_linked(term)
return term == "?" or -- signals an unknown term
-- optimization to avoid unnecessarily loading [[Module:parse utilities]]
(term:find("[<{]") and require(parse_utilities_module).term_already_linked(term))
end
local function convert_delimiter_to_separator(item, itemind, args)
if itemind == 1 then
item.separator = nil
elseif item.delimiter == " " then
item.separator = args.space_delim
elseif item.delimiter == "~" then
item.separator = args.tilde_delim
else
item.separator = args.comma_delim
end
end
local function get_horizontal_separator(args_horiz, embedded_comma)
return args_horiz == "bullet" and " · " or embedded_comma and "; " or ", "
end
-- Suppress false positives in categories like [[Category:English links with redundant wikilinks]] so people won't
-- be tempted to "correct" them; terms like embedded ~ like [[Micros~1]] or embedded comma not followed by a space
-- such as [[1,6-Cleves acid]] need to have a link around them to avoid the tilde or comma being interpreted as a
-- delimiter.
local function suppress_redundant_wikilink_cat(term, _alt)
return term:find("~") or term:find(",%S")
end
local function full_link_and_track_self_links(item, face, nochecktr)
if item.term then
local pagename = mw.loadData(headword_data_module).pagename
local term_is_pagename = item.term == pagename
local term_contains_pagename = item.term:find("%[%[" .. m_str_utils.pattern_escape(pagename) .. "[|%]]")
if term_is_pagename or term_contains_pagename then
local current_L2 = require(pages_module).get_current_L2()
if current_L2 then
local current_L2_lang = require(languages_module).getByCanonicalName(current_L2)
if current_L2_lang and current_L2_lang:getCode() == item.lang:getCode() then
if term_is_pagename then
track("term-is-pagename")
else
track("term-contains-pagename")
end
end
end
end
end
item.suppress_redundant_wikilink_cat = suppress_redundant_wikilink_cat
item.never_call_transliteration_module = nochecktr
return require(links_module).full_link(item, face)
end
local function format_subitem(subitem, lang, face, compute_embedded_comma, nochecktr)
local embedded_comma = false
local text
if subitem.term and term_already_linked(subitem.term) then
text = subitem.term
if compute_embedded_comma then
embedded_comma = not not require(utilities_module).get_plaintext(text):find(",")
end
else
text = full_link_and_track_self_links(subitem, face, nochecktr)
if compute_embedded_comma then
-- We don't check decoration text for commas as it's inside parens or displayed elsewhere.
local subitem_plaintext = subitem.alt or subitem.term
if subitem_plaintext then
embedded_comma = not not subitem_plaintext:find(",")
end
end
end
-- We could use the `show_decorations` field to full_link() but not when term_already_linked().
if subitem.q and subitem.q[1] or subitem.qq and subitem.qq[1] or subitem.l and subitem.l[1] or
subitem.ll and subitem.ll[1] or subitem.refs and subitem.refs[1] then
text = require(decorations_module).format_decorations {
lang = subitem.lang or lang,
text = text,
q = subitem.q,
qq = subitem.qq,
l = subitem.l,
ll = subitem.ll,
refs = subitem.refs,
}
end
return text, embedded_comma
end
function export.format_item(item, args, face)
local compute_embedded_comma = args.horiz == "comma"
local embedded_comma = false
local nochecktr = args.noautotr
if type(item) == "table" then
if item.terms then
local parts = {}
local is_first = true
for _, subitem in ipairs(item.terms) do
if subitem == false then
-- omitted subitem; do nothing
else
local separator = subitem.separator or not is_first and (args.subitem_separator or ", ")
if separator then
if compute_embedded_comma then
embedded_comma = embedded_comma or not not separator:find(",")
end
insert(parts, separator)
end
local formatted, this_embedded_comma = format_subitem(subitem, args.lang, face,
compute_embedded_comma, nochecktr)
embedded_comma = embedded_comma or this_embedded_comma
insert(parts, formatted)
is_first = false
end
end
return concat(parts), embedded_comma
else
return format_subitem(item, args.lang, face, compute_embedded_comma, nochecktr)
end
else
if compute_embedded_comma then
embedded_comma = not not require(utilities_module).get_plaintext(item):find(",")
end
if args.lang and not term_already_linked(item) then
return full_link_and_track_self_links({lang = args.lang, term = item, sc = args.sc}, face, nochecktr), embedded_comma
else
return item, embedded_comma
end
end
end
function export.construct_old_style_header(header, horiz)
local old_style_header
local function ib_colon()
return tostring(html("span"):addClass("ib-colon"):addClass("ib-content"):wikitext(":"))
end
if horiz then
old_style_header = require(qualifier_module).format_qualifiers {
qualifiers = header,
open = false,
close = false,
} .. ib_colon() .. " "
else
old_style_header = require(qualifier_module).format_qualifiers {
qualifiers = header
} .. ib_colon()
old_style_header = tostring(html("div"):wikitext(old_style_header))
end
return old_style_header
end
-- Construct the sort base of a single term. As a hack, sort appendices after mainspace items.
local function term_sortbase(val)
if not val then
-- This should not normally happen.
return u(0x10FFFF)
elseif val:find("^%[*Appendix:") then
return u(0x10FFFE) .. val
else
return val
end
end
-- Construct the sort base of a single item, using the display form preferentially, otherwise the term itself.
-- As a hack, sort appendices after mainspace items.
local function item_sortbase(item)
return term_sortbase(item.alt or item.term)
end
local function make_sortbase(item)
if item == false then
return "*" -- doesn't matter, will be omitted in create_list()
elseif type(item) == "table" then
if item.terms then
-- Optimize for the common case of only a single term
if item.terms[2] then
local parts = {}
-- multiple terms
local first = true
for _, subitem in ipairs(item.terms) do
if subitem ~= false then
if not first then
insert(parts, ", ")
end
insert(parts, item_sortbase(subitem))
first = false
end
end
if parts[1] then
return concat(parts)
end
else
local subitem = item.terms[1]
if subitem ~= false then
return item_sortbase(subitem)
end
end
return "*" -- doesn't matter, entire group will be omitted in create_list()
else
return item_sortbase(item)
end
else
return item
end
end
local function make_node_sortbase(node)
return make_sortbase(node.item)
end
-- Sort a sublist of `list` in place, keeping the first `keepfirst` and last `keeplast` items fixed.
-- `lang` is the language of the items and `make_sortbase` creates the appropriate sort base.
local function sort_sublist(list, lang, make_sortbase_fn, keepfirst, keeplast)
if keepfirst == 0 and keeplast == 0 then
require(collation_module).sort(list, lang, make_sortbase_fn)
else
local sublist = {}
for i = keepfirst + 1, #list - keeplast do
sublist[i - keepfirst] = list[i]
end
require(collation_module).sort(sublist, lang, make_sortbase_fn)
for i = keepfirst + 1, #list - keeplast do
list[i] = sublist[i - keepfirst]
end
end
end
--[=[ Unused but could be useful in the future
-- URL-encode only the characters that serve as template delimiters (left and right brace, vertical bar, equal sign
-- and percent sign since it's the escape character).
local function bot_url_encode(txt)
return (txt:gsub("[%%|{}=&]",
{["%"] = "%25", ["|"] = "%7C", ["{"] = "%7B", ["}"] = "%7D", ["="] = "%3D", ["&"] = "%26"}))
end
]=]
-- Reverse the action of bot_url_encode().
local function bot_url_decode(txt)
return (txt:gsub("%%7([BCD])", {B = "{", C = "|", D = "}"}):gsub("%%3D", "="):gsub("%%26", "&"):gsub("%%25", "%%"))
end
--[==[
Bot-callable function to generate a number of sortkeys simultaneously. {{para|1}} contains the langcode, and remaining
numeric parameters contain "bot-URL-encoded" strings whose sort keys will be computed and returned as a JSON array.
Here, "bot-URL-encoded" means that the six characters `{ | } = & %` should be converted to
their URL-encoded representation (respectively `%7B %7C %7D %3D %26 %25`), and will be decoded appropriately
before computing the sortkey.
]==]
function export.make_sortkey(frame)
local iparams = {
[1] = {type = "language"},
[2] = {list = true},
}
local iargs = require(parameters_module).process(frame.args, iparams)
local make_sortkey = require(collation_module).make_lang_sortkey_function(iargs[1], term_sortbase)
local retval = {}
for _, arg in ipairs(iargs[2]) do
arg = bot_url_decode(arg)
insert(retval, make_sortkey(arg))
end
return require(JSON_module).toJSON(retval)
end
local large_text_scripts = {
["Arab"] = true,
["Beng"] = true,
["Deva"] = true,
["Gujr"] = true,
["Guru"] = true,
["Hebr"] = true,
["Khmr"] = true,
["Knda"] = true,
["Laoo"] = true,
["Mlym"] = true,
["Mong"] = true,
["Mymr"] = true,
["Orya"] = true,
["Sinh"] = true,
["Syrc"] = true,
["Taml"] = true,
["Telu"] = true,
["Tfng"] = true,
["Thai"] = true,
["Tibt"] = true,
}
--[==[
Format a list of items using HTML. `args` is an object specifying the items to add and related properties, with the
following fields:
* `content`: A list of the items to format. See below for the format of the items.
* `lang`: The language object of the items to format, if the items in `content` are strings.
* `sc`: The script object of the items to format, if the items in `content` are strings.
* `raw`: If true, return the list raw, without any collapsing or columns.
* `class`: The CSS class of the surrounding {<div>}.
* `column_count`: Number of columns to format the list into.
* `alphabetize`: If true, sort the items in the table.
* `collapse`: If true, make the table partially collapsed by default, with a "Show more" button at the bottom.
* `toggle_category`: Value of `data-toggle-category` property grouping collapsible elements.
* `header`: If specified, Wikicode to prepend to the output.
* `title_new_style`: If true, the header is treated as a title and displayed in a new style. This is ignored if `horiz`
is non-nil.
* `subitem_separator`: Separator used between subitems when multiple subitems occur on a line, if not specified in the
subitem itself (using the `separator` field). Defaults to {", "}.
* `keepfirst`: If > 0, keep this many rows unsorted at the beginning of the top level.
* `keeplast`: If > 0, keep this many rows unsorted at the end of the top level.
* `horiz`: If non-nil, format the items horizontally. If the value is "bullet", put a center dot/bullet (·) between
items. If the value is "comma", put a comma between items (but if there is an embedded comma in any item,
put a semicolon between all items).
Each item in `content` is in one of the following formats:
* A string. This is for compatibility and should not be used by new callers.
* An object describing an item to format, in the format expected by full_link() in [[Module:links]], including
decorations (left or right qualifiers, left or right labels, or references).
* An object describing a list of subitems to format, displayed side-by-side, separated by a comma or other separator.
This format is identified by the presence of a key `terms` specifying the list of subitems. Each subitem is in
the same format as for a single top-level item, except that it should also have a `separator` field specifying the
separator to display before each item (which will typically be a blank string before the first item).
]==]
function export.create_list(args)
if type(args) ~= "table" then
error("expected table, got " .. type(args))
end
local column_count = args.column_count or 1
local toggle_category = args.toggle_category or "derived terms"
local keepfirst = args.keepfirst or 0
local keeplast = args.keeplast or 0
if keepfirst > 0 then
track("keepfirst")
end
if keeplast > 0 then
track("keeplast")
end
-- maybe construct old-style header
local old_style_header = nil
if args.header and (args.horiz or not args.title_new_style) then
old_style_header = export.construct_old_style_header(args.header, args.horiz)
end
if args.horiz then
old_style_header = "* " .. (old_style_header or "")
end
local list
local any_extra_indented_item = false
for _, item in ipairs(args.content) do
if item == false then
-- do nothing
elseif type(item) == "table" and item.extra_indent and item.extra_indent > 0 then
any_extra_indented_item = true
break
end
end
-- If any extra indented item, convert the items to a nested structure, which is necessary both for sorting and
-- for converting to HTML.
if any_extra_indented_item then
local function make_node(item)
return {
item = item
}
end
local root_node = make_node(nil)
local node_stack = {root_node}
local last_indent = 0
local function append_subnode(node, subnode)
if not node.subnodes then
node.subnodes = {}
end
insert(node.subnodes, subnode)
end
for i, item in ipairs(args.content) do
if item == false then
-- do nothing
else
local this_indent
if type(item) ~= "table" then
this_indent = 1
else
this_indent = (item.extra_indent or 0) + 1
end
local node = make_node(item)
if this_indent == last_indent then
append_subnode(node_stack[#node_stack], node)
elseif this_indent > last_indent + 1 then
error(("Element #%s (%s) has indent %s, which is more than one greater than the previous item with indent %s"):format(
i, make_sortbase(item), this_indent, last_indent))
elseif this_indent > last_indent then
-- Start a new sublist attached to the last item of the sublist one level up; but we need special
-- handling for the root node (last_indent == 0).
if last_indent > 0 then
local subnodes = node_stack[#node_stack].subnodes
if not subnodes then
error(("Internal error: Not first item and no subnodes at preceding level %s: %s"):format(
#node_stack, dump(node_stack)))
end
insert(node_stack, subnodes[#subnodes])
end
append_subnode(node_stack[#node_stack], node)
last_indent = this_indent
else
while last_indent > this_indent do
local finished_node = table.remove(node_stack)
if args.alphabetize then
require(collation_module).sort(finished_node.subnodes, args.lang, make_node_sortbase)
end
last_indent = last_indent - 1
end
append_subnode(node_stack[#node_stack], node)
end
end
end
if args.alphabetize then
while node_stack[1] do
local finished_node = table.remove(node_stack)
if node_stack[1] then
-- We're sorting something other than the root node.
require(collation_module).sort(finished_node.subnodes, args.lang, make_node_sortbase)
else
-- We're sorting the root node; honor `keepfirst` and `keeplast`.
sort_sublist(finished_node.subnodes, args.lang, make_node_sortbase, keepfirst, keeplast)
end
end
end
local function format_node(node, depth)
local sublist
local embedded_comma = false
if node.subnodes then
if args.horiz then
sublist = {}
else
sublist = html("ul")
end
local prevnode = nil
for _, subnode in ipairs(node.subnodes) do
local thisnode, this_embedded_comma = format_node(subnode, depth + 1)
embedded_comma = embedded_comma or this_embedded_comma
if not prevnode or not args.alphabetize or not deepEquals(prevnode, thisnode) then
if args.horiz then
table.insert(sublist, thisnode)
else
sublist = sublist:node(thisnode)
end
prevnode = thisnode
end
end
if args.horiz then
sublist = table.concat(sublist, get_horizontal_separator(args.horiz, embedded_comma))
end
end
if not node.item then
-- At the root.
return sublist, embedded_comma
end
local formatted, listitem
-- Ignore embedded commas in subitems inside of parens or square brackets.
formatted, embedded_comma = export.format_item(node.item, args)
if args.horiz then
listitem = formatted
if sublist then
-- Use parens for the first, third, fifth, etc. sublists and square brackets for the remainder.
if depth % 2 == 1 then
listitem = ("%s (%s)"):format(listitem, sublist)
else
listitem = ("%s [%s]"):format(listitem, sublist)
end
end
else
listitem = html("li"):wikitext(formatted)
if sublist then
listitem = listitem:node(sublist)
end
end
return listitem, embedded_comma
end
list = format_node(root_node, 0)
else
if args.alphabetize then
sort_sublist(args.content, args.lang, make_sortbase, keepfirst, keeplast)
end
if args.horiz then
list = {}
else
list = html("ul")
end
local previtem = nil
local embedded_comma = false
for _, item in ipairs(args.content) do
if item == false then
-- omitted item; do nothing
else
local thisitem, this_embedded_comma = export.format_item(item, args)
embedded_comma = embedded_comma or this_embedded_comma
if not previtem or not args.alphabetize or previtem ~= thisitem then
if args.horiz then
table.insert(list, thisitem)
else
list = list:node(html("li"):wikitext(thisitem))
end
previtem = thisitem
end
end
end
if args.horiz then
list = table.concat(list, get_horizontal_separator(args.horiz, embedded_comma))
end
end
local output
if args.horiz then
output = list
else
output = html("div"):addClass("term-list"):node(list)
if args.class then
output:addClass(args.class)
end
if not args.raw then
output:addClass("ul-column-count")
:attr("data-column-count", column_count)
if args.collapse then
output = html("div")
:node(output)
:addClass("list-switcher")
:attr("data-toggle-category", toggle_category)
-- identify commonly used scripts that use large text and
-- provide a special CSS class to make the template bigger
local sc = args.sc
if sc == nil then
local scripts = args.lang:getScripts()
if #scripts > 0 then
sc = scripts[1]
end
end
if sc ~= nil then
local scriptcode = sc:getParentCode()
if scriptcode == "top" then
scriptcode = sc:getCode()
end
if large_text_scripts[scriptcode] then
output:addClass("list-switcher-large-text")
end
end
end
end
if args.collapse or args.title_new_style then
-- wrap in wrapper to prevent interference from floating elements
local list_switcher_wrapper = html("div")
:addClass("list-switcher-wrapper")
if args.title_new_style then
list_switcher_wrapper
:node(
html("div")
:addClass("list-switcher-header")
:wikitext(args.header)
)
end
list_switcher_wrapper:node(output)
output = list_switcher_wrapper
end
output = tostring(output)
end
return (old_style_header or "") .. output
end
-- This function is for compatibility with earlier version of [[Module:columns]]
-- (now found in [[Module:columns/old]]).
function export.create_table(...)
-- Earlier arguments to create_table:
-- n_columns, content, alphabetize, bg, collapse, class, title, column_width, line_start, lang
local args = {}
args.column_count, args.content, args.alphabetize,
args.collapse, args.class, args.header, args.column_width,
args.line_start, args.lang = ...
return export.create_list(args)
end
function export.display_from(frame_args, parent_args, frame)
local boolean = {type = "boolean"}
local iparams = {
["class"] = true,
-- Default for auto-collapse. Overridable by template |collapse= param.
["collapse"] = boolean,
-- If specified, this specifies the number of columns, and no columns parameter is available on the template.
-- Otherwise, the columns parameter is named |n=.
["columns"] = {type = "number"},
-- If specified, this specifies the default language code, which can be overridden using |lang= in the template.
-- Otherwise, the language-code parameter is required and normally found in |1=, but for compatibility can be
-- specified as |lang= (which leads to deprecation handling).
["lang"] = {type = "language"},
-- Default for auto-sort. Overridable by template |sort= param.
["sort"] = boolean,
["toggle_category"] = true,
-- Minimum number of rows required to format into a multicolumn list. If below this, the list is displayed "raw"
-- (no columns, no collapsbility).
["minrows"] = {type = "number", default = 5},
-- Disables automatic transliteration; entries without a manual transliteration will have none at all.
-- Used on large pages, especially Chinese ones, because zh-translit works by fetching and parsing
-- the target of the page, which is a performance killer on large pages with potentially thousands
-- of link targets.
-- Note: noautotr also disables redundant transliteration checks.
["noautotr"] = boolean,
}
local iargs = require(parameters_module).process(frame_args, iparams)
local langcode_in_lang = iargs.lang or parent_args.lang
local lang_param = langcode_in_lang and "lang" or 1
local deprecated = not iargs.lang and langcode_in_lang
local ret = export.handle_display_from_or_topic_list(iargs, parent_args, nil)
return deprecated and frame:expandTemplate{title = "check deprecated lang param usage",
-- FIXME: Accessing undefined global var
args = {ret, lang = args[lang_param]}} or ret
end
--[==[
Implement `display_from()` [the internal entry point for {{tl|col}} and variants, which enter originally through
`display()`] as well as regular (column-oriented) topic lists, invoked through [[Module:topic list]].
`iargs` are the invocation args of {{tl|col}}, and `raw_item_args` are the arguments specifying the values of
each row as well as other properties, corresponding to the user-specified template arguments of {{tl|col}}. Note that
`show()` in [[Module:topic list]] is normally invoked directly by a topic list template, whose invocation
arguments are passed in using `raw_item_args` and are similar to the template arguments of {{tl|col}}. `iargs` for
topic-list invocations is hard-coded, and template arguments to a topic-list template are processed in
[[Module:topic list]] itself. Note that the handling of topic lists is currently implemented almost entirely
through callbacks in `topic_list_data` (which is nil if we're processing {{tl|col}} rather than a topic list) in an
attempt to reduce the coupling and keep the topic-list-specific code in [[Module:topic list]], but IMO the coupling
is still too tight. Probably the control structure should be reversed and the following function split up into
subfunctions, which are invoked as needed by {{tl|col}} and/or [[Module:topic list]].
]==]
function export.handle_display_from_or_topic_list(iargs, raw_item_args, topic_list_data)
local boolean = {type = "boolean"}
local langcode_in_lang = iargs.lang or raw_item_args.lang
local lang_param = langcode_in_lang and "lang" or 1
local first_content_param = langcode_in_lang and 1 or 2
local params = {
[lang_param] = {required = not iargs.lang, type = "language",
template_default = not iargs.lang and "und" or nil},
["n"] = not iargs.columns and {type = "number"} or nil,
[first_content_param] = {list = true, allow_holes = true},
["title"] = {},
["collapse"] = boolean,
["sort"] = boolean,
["sc"] = {type = "script"},
-- used when calling from [[Module:saurus]] so the page displaying the synonyms/antonyms doesn't occur in the
-- list
["omit"] = {list = true},
["keepfirst"] = {type = "number", default = 0},
["keeplast"] = {type = "number", default = 0},
["horiz"] = {},
["notr"] = boolean,
["noautotr"] = boolean,
["allow_space_delim"] = boolean,
["tilde_delim"] = {},
["space_delim"] = {},
["comma_delim"] = {},
}
if topic_list_data then
topic_list_data.add_topic_list_params(params)
end
local m_param_utils = require(parameter_utilities_module)
local param_mods = m_param_utils.construct_param_mods {
{default = true, require_index = true},
{group = "link"}, -- sc has separate_no_index = true; that's the only one
-- It makes no sense to have overall l=, ll=, q= or qq= params for columnar display.
{group = {"ref", "l", "q"}, require_index = true},
}
m_param_utils.augment_params_with_modifiers(params, param_mods)
local processed_args = require(parameters_module).process(raw_item_args, params)
local horiz = processed_args.horiz
if horiz and horiz ~= "comma" and horiz ~= "bullet" then
horiz = require(yesno_module)(horiz)
if horiz == nil then
error(("Unrecognized value |horiz=%s; should be 'comma', 'bullet' or a recognized Boolean value such " ..
"as 'yes' or '1' (same as 'bullet') or 'no' or '0'"):format(processed_args.horiz))
end
if horiz == true then
horiz = "bullet"
end
processed_args.horiz = horiz
end
-- If default argument values specified, set them after parsing the caller-specified arguments in `raw_item_args`.
if topic_list_data then
topic_list_data.set_default_arguments(processed_args)
end
-- Now set defaults for the various delimiters, depending in some cases on whether horiz was set.
-- We can't set these defaults (even regardless of their dependency on horiz=) in `local params` above
-- because we want any defaults specified in `default_props` to override these.
if not processed_args.tilde_delim then
local tilde_with_abbr = '<abbr title="near equivalent">~</abbr>'
processed_args.tilde_delim = processed_args.horiz and tilde_with_abbr or " " .. tilde_with_abbr .. " "
end
if not processed_args.space_delim then
processed_args.space_delim = " "
end
if not processed_args.comma_delim then
processed_args.comma_delim = processed_args.horiz and "/" or ", "
end
-- Check for extra term indent. Do this before calling parse_list_with_inline_modifiers_and_separate_params()
-- because sometimes space is a delimiter and the space in the indent will confuse things and get interpreted as a
-- delimiter.
local extra_indent_by_termno = {}
local termargs = processed_args[first_content_param]
for i = 1, termargs.maxindex do
local term = termargs[i]
if term then
local extra_indent, actual_term = rmatch(term, "^(%*+)%s+(.-)$")
if extra_indent then
termargs[i] = actual_term
extra_indent_by_termno[i] = #extra_indent
end
end
end
local groups, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
param_mods = param_mods,
processed_args = processed_args,
termarg = first_content_param,
parse_lang_prefix = true,
allow_multiple_lang_prefixes = true,
disallow_custom_separators = true,
track_module = "columns",
lang = iargs.lang or lang_param,
sc = "sc.default",
splitchar = processed_args.allow_space_delim and "[,~ ]" or "[,~]",
no_show_decorations = true, -- since we handle them ourselves in format_subitem()
}
local lang = iargs.lang or args[lang_param]
local langcode = lang:getCode()
local sc = args.sc.default
local sort = iargs.sort
if args.sort ~= nil then
if not args.sort then
track("nosort")
end
sort = args.sort
else
-- HACK! For Japanese-script languages (Japanese, Okinawan, Miyako, etc.), sorting doesn't yet work properly, so
-- disable it.
for _, langsc in ipairs(lang:getScriptCodes()) do
if langsc == "Jpan" then
sort = false
break
end
end
end
local collapse = iargs.collapse
if args.collapse ~= nil then
if not args.collapse then
track("nocollapse")
end
collapse = args.collapse
end
local title = args.title
local formatted_cats
if topic_list_data then
title, formatted_cats = topic_list_data.get_title_and_formatted_cats(args, lang, sc, topic_list_data)
end
local number_of_groups = 0
for i, group in ipairs(groups) do
local number_of_items = 0
group.extra_indent = extra_indent_by_termno[group.orig_index]
for j, item in ipairs(group.terms) do
convert_delimiter_to_separator(item, j, args)
if args.notr then
item.tr = "-"
elseif args.noautotr then
item.tr = item.tr or "-"
end
-- If a separate language code was given for the term, display the language name as a right qualifier.
-- (Briefly we made them labels but this leads to non-obvious behavior e.g. "French" becoming "France" under
-- some circumstances.) Otherwise it may not be obvious that the term is in a separate language (e.g. if the
-- main language is 'zh' and the term language is a Chinese lect such as Min Nan). But don't do this for
-- Translingual terms, which are often added to the list of English and other-language terms.
if item.termlangs then
local qqs = {}
for _, termlang in ipairs(item.termlangs) do
local termlangcode = termlang:getCode()
if termlangcode ~= langcode and termlangcode ~= "mul" then
insert(qqs, termlang:getCanonicalName())
end
end
if item.qq then
for _, qq in ipairs(item.qq) do
insert(qqs, qq)
end
end
item.qq = qqs
end
local omitted = false
for _, omitted_item in ipairs(args.omit) do
if omitted_item == item.term then
omitted = true
break
end
end
if omitted then
-- signal create_list() to omit this item
group.terms[j] = false
else
number_of_items = number_of_items + 1
end
end
if number_of_items == 0 then
-- omit the whole group
groups[i] = false
else
number_of_groups = number_of_groups + 1
end
end
local column_count = iargs.columns or args.n
-- FIXME: This needs a total rewrite.
if column_count == nil then
column_count = number_of_groups <= 3 and 1 or
number_of_groups <= 9 and 2 or
number_of_groups <= 27 and 3 or
number_of_groups <= 81 and 4 or
5
end
local raw = number_of_groups < iargs.minrows
local horiz_edit_button
if topic_list_data and args.horiz then
-- append edit button to title
horiz_edit_button = topic_list_data.make_horiz_edit_button(topic_list_data.topic_list_template)
end
return export.create_list {
column_count = column_count,
raw = raw,
content = groups,
alphabetize = sort,
header = title,
title_new_style = (title ~= nil and title ~= ''),
collapse = collapse,
toggle_category = iargs.toggle_category,
-- columns-bg (in [[MediaWiki:Gadget-Site.css]]) provides the background color
class = (iargs.class and iargs.class .. " columns-bg" or "columns-bg"),
lang = lang,
sc = sc,
subitem_separator = ", ",
keepfirst = args.keepfirst,
keeplast = args.keeplast,
horiz = args.horiz,
noautotr = args.noautotr,
} .. (horiz_edit_button or "") .. (formatted_cats or "")
end
function export.display(frame)
if not is_substing() then
return export.display_from(frame.args, frame:getParent().args, frame, false)
end
-- If substed, unsubst template with newlines between each term, redundant wikilinks removed, and remove duplicates + sort terms if sort is enabled.
local m_table = require("Module:table")
local m_template_parser = require("Module:template parser")
local parent = frame:getParent()
local elems = m_table.shallowCopy(parent.args)
local code = remove(elems, 1)
code = code and trim(code)
local lang = require("Module:languages").getByCode(code, 1)
local i = 1
while true do
local elem = elems[i]
while elem do
elem = trim(elem, "%s")
if elem ~= "" then
break
end
remove(elems, i)
elem = elems[i]
end
if not elem then
break
elseif not ( -- Strip redundant wikilinks.
not elem:match("^()%[%[") or
elem:find("[[", 3, true) or
elem:find("]]", 3, true) ~= #elem - 1 or
elem:find("|", 3, true)
) then
elem = sub(elem, 3, -3)
elem = trim(elem, "%s")
end
elems[i] = elem .. "\n"
i = i + 1
end
-- If sort is enabled, remove duplicates then sort elements.
if require("Module:yesno")(frame.args.sort) then
elems = m_table.removeDuplicates(elems)
require("Module:collation").sort(elems, lang)
end
-- Readd the langcode.
insert(elems, 1, code .. "\n")
-- TODO: Place non-numbered parameters after 1 and before 2.
local template = m_template_parser.getTemplateInvocationName(mw.title.new(parent:getTitle()))
return "{{" .. concat(m_template_parser.buildTemplate(template, elems), "|") .. "}}"
end
return export
q1zh3i0jgwf4rzgnir2tkpvmqf5xx70
Module:languages/data/3/n
828
32648
178384
175591
2026-10-23T07:25:57Z
GinawaSaHapon
3989
178384
Scribunto
text/plain
local m_langdata = require("Module:languages/data")
-- Loaded on demand, as it may not be needed (depending on the data).
local function u(...)
u = require("Module:string utilities").char
return u(...)
end
local c = m_langdata.chars
local p = m_langdata.puaChars
local s = m_langdata.shared
local m = {}
m["naa"] = {
"Namla",
3508760,
"paa-nto",
"Latn",
}
m["nab"] = {
"Nambikwara",
2068190,
"sai-nmk",
"Latn",
}
m["nac"] = {
"Narak",
6965295,
"ngf-jim",
"Latn",
}
m["nae"] = {
"Naka'ela",
6960073,
"poz",
"Latn",
}
m["naf"] = {
"Nabak",
11732491,
"ngf-san",
"Latn",
}
m["nag"] = {
"Naga Pidgin",
3503454,
"crp",
"Latn",
ancestors = "as",
}
m["nah"] = {
"Nahuatl",
13300,
"azc-nah",
"Latn",
}
m["naj"] = {
"Nalu",
36026,
"alv-nal",
"Latn",
}
m["nak"] = {
"Nakanai",
6528669,
"poz-ocw",
"Latn",
}
m["nal"] = {
"Nalik",
3335387,
"poz-ocw",
"Latn",
}
m["nam"] = {
"Ngan'gityemerri",
3298041,
"aus-dal",
"Latn",
}
-- Being converted into the family "Southern Min" ("zhx-nan", which will take the code "nan" once the language can be removed). Retain the name "Min Nan" here to avoid having to move things that are scheduled for deletion anyway.
m["nan"] = {
"Min Nan",
36495,
"zhx-com",
"Hants, Latn, Bopo, Kana",
wikimedia_codes = "zh-min-nan",
generate_forms = "zh-generateforms",
sort_key = {
Hani = "Hani-sortkey",
Kana = "Kana-sortkey"
},
}
m["nao"] = {
"Naaba",
11883865,
"sit-tib",
ancestors = "xct",
}
m["nap"] = {
"Neapolitan",
33845,
"roa-itr",
ancestors = "nap-old",
"Latn",
}
m["naq"] = {
"Khoekhoe",
13301,
"khi-khk",
"Latn",
}
m["nar"] = {
"Iguta",
5621686,
"nic-jer",
"Latn",
}
m["nas"] = {
"Nasioi",
56772,
"paa-sbo",
"Latn",
}
m["nat"] = {
"Hungworo",
3914395,
"nic-kmk",
"Latn",
}
m["naw"] = {
"Nawuri",
35906,
"alv-gng",
"Latn",
}
m["nax"] = {
"Nakwi",
3504178,
"paa-lma",
"Latn",
}
m["nay"] = {
"Ngarrindjeri",
7022091,
"aus-pam",
"Latn",
}
m["naz"] = {
"Coatepec Nahuatl",
5138605,
"azc-nah",
"Latn",
}
m["nba"] = {
"Nyemba",
3346655,
"bnt-clu",
"Latn",
ancestors = "lch",
}
m["nbb"] = {
"Ndoe",
36134,
"nic-eko",
"Latn",
}
m["nbc"] = {
"Chang",
5071694,
"sit-kch",
"Latn",
}
m["nbd"] = {
"Ngbinda",
11132859,
"bnt-boa",
"Latn",
}
m["nbe"] = {
"Konyak Naga",
6430448,
"sit-kch",
"Latn",
}
m["nbg"] = {
"Nagarchal",
13299,
"dra-gon",
}
m["nbh"] = {
"Ngamo",
3438705,
"cdc-wst",
"Latn",
}
m["nbi"] = {
"Mao Naga",
12952905,
"tbq-anp",
"Latn",
}
m["nbj"] = {
"Ngarinman",
10600380,
nil,
"Latn",
}
m["nbk"] = {
"Nake",
11732496,
"ngf-han",
"Latn",
}
m["nbm"] = {
"Ngbaka Ma'bo",
3915331,
"nic-nkm",
"Latn",
}
m["nbn"] = {
"Kuri",
3200540,
"poz",
"Latn",
}
m["nbo"] = {
"Nkukoli",
3914482,
"nic-uce",
"Latn",
}
m["nbp"] = {
"Nnam",
36138,
"nic-eko",
"Latn",
}
m["nbq"] = {
"Nggem",
12952956,
"ngf-dan",
"Latn",
}
m["nbr"] = {
"Numana",
5529310,
"nic-nin",
"Latn",
}
m["nbs"] = {
"Namibian Sign Language",
6961792,
"sgn",
"Latn", -- when documented
}
m["nbt"] = {
"Na",
12952895,
"sit-tan",
"Deva, Latn",
}
m["nbu"] = {
"Rongmei Naga",
12952912,
"sit-zem",
"Latn",
}
m["nbv"] = {
"Ngamambo",
11129694,
"nic-mom",
"Latn",
}
m["nbw"] = {
"Southern Ngbandi",
17522635,
"nic-ngd",
"Latn",
}
m["nby"] = {
"Ningera",
11732524,
"paa-bew",
"Latn",
}
m["nca"] = {
"Iyo",
6101336,
"ngf-gmo",
"Latn",
}
m["ncb"] = {
"Central Nicobarese",
3335553,
"aav-nic",
"Deva, Latn",
}
m["ncc"] = {
"Ponam",
3396122,
"poz-aay",
"Latn",
}
m["ncd"] = {
"Nachering",
6957144,
"sit-kic",
"Deva",
}
m["nce"] = {
"Yale",
2992915,
"qfa-dis", -- Papuan; isolate in Glottolog and Palmer (2018); under proposed Senu River family in Usher (2020)
"Latn",
}
m["ncf"] = {
"Notsi",
3344784,
"poz-ocw",
"Latn",
}
m["ncg"] = {
"Nisga'a",
3342138,
"nai-tsi",
"Latn",
}
m["nch"] = {
"Central Huasteca Nahuatl",
2194290,
"azc-hua",
"Latn",
}
m["nci"] = {
"Classical Nahuatl",
559242,
"azc-nah",
"Latn",
strip_diacritics = {remove_diacritics = c.macron},
}
m["ncj"] = {
"Northern Puebla Nahuatl",
15705671,
"azc-nah",
"Latn",
}
m["nck"] = {
"Nakara",
6960662,
"aus-arn",
"Latn",
}
m["ncl"] = {
"Michoacán Nahuatl",
2896217,
"azc-nah",
"Latn",
}
m["ncm"] = {
"Nambo",
42173731,
"paa-nam",
"Latn",
}
m["ncn"] = {
"Nauna",
3337158,
"poz-aay",
"Latn",
}
m["nco"] = {
"Sibe",
56806,
"paa-sbo",
"Latn",
}
m["ncr"] = {
"Ncane",
11297920,
"nic-bbe",
"Latn",
ancestors = "nhu",
}
m["ncs"] = {
"Nicaraguan Sign Language",
33765,
"sgn",
"Sgnw",
}
m["nct"] = {
"Chothe Naga",
5105385,
"tbq-kuk",
"Beng, Latn",
}
m["ncu"] = {
"Chumburung",
35198,
"alv-gng",
"Latn",
}
m["ncx"] = {
"Central Puebla Nahuatl",
5061727,
"azc-nah",
"Latn",
}
m["ncz"] = {
"Natchez",
3111838,
nil,
"Latn",
}
m["nda"] = {
"Ndasa",
35904,
"bnt-kel",
"Latn",
}
m["ndb"] = {
"Kenswei Nsei",
7067553,
"nic-rnn",
"Latn",
}
m["ndc"] = {
"Ndau",
13311,
"bnt-sho",
"Latn",
}
m["ndd"] = {
"Nde-Nsele-Nta",
36131,
"nic-eko",
"Latn",
}
m["ndf"] = {
"Nadruvian",
6957967,
nil,
"Latn",
}
m["ndg"] = {
"Ndengereko",
6983726,
"bnt-mbi",
"Latn",
}
m["ndh"] = {
"Ndali",
6983678,
"bnt-run",
"Latn",
}
m["ndi"] = {
"Chamba Leko",
36381,
"alv-lek",
"Latn",
}
m["ndj"] = {
"Ndamba",
6983684,
"bnt-kil",
"Latn",
}
m["ndk"] = {
"Ndaka",
11164947,
"bnt-nya",
"Latn",
}
m["ndl"] = {
"Ndolo",
6983788,
"bnt-zbi",
"Latn",
ancestors = "lse",
}
m["ndm"] = {
"Ndam",
56283,
"cdc-est",
"Latn",
}
m["ndn"] = {
"Ngundi",
35916,
"bnt-ngn",
"Latn",
}
m["ndp"] = {
"Ndo",
6983774,
"csu-mle",
"Latn",
}
m["ndq"] = {
"Ndombe",
6983792,
"bnt-swb",
"Latn",
}
m["ndr"] = {
"Ndoola",
35837,
"nic-mmb",
"Latn",
}
m["nds"] = {
"Low German",
25433,
"gmw-lgm",
"Latn",
ancestors = "gml",
}
m["ndt"] = {
"Ndunga",
6983857,
"nic-mbc",
"Latn",
}
m["ndu"] = {
"Dugun",
11015189,
"alv-dur",
"Latn",
}
m["ndv"] = {
"Ndut",
36028,
"alv-cng",
"Latn",
}
m["ndw"] = {
"Ndobo",
11008568,
"bnt-ngn",
"Latn",
}
m["ndx"] = {
"Nduga",
6983833,
"ngf-ngn",
"Latn",
}
m["ndy"] = {
"Lutos",
6705910,
"csu-val",
"Latn",
}
m["ndz"] = {
"Ndogo",
35983,
"nic-ser",
"Latn",
}
m["nea"] = {
"Eastern Ngad'a",
12473454,
"poz-cet",
"Latn",
}
m["neb"] = {
"Toura",
7853636,
"dmn-mda",
"Latn",
}
m["nec"] = {
"Nedebang",
4925378,
"paa-alp",
"Latn",
}
m["ned"] = {
"Nde-Gbite",
11010279,
"nic-grf",
}
m["nee"] = {
"Kumak",
3347266,
"poz-cln",
"Latn",
}
m["nef"] = {
"Nefamese",
6987002,
"crp",
}
m["neg"] = {
"Negidal",
33676,
"tuw-ewe",
"Cyrl",
}
m["neh"] = {
"Nyenkha",
3695185,
"sit-ebo",
"Tibt, Latn",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["nej"] = {
"Neko",
6989840,
"ngf-gmo",
"Latn",
}
m["nek"] = {
"Neku",
14916900,
"poz-cln",
}
m["nem"] = {
"Nemi",
3338008,
"poz-cln",
"Latn",
}
m["nen"] = {
"Nengone",
3338052,
"poz-cln",
"Latn",
}
m["neo"] = {
"Ná-Meo",
15977293,
"hmn",
}
m["neq"] = {
"North Central Mixe",
25559729,
nil,
"Latn",
}
m["ner"] = {
"Yahadian",
8046778,
nil,
"Latn",
}
m["nes"] = {
"Bhoti Kinnauri",
21179921,
"sit-las",
}
m["net"] = {
"Nete",
6998869,
"ngf-oen",
"Latn",
}
m["neu"] = {
"Neo",
606917,
"art",
"Latn",
type = "appendix-constructed",
}
m["nev"] = {
"Nyaheun",
7070801,
"mkh-ban",
}
m["new"] = {
"Newar",
33979,
"sit-new",
"Deva, Newa, Ranj",
ancestors = "nwx",
translit = {
Deva = "new-translit",
Newa = "new-Newa-translit",
},
}
m["nex"] = {
"Neme",
12952941,
"paa-nam",
"Latn",
}
m["ney"] = {
"Neyo",
36410,
"kro",
}
m["nez"] = {
"Nez Perce",
3339226,
"nai-shp",
"Latn",
}
m["nfa"] = {
"Dhao",
2053828,
"poz",
"Latn",
}
m["nfd"] = {
"Ahwai",
3913957,
"nic-plt",
"Latn",
}
m["nfl"] = {
"Äiwoo",
56742,
"poz-tem",
"Latn",
}
m["nfr"] = {
"Nafaanra",
13297,
"alv-snf",
"Latn",
}
m["nfu"] = {
"Mfumte",
6826794,
"nic-nka",
"Latn",
}
m["nga"] = {
"Ngbaka",
36022,
"gba-eas",
"Latn",
}
m["ngb"] = {
"Northern Ngbandi",
17522631,
"nic-ngd",
"Latn",
}
m["ngc"] = {
"Ngombe (Congo)",
3123524,
"bnt-bun",
}
m["ngd"] = {
"Ngando (Central African Republic)",
35910,
"bnt-ngn",
}
m["nge"] = {
"Ngemba",
6750551,
"nic-nge",
"Latn",
}
m["ngg"] = { -- compare 'aiy'
"Ngbaka Manza",
11033316,
"gba-eas",
"Latn",
}
m["ngh"] = {
"Nǀuu",
2618974,
"khi-tuu",
"Latn",
}
m["ngi"] = {
"Ngizim",
3914924,
"cdc-wst",
"Latn",
}
m["ngj"] = {
"Ngie",
36361,
"nic-mom",
"Latn",
}
m["ngk"] = {
"Ngalkbun",
3913790,
"aus-gun",
"Latn",
}
m["ngl"] = {
"Lomwe",
35824,
"bnt-mak",
"Latn",
}
m["ngm"] = {
"Ngatik Men's Creole",
36400,
"crp",
ancestors = "en, pon",
}
m["ngn"] = {
"Ngwo",
36051,
"nic-mom",
"Latn",
}
m["ngo"] = {
"Ngoni",
7022547,
"bnt-ngu",
"Latn",
}
m["ngp"] = {
"Ngulu",
7193332,
"bnt-seu",
"Latn",
}
m["ngq"] = {
"Ngoreme",
7022573,
"bnt-lok",
"Latn",
}
m["ngr"] = {
"Nagu",
3063524,
"poz-tem",
"Latn",
}
m["ngs"] = {
"Gvoko",
3441188,
"cdc-cbm",
"Latn",
}
m["ngt"] = {
"Ngeq",
25559548,
"mkh-kat",
}
m["ngu"] = {
"Guerrero Nahuatl",
5614980,
"azc-nah",
"Latn",
}
m["ngv"] = {
"Nagumi",
35842,
"nic-jrn",
}
m["ngw"] = {
"Ngwaba",
3440480,
"cdc-cbm",
"Latn",
}
m["ngx"] = {
"Nggwahyi",
56265,
"cdc-cbm",
"Latn",
}
m["ngy"] = {
"Tibea",
36598,
"bnt-baf",
"Latn",
}
m["ngz"] = {
"Ngungwel",
35920,
"bnt-tkc",
"Latn",
}
m["nha"] = {
"Nhanda",
3339380,
"aus-psw",
"Latn",
}
m["nhb"] = {
"Beng",
3913311,
"dmn-nbe",
"Latn",
}
m["nhc"] = {
"Tabasco Nahuatl",
6047326,
"azc-nah",
"Latn",
}
m["nhd"] = {
"Chiripá",
2873230,
"gn",
"Latn",
}
m["nhe"] = {
"Nahuatl ng Silangang Huasteca", -- "Eastern Huasteca Nahuatl",
4358289,
"azc-hua",
"Latn",
}
m["nhf"] = {
"Nhuwala",
10600396,
"aus-nga",
"Latn",
}
m["nhg"] = {
"Tetelcingo Nahuatl",
3450252,
"azc-nah",
"Latn",
}
m["nhh"] = {
"Nahari",
6583560,
"inc-hal",
}
m["nhi"] = {
"Zacatlán-Ahuacatlán-Tepetzintla Nahuatl",
12953764,
"azc-nah",
"Latn",
}
m["nhk"] = {
"Cosoleacaque Nahuatl",
12953757,
"azc-nah",
"Latn",
}
m["nhm"] = {
"Morelos Nahuatl",
4800819,
"azc-nah",
"Latn",
}
m["nhn"] = {
"Central Nahuatl",
6047309,
"azc-nah",
"Latn",
}
m["nho"] = {
"Takuu",
3409818,
"poz-pnp",
"Latn",
}
m["nhp"] = {
"Pajapan Nahuatl",
12953760,
"azc-nah",
"Latn",
}
m["nhq"] = {
"Huaxcaleca Nahuatl",
12953758,
"azc-nah",
"Latn",
}
m["nhr"] = {
"Naro",
2164778,
"khi-kal",
"Latn",
}
m["nht"] = {
"Ometepec Nahuatl",
7090132,
"azc-nah",
"Latn",
}
m["nhu"] = {
"Noone",
36072,
"nic-bbe",
"Latn",
}
m["nhv"] = {
"Temascaltepec Nahuatl",
2379405,
"azc-nah",
"Latn",
}
m["nhw"] = {
"Western Huasteca Nahuatl",
2678840,
"azc-hua",
"Latn",
}
m["nhx"] = {
"Mecayapan Nahuatl",
12953756,
"azc-nah",
"Latn",
}
m["nhy"] = {
"Northern Oaxaca Nahuatl",
12953763,
"azc-nah",
"Latn",
}
m["nhz"] = {
"Santa María La Alta Nahuatl",
15705753,
"azc-nah",
"Latn",
}
m["nia"] = {
"Nias",
2407831,
"poz-nws",
"Latn",
}
m["nib"] = {
"Nakame",
11732495,
"ngf-boa",
"Latn",
}
m["nid"] = {
"Ngandi",
7021977,
"aus-arn",
"Latn",
}
m["nie"] = {
"Niellim",
33662,
"alv-bua",
}
m["nif"] = {
"Nek",
6989781,
"ngf-boa",
"Latn",
}
m["nig"] = {
"Ngalakan",
3913796,
"aus-gun",
"Latn",
}
m["nih"] = {
"Nyiha",
11128374,
"bnt-mby",
"Latn",
}
m["nii"] = {
"Nii",
35237,
"ngf-wah",
"Latn",
}
m["nij"] = {
"Ngaju",
2992872,
"poz-brw",
"Latn",
}
m["nik"] = {
"Southern Nicobarese",
7570194,
"aav-nic",
}
m["nil"] = {
"Nila",
7036821,
}
m["nim"] = {
"Nilamba",
4121200,
"bnt-tkm",
"Latn",
}
m["nin"] = {
"Ninzo",
3914021,
"nic-nin",
}
m["nio"] = {
"Nganasan",
36743,
"syd",
"Cyrl",
translit = "nio-translit",
}
m["niq"] = {
"Nandi",
6956591,
"sdv-nma",
"Latn",
}
m["nir"] = {
"Nimboran",
301116,
"paa-nim",
"Latn",
}
m["nis"] = {
"Nimi",
11732523,
"ngf-era",
"Latn",
}
m["nit"] = {
"Southeastern Kolami",
56767,
"dra-knk",
"Deva, Telu",
translit = {
Telu = "te-translit"
},
}
m["niu"] = {
"Niuean",
33790,
"poz-ton",
"Latn",
}
m["niv"] = {
"Nivkh",
36464,
"qfa-iso",
"Cyrl, Latn",
translit = "niv-translit",
strip_diacritics = {
from = {"['’]"},
to = {"ʼ"}
},
sort_key = "niv-sortkey",
}
m["niw"] = {
"Nimo",
3504126,
"paa-lma",
"Latn",
}
m["nix"] = {
"Hema",
5710904,
"bnt-nyg",
"Latn",
}
m["niy"] = {
"Ngiti",
7022396,
"csu-lnd",
}
m["niz"] = {
"Ningil",
11732527,
"paa-wap",
"Latn",
}
m["nja"] = {
"Nzanyi",
3441299,
"cdc-cbm",
"Latn",
}
m["njb"] = {
"Nocte",
7046410,
"sit-tno",
}
m["njh"] = {
"Lotha Naga",
33590,
"sit-aao",
}
m["nji"] = {
"Gudanji",
3915692,
"aus-mir",
"Latn",
}
m["njj"] = {
"Njen",
36112,
"nic-mom",
"Latn",
}
m["njl"] = {
"Njalgulgule",
7071229,
"sdv-daj",
}
m["njm"] = {
"Angami",
56761,
"tbq-anp",
"Latn",
}
m["njn"] = {
"Liangmai Naga",
14194500,
"sit-zem",
"Latn",
}
m["njo"] = {
"Ao",
28433,
"sit-aao",
"Latn",
}
m["njr"] = {
"Njerep",
35844,
"nic-mmb",
"Latn",
}
m["njs"] = {
"Nisa",
13593518,
"paa-egb",
"Latn",
}
m["njt"] = {
"Ndyuka-Trio Pidgin",
13591205,
"crp",
ancestors = "djk, tri",
}
m["nju"] = {
"Ngadjunmaya",
7021846,
"aus-pam",
"Latn",
}
m["njx"] = {
"Kunyi",
3196559,
"bnt-kng",
"Latn",
}
m["njy"] = {
"Njyem",
35898,
"bnt-ndb",
"Latn",
}
m["njz"] = {
"Nyishi",
56870,
"sit-tan",
"Latn",
}
m["nka"] = {
"Nkoya",
7042633,
"bnt-lbn",
"Latn",
}
m["nkb"] = {
"Khoibu Naga",
21481876,
"sit-mar",
}
m["nkc"] = {
"Nkongho",
35863,
"bnt-saw",
"Latn",
}
m["nkd"] = {
"Koireng",
6426342,
"sit-zem",
}
m["nke"] = {
"Duke",
3041075,
"poz-ocw",
"Latn",
}
m["nkf"] = {
"Inpui Naga",
21481817,
"sit-zem",
}
m["nkg"] = {
"Nekgini",
11732509,
"ngf-gmo",
"Latn",
}
m["nkh"] = {
"Khezha Naga",
6401519,
"tbq-anp",
}
m["nki"] = {
"Thangal Naga",
56374,
"sit-zem",
}
m["nkj"] = {
"Nakai",
14916897,
"ngf-tna",
"Latn",
}
m["nkk"] = {
"Nokuku",
7048122,
"poz-vnn",
"Latn",
}
m["nkm"] = {
"Namat",
15634505,
"paa-nam",
"Latn",
}
m["nkn"] = {
"Nkangala",
10962292,
"bnt-clu",
"Latn",
ancestors = "mck",
}
m["nko"] = {
"Nkonya",
35867,
"alv-gng",
"Latn",
}
m["nkp"] = {
"Niuatoputapu",
3399095,
"poz-pnp",
"Latn",
}
m["nkq"] = {
"Nkami",
7042522,
"alv-gng",
"Latn",
}
m["nkr"] = {
"Nukuoro",
2635961,
"poz-pnp",
"Latn",
}
m["nks"] = {
"North Asmat",
11732049,
"ngf-asm",
"Latn",
}
m["nkt"] = {
"Nyika",
16917497,
"bnt-mwi",
"Latn",
}
m["nku"] = {
"Bouna Kulango",
20668241,
"alv-kul",
}
-- nkv is treated as nkt, see [[WT:LT]]
m["nkw"] = {
"Nkutu",
7193313,
"bnt-tet",
"Latn",
}
m["nkx"] = {
"Nkoroo",
36000,
"ijo",
}
m["nkz"] = {
"Nkari",
11130307,
"nic-ief",
ancestors = "ibr",
}
m["nla"] = {
"Ngombale",
36292,
"bai",
"Latn",
}
m["nlc"] = {
"Nalca",
6960839,
"ngf-mek",
"Latn",
}
m["nle"] = {
"East Nyala",
25559347,
"bnt-msl",
"Latn",
ancestors = "luy",
}
m["nlg"] = {
"Gela",
3063531,
"poz-sls",
"Latn",
}
m["nli"] = {
"Grangali",
3444203,
"inc-kun",
"Arab",
}
m["nlj"] = {
"Nyali",
7070830,
"bnt-nya",
"Latn",
}
m["nlk"] = {
"Ninia Yali",
12953310,
"ngf-yal",
"Latn",
}
m["nll"] = {
"Nihali",
33904,
"qfa-iso",
"Deva, Latn",
}
m["nlm"] = {
"Mankiyali",
47522426,
"inc-koh",
}
m["nlo"] = {
"Ngul",
35894,
"bnt-bdz",
"Latn",
}
m["nlq"] = {
"Lao Naga",
63283609,
"sit-tno",
}
m["nlu"] = {
"Nchumbulu",
36143,
"alv-gng",
"Latn",
}
m["nlv"] = {
"Orizaba Nahuatl",
3086050,
"azc-nah",
"Latn",
}
m["nlw"] = {
"Walangama",
7961277,
}
m["nlx"] = {
"Nahali",
33361,
"inc-bhi",
}
m["nly"] = {
"Nyamal",
7070837,
"aus-nga",
"Latn",
}
m["nlz"] = {
"Nalögo",
20527138,
"poz-tem",
"Latn",
}
m["nma"] = {
"Maram Naga",
56378,
"sit-zem",
}
m["nmb"] = {
"Big Nambas",
2902304,
"poz-vnc",
"Latn",
}
m["nmc"] = {
"Ngam",
3915446,
"csu-sar",
"Latn",
}
m["nmd"] = {
"Ndumu",
35901,
"bnt-mbt",
"Latn",
}
m["nme"] = {
"Mzieme Naga",
6949473,
"sit-zem",
}
m["nmf"] = {
"Tangkhul Naga",
7682992,
"sit-tng",
"Latn, Mtei",
}
m["nmg"] = {
"Kwasio",
34098,
"bnt-mnj",
"Latn",
}
m["nmh"] = {
"Monsang Naga",
6902496,
}
m["nmi"] = {
"Nyam",
3438738,
"cdc-wst",
"Latn",
}
m["nmj"] = {
"Ngombe (Central African Republic)",
3913949,
"gba-sou",
}
m["nmk"] = {
"Namakura",
3335410,
"poz-vnc",
"Latn",
}
m["nml"] = {
"Ndemli",
36089,
"nic-grf",
"Latn",
}
m["nmm"] = {
"Manangba",
6746900,
"sit-tam",
"Tibt, Deva",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["nmn"] = {
"ǃXóõ",
13229,
"khi-tuu",
"Latn",
}
m["nmo"] = {
"Moyon Naga",
6927748,
"tbq-kuk",
}
m["nmp"] = {
"Nimanbur",
16891606,
}
m["nmq"] = {
"Nambya",
11008869,
"bnt-sho",
"Latn",
}
m["nmr"] = {
"Nimbari",
36069,
"alv-lni",
}
m["nms"] = {
"Letemboi",
3236886,
"poz-vnc",
"Latn",
}
m["nmt"] = {
"Namonuito",
12908815,
"poz-mic",
}
m["nmu"] = {
"Northeast Maidu",
3278074,
"nai-mdu",
"Latn",
}
m["nmv"] = {
"Ngamini",
7021944,
"aus-kar",
"Latn",
}
m["nmw"] = {
"Nimoa",
7037729,
"poz-ocw",
"Latn",
}
m["nmx"] = {
"Nama",
20812287,
"paa-nam",
"Latn",
}
m["nmy"] = {
"Namuyi",
56844,
"sit-nax",
"Latn",
}
m["nmz"] = {
"Nawdm",
36085,
"nic-yon",
"Latn",
}
m["nna"] = {
"Nyangumarta",
33653,
}
m["nnb"] = {
"Nande",
3196953,
"bnt-glb",
"Latn",
}
m["nnc"] = {
"Nancere",
3140491,
"cdc-est",
"Latn",
}
m["nnd"] = {
"West Ambae",
2841479,
"poz-vnn",
"Latn",
}
m["nne"] = {
"Ngandyera",
10961003,
"bnt-ova",
"Latn",
}
m["nnf"] = {
"Ngaing",
11732510,
"ngf-gmo",
"Latn",
}
m["nng"] = {
"Maring Naga",
12952908,
"sit-mar",
}
m["nnh"] = {
"Ngiemboon",
36286,
"bai",
"Latn",
}
m["nni"] = {
"North Nuaulu",
12952968,
"poz-cma",
}
m["nnj"] = {
"Nyangatom",
4662604,
"sdv-ttu",
}
m["nnk"] = {
"Nankina",
11732502,
"ngf-yup",
"Latn",
}
m["nnl"] = {
"Northern Rengma Naga",
7067615,
"tbq-anp",
}
m["nnm"] = {
"Namia",
56363,
"paa-sep",
"Latn",
}
m["nnn"] = {
"Ngete",
56625,
"cdc-mas",
"Latn",
}
m["nnp"] = {
"Wancho",
7967085,
"sit-kch",
"Wcho, Deva, Latn",
}
m["nnq"] = {
"Ngindo",
7022366,
"bnt-mbi",
"Latn",
}
m["nnr"] = {
"Narungga",
13591127,
"aus-pam",
"Latn",
}
m["nnt"] = {
"Nanticoke",
3915517,
"alg-eas",
"Latn",
}
m["nnu"] = {
"Dwang",
35258,
"alv-gng",
"Latn",
}
m["nnv"] = {
"Nukunu",
10604066,
nil,
"Latn",
}
m["nnw"] = {
"Southern Nuni",
11152248,
"nic-gnn",
"Latn",
}
m["nnx"] = {
"Ngong",
12952915,
}
m["nny"] = { -- contrast aus-ynk
"Nyangga",
10604331,
"aus-tnk",
"Latn",
}
m["nnz"] = {
"Nda'nda'",
36016,
"bai",
"Latn",
}
m["noa"] = {
"Woun Meu",
3111873,
"sai-chc",
"Latn",
}
m["noc"] = {
"Nuk",
11732534,
"ngf-boa",
"Latn",
}
m["nod"] = {
"Northern Thai",
565110,
"tai-swe",
"Lana, Thai",
strip_diacritics = {remove_diacritics = c.ZWNJ},
sort_key = {
Lana = "Lana-sortkey",
Thai = "Thai-sortkey"
},
}
m["noe"] = {
"Nimadi",
3502294,
"raj",
"Deva",
translit = "hi-translit",
}
m["nof"] = {
"Nomane",
11732531,
"ngf-sim",
"Latn",
}
m["nog"] = {
"Nogai",
33871,
"trk-kno",
"Cyrl, Arab, Latn",
translit = "nog-translit",
override_translit = true,
}
m["noh"] = {
"Nomu",
11732532,
"ngf-dal",
"Latn",
}
m["noi"] = {
"Noiri",
12953774,
"inc-bhi",
}
m["noj"] = {
"Nonuya",
5372139,
"sai-wit",
"Latn",
}
m["nok"] = {
"Nooksack",
3343396,
"sal",
}
m["nol"] = {
"Nomlaki",
3343229,
"nai-wtq",
"Latn",
}
m["nom"] = {
"Nocamán",
7046289,
"sai-pan",
"Latn",
}
m["non"] = {
"Old Norse",
35505,
"gmq",
"Latn, Runr",
translit = {Runr = "Runr-translit"},
}
m["nop"] = {
"Numanggang",
7069052,
"ngf-boa",
"Latn",
}
m["noq"] = {
"Ngongo",
11057478,
"bnt-yak",
"Latn",
}
m["nos"] = {
"Eastern Nisu",
25559419,
"tbq-nis",
}
m["not"] = {
"Nomatsiguenga",
3342992,
"awd",
"Latn",
}
m["nou"] = {
"Ewage-Notu",
5418860,
"ngf-bin",
"Latn",
}
m["nov"] = {
"Novial",
36738,
"art",
"Latn",
type = "appendix-constructed"
}
m["now"] = {
"Nyambo",
4967930,
"bnt-haj",
"Latn",
}
m["noy"] = {
"Noy",
36321,
"alv-bua",
}
m["noz"] = {
"Nayi",
3183349,
"omv-diz",
}
m["npa"] = {
"Nar Phu",
4926353,
"sit-tam",
}
m["npb"] = {
"Nupbikha",
3695201,
"sit-ebo",
}
m["npg"] = {
"Ponyo",
7228475,
"sit-kch",
}
m["nph"] = {
"Phom",
7187109,
"sit-kch",
}
m["npl"] = {
"Southeastern Puebla Nahuatl",
4632950,
"azc-nah",
"Latn",
}
m["npn"] = {
"Mondropolon",
3320594,
"poz-aay",
}
m["npo"] = {
"Pochuri Naga",
7206342,
"tbq-anp",
}
m["nps"] = {
"Nipsan",
11732528,
"ngf-mek",
"Latn",
}
m["npu"] = {
"Puimei Naga",
7259044,
"sit-zem",
}
m["npx"] = {
"Noipä",
63283617,
"poz-tem",
"Latn",
}
m["npy"] = {
"Napu",
12953768,
}
m["nqg"] = {
"Ede Nago",
12952408,
"alv-ede",
"Latn",
}
m["nqk"] = {
"Kura Ede Nago",
12952409,
"alv-ede",
}
m["nql"] = {
"Ngendelengo",
63283693,
"bnt-swb",
"Latn",
}
m["nqm"] = {
"Ndom",
6983791,
"paa-kol",
"Latn",
}
m["nqn"] = {
"Nen",
20816352,
"paa-nam",
"Latn",
}
m["nqo"] = {
"N'Ko",
18546266,
"dmn-man",
"Nkoo",
}
m["nqq"] = {
"Kyan-Karyaw Naga",
63283784,
"sit-tno",
}
m["nqy"] = {
"Akyaung Ari",
4702035,
"sit-tng",
}
m["nra"] = {
"Ngom",
36087,
"bnt-kel",
"Latn",
}
m["nrb"] = {
"Nara",
36179,
"sdv-nes",
}
m["nrc"] = {
"Noric",
37023,
"cel",
"Ital",
-- Ital translit in [[Module:scripts/data]]
}
m["nre"] = {
"Southern Rengma Naga",
7313205,
"tbq-anp",
}
m["nrf"] = {
"Norman",
33850,
"roa-oil",
"Latn",
wikimedia_codes = "nrm",
ancestors = "fro-nor",
sort_key = s["roa-oil-sortkey"],
}
m["nrg"] = {
"Narango",
12952929,
"poz-vnn",
"Latn",
}
m["nri"] = {
"Chokri Naga",
5104247,
"tbq-anp",
}
m["nrk"] = {
"Ngarla",
3915860,
"aus-nga",
"Latn",
}
m["nrl"] = {
"Ngarluma",
7022078,
"aus-nga",
"Latn",
}
m["nrm"] = {
"Narom",
3336135,
"poz-swa",
"Latn",
}
m["nrn"] = {
"Norn",
36708,
"gmq-ins",
"Latn",
}
m["nrp"] = {
"North Picene",
430138,
"qfa-unc", -- extinct, might be a hoax
"Ital",
-- Ital translit in [[Module:scripts/data]]
}
m["nrr"] = {
"Norra",
12952967,
"tai",
}
m["nrt"] = {
"Northern Kalapuya",
3192121,
"nai-klp",
}
m["nru"] = {
"Narua",
21658869,
"sit-nas",
"Latn",
}
m["nrx"] = {
"Ngurmbur",
2591251,
}
m["nrz"] = {
"Lala (New Guinea)",
6480151,
"poz-ocw",
"Latn",
}
m["nsa"] = {
"Sangtam Naga",
7418144,
"sit-aao",
}
m["nsb"] = {
"Lower Nossob",
6693681,
"khi-tuu",
"Latn",
}
m["nsc"] = {
"Nshi",
11129508,
"nic-rnn",
"Latn",
}
m["nsd"] = {
"Southern Nisu",
63284284,
"tbq-nis",
}
m["nse"] = {
"Nsenga",
3081996,
"bnt-sna",
"Latn",
}
m["nsg"] = {
"Ngasa",
56345,
"sdv-lma",
}
m["nsh"] = {
"Ngoshie",
7022582,
"nic-mom",
"Latn",
}
m["nsi"] = {
"Nigerian Sign Language",
7033021,
"sgn",
}
m["nsk"] = {
"Naskapi",
1704302,
"alg",
"Cans, Latn",
ancestors = "cr",
translit = "nsk-translit",
}
m["nsl"] = {
"Norwegian Sign Language",
1781613,
"sgn",
}
m["nsm"] = {
"Sema",
3478238,
"tbq-anp",
}
m["nsn"] = {
"Nehan",
3337774,
"poz-ocw",
"Latn",
}
m["nso"] = {
"Northern Sotho",
33890,
"bnt-sts",
"Latn",
}
m["nsp"] = {
"Nepalese Sign Language",
3915492,
"sgn",
}
m["nsq"] = {
"Northern Sierra Miwok",
3344226,
"nai-utn",
"Latn",
}
m["nsr"] = {
"Maritime Sign Language",
3915483,
"sgn",
}
m["nss"] = {
"Nali",
3335385,
"poz-aay",
}
m["nst"] = {
"Tangsa",
56350,
"sit-tno",
"Latn, Tnsa",
}
m["nsu"] = {
"Sierra Negra Nahuatl",
63284326,
"azc-nah",
"Latn",
}
m["nsv"] = {
"Southwestern Nisu",
63308004,
"tbq-nis",
}
m["nsw"] = {
"Navut",
3337327,
"poz-vnn",
"Latn",
}
m["nsx"] = {
"Nsongo",
7067577,
"bnt-tmb",
"Latn",
}
m["nsy"] = {
"Nasal",
6966574,
}
m["nsz"] = {
"Nisenan",
33665,
"nai-mdu",
"Latn",
}
m["ntd"] = {
"Northern Tidung",
24938325,
"poz-san",
}
-- ISO merged "nte" into "eko"
m["ntg"] = {
"Ngantangarra",
33060509,
}
m["nti"] = {
"Natioro",
36140,
"alv-wan",
}
m["ntj"] = {
"Ngaanyatjarra",
3915409,
"aus-pam",
"Latn",
}
m["ntk"] = {
"Ikoma",
5996114,
"bnt-lok",
"Latn",
}
m["ntm"] = {
"Nateni",
3070731,
"nic-grm",
"Latn",
}
m["nto"] = {
"Ntomba",
11130292,
"bnt-mon",
"Latn",
}
m["ntp"] = {
"Northern Tepehuan",
15615651,
"azc-pim",
"Latn",
sort_key = {remove_diacritics = c.acute},
}
m["ntr"] = {
"Delo",
35195,
"nic-gne",
"Latn",
}
m["nts"] = {
"Natagaimas",
6967931,
}
m["ntu"] = {
"Natügu",
63308082,
"poz-tem",
"Latn",
}
m["ntw"] = {
"Nottoway",
3344791,
"iro-nor",
"Latn",
}
m["ntx"] = {
"Somra",
7560536,
"sit-tng",
}
m["nty"] = {
"Mantsi",
56878,
"sit-mnz",
}
m["nua"] = {
"Yuanga",
3573088,
"poz-cln",
"Latn",
}
m["nuc"] = {
"Nukuini",
3346231,
}
m["nud"] = {
"Ngala",
7021893,
"paa-ndu",
"Latn",
}
m["nue"] = {
"Ngundu",
12952953,
"bad-cnt",
"Latn",
}
m["nuf"] = {
"Nusu",
56413,
"tbq-nus",
"Latn",
}
m["nug"] = {
"Nungali",
7069826,
"aus-mir",
"Latn",
}
m["nuh"] = {
"Ndunda",
3913968,
"nic-mmb",
"Latn",
}
m["nui"] = {
"Ngumbi",
36459,
"bnt-yko",
}
m["nuj"] = {
"Nyole (Uganda)",
3739448,
"bnt-msl",
"Latn",
}
m["nuk"] = {
"Nootka",
2992876,
"wak",
"Latn",
}
m["nul"] = {
"Nusa Laut",
7070332,
"poz-cma",
}
m["num"] = {
"Niuafo'ou",
36173,
"poz-ton",
"Latn",
}
m["nun"] = {
"Anong",
2748232,
"sit-nng",
"Latn",
}
m["nuo"] = {
"Nguôn",
3915785,
"mkh-vie",
"Latn",
sort_key = "vi-sortkey",
}
m["nup"] = {
"Nupe",
36720,
"alv-ngb",
"Latn",
strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.macron .. c.caron},
sort_key = "nup-sortkey",
}
m["nuq"] = {
"Nukumanu",
12909019,
"poz-pnp",
"Latn",
}
m["nur"] = {
"Nuguria",
7068910,
"poz-pnp",
"Latn",
}
m["nus"] = {
"Nuer",
33675,
"sdv-dnu",
"Latn",
}
m["nut"] = {
"Nùng",
72695,
"tai",
"Latn, Hani",
sort_key = {Hani = "Hani-sortkey"},
}
m["nuu"] = {
"Ngbundu",
11126081,
"bad",
"Latn",
}
m["nuv"] = {
"Northern Nuni",
11016572,
"nic-gnn",
"Latn",
}
m["nuw"] = {
"Nguluwan",
6528643,
}
m["nux"] = {
"Mehek",
6809452,
"paa-sep",
"Latn",
}
m["nuy"] = {
"Nunggubuyu",
1747811,
"aus-arn",
"Latn",
}
m["nuz"] = {
"Tlamacazapa Nahuatl",
2073277,
"azc-nah",
"Latn",
}
m["nvh"] = {
"Nasarian",
6966614,
"poz-vnc",
"Latn",
}
m["nvm"] = {
"Namiae",
12952922,
"ngf-koi",
"Latn",
}
m["nvo"] = {
"Nyokon",
19573407,
"nic-mbw",
"Latn",
}
m["nwa"] = {
"Nawathinehena",
6982892,
"alg-ara",
"Latn",
}
m["nwb"] = {
"Nyabwa",
33664,
"kro-wee",
}
m["nwc"] = {
"Classical Newar",
5128301,
"sit-new",
"Brah, Deva, Newa, Ranj",
-- Brah translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission)
}
m["nwe"] = {
"Ngwe",
36181,
"bai",
"Latn",
}
m["nwg"] = {
"Ngaiawang",
16920653,
"aus-pam",
"Latn",
}
m["nwi"] = {
"Southwest Tanna",
3504488,
"poz-vns",
"Latn",
}
m["nwm"] = {
"Nyamusa-Molo",
12747951,
"csu-bbk",
}
m["nwo"] = {
"Nauo",
6981305,
"aus-pam",
"Latn",
}
m["nwr"] = {
"Nawaru",
12638166,
"ngf-yar",
"Latn",
}
m["nwx"] = {
"Middle Newar",
65455877,
"sit-new",
"Deva, Newa, Ranj",
ancestors = "nwc",
}
m["nwy"] = {
"Nottoway-Meherrin",
65455878,
"iro-nor",
"Latn",
}
m["nxa"] = {
"Nauete",
6981095,
"poz-tim",
}
m["nxd"] = {
"Ngando (Congo)",
3913277,
"bnt-ske",
}
m["nxe"] = {
"Nage",
2295569,
"poz-cet",
}
m["nxg"] = {
"Ngadha",
1516651,
"poz-cet",
"Latn",
}
m["nxi"] = {
"Nindi",
7038230,
"bnt-mbi",
"Latn",
}
m["nxl"] = {
"South Nuaulu",
18544857,
"poz-cma",
}
m["nxm"] = {
"Numidian",
35761,
"afa",
"Tfng, Latn", --Tfng may not support all the needed characters
}
m["nxn"] = {
"Ngawun",
3915711,
"aus-pam",
"Latn",
}
m["nxo"] = {
"Ndambomo",
6983681,
"bnt-kel",
"Latn",
}
m["nxq"] = {
"Naxi",
2478711,
"sit-nas",
"Nkdb, Nkgb, Latn, Lisu",
-- Lisu translit, sort_key in [[Module:scripts/data]]
}
m["nxr"] = {
"Ninggerum",
11732526,
"ngf-lok",
"Latn",
}
-- nxu (Narau) merged into bpp (Kaure) per ISO 639-3 2020 merger
m["nxx"] = {
"Nafri",
6958211,
"paa-sen",
"Latn",
}
m["nyb"] = {
"Nyangbo",
36256,
"alv-ktg",
"Latn",
}
m["nyc"] = {
"Nyanga-li",
7070876,
"bnt-boa",
"Latn",
}
m["nyd"] = {
"Nyole (Kenya)",
7071227,
"bnt-msl",
"Latn",
}
m["nye"] = {
"Nyengo",
7071068,
"bnt-clu",
"Latn",
}
m["nyf"] = {
"Giryama",
3107606,
"bnt-mij",
"Latn",
}
m["nyg"] = {
"Nyindu",
11030685,
"bnt-shh",
"Latn",
}
m["nyh"] = {
"Nyigina",
3913780,
"aus-nyu",
"Latn",
}
m["nyi"] = {
"Nyimang",
34846,
"sdv-nyi",
"Latn",
}
m["nyj"] = {
"Nyanga (Congo)",
7070879,
"bnt-nyb",
"Latn",
}
m["nyk"] = {
"Nyaneka",
10962298,
"bnt-swb",
"Latn",
}
m["nyl"] = {
"Nyeu",
3033578,
"mkh-kat",
}
m["nym"] = {
"Nyamwezi",
4121131,
"bnt-tkm",
"Latn",
}
m["nyn"] = {
"Nyankole",
13207,
"bnt-nyg",
"Latn",
}
m["nyo"] = {
"Nyoro",
33794,
"bnt-nyg",
"Latn",
}
m["nyp"] = {
"Nyang'i",
7070894,
"ssa-klk",
}
m["nys"] = {
"Nyunga",
7049771,
"aus-pam",
"Latn",
}
m["nyt"] = {
"Nyawaygi",
3915783,
"aus-dyb",
"Latn",
}
m["nyu"] = {
"Nyungwe",
7071318,
"bnt-sna",
"Latn",
}
m["nyv"] = {
"Nyulnyul",
3442732,
"aus-nyu",
"Latn",
}
m["nyw"] = {
"Nyaw",
26425602,
"tai-nor", -- Chamberlain (1991), but Pittayaporn (2009) suggests tai-swe
"Thai, Tayo", -- Thailand
sort_key = "Thai-sortkey", -- no effect on Latn
}
m["nyx"] = {
"Nganyaywana",
3913800,
"aus-cww",
"Latn",
}
m["nyy"] = {
"Nyakyusa",
3272620,
"bnt-run",
"Latn",
}
m["nza"] = {
"Tigon Mbembe",
36518,
"nic-jkn",
"Latn",
}
m["nzb"] = {
"Njebi",
35923,
"bnt-nze",
"Latn",
}
m["nzd"] = {
"Nzadi",
17152586,
"bnt-bdz",
"Latn",
strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron},
}
m["nzi"] = {
"Nzima",
36337,
"alv-ctn",
"Latn",
}
m["nzk"] = {
"Nzakara",
3913339,
"znd",
"Latn",
}
m["nzm"] = {
"Zeme Naga",
21491053,
"sit-zem",
}
m["nzs"] = {
"New Zealand Sign Language",
36239,
"sgn",
}
m["nzu"] = {
"Central Teke",
36473,
"bnt-tkc",
"Latn",
}
m["nzy"] = {
"Nzakambay",
36374,
"alv-mbm",
"Latn",
}
m["nzz"] = {
"Nanga Dama Dogon",
6963443,
"nic-nwa",
}
return require("Module:languages").finalizeData(m, "language")
9pmp5h8u00d3f8tdp3bxwuz4wmascg2
178385
178384
2026-10-23T07:33:11Z
GinawaSaHapon
3989
178385
Scribunto
text/plain
local m_langdata = require("Module:languages/data")
-- Loaded on demand, as it may not be needed (depending on the data).
local function u(...)
u = require("Module:string utilities").char
return u(...)
end
local c = m_langdata.chars
local p = m_langdata.puaChars
local s = m_langdata.shared
local m = {}
m["naa"] = {
"Namla",
3508760,
"paa-nto",
"Latn",
}
m["nab"] = {
"Nambikwara",
2068190,
"sai-nmk",
"Latn",
}
m["nac"] = {
"Narak",
6965295,
"ngf-jim",
"Latn",
}
m["nae"] = {
"Naka'ela",
6960073,
"poz",
"Latn",
}
m["naf"] = {
"Nabak",
11732491,
"ngf-san",
"Latn",
}
m["nag"] = {
"Naga Pidgin",
3503454,
"crp",
"Latn",
ancestors = "as",
}
m["nah"] = {
"Nahuatl",
13300,
"azc-nah",
"Latn",
}
m["naj"] = {
"Nalu",
36026,
"alv-nal",
"Latn",
}
m["nak"] = {
"Nakanai",
6528669,
"poz-ocw",
"Latn",
}
m["nal"] = {
"Nalik",
3335387,
"poz-ocw",
"Latn",
}
m["nam"] = {
"Ngan'gityemerri",
3298041,
"aus-dal",
"Latn",
}
-- Being converted into the family "Southern Min" ("zhx-nan", which will take the code "nan" once the language can be removed). Retain the name "Min Nan" here to avoid having to move things that are scheduled for deletion anyway.
m["nan"] = {
"Min Nan",
36495,
"zhx-com",
"Hants, Latn, Bopo, Kana",
wikimedia_codes = "zh-min-nan",
generate_forms = "zh-generateforms",
sort_key = {
Hani = "Hani-sortkey",
Kana = "Kana-sortkey"
},
}
m["nao"] = {
"Naaba",
11883865,
"sit-tib",
ancestors = "xct",
}
m["nap"] = {
"Neapolitan",
33845,
"roa-itr",
ancestors = "nap-old",
"Latn",
}
m["naq"] = {
"Khoekhoe",
13301,
"khi-khk",
"Latn",
}
m["nar"] = {
"Iguta",
5621686,
"nic-jer",
"Latn",
}
m["nas"] = {
"Nasioi",
56772,
"paa-sbo",
"Latn",
}
m["nat"] = {
"Hungworo",
3914395,
"nic-kmk",
"Latn",
}
m["naw"] = {
"Nawuri",
35906,
"alv-gng",
"Latn",
}
m["nax"] = {
"Nakwi",
3504178,
"paa-lma",
"Latn",
}
m["nay"] = {
"Ngarrindjeri",
7022091,
"aus-pam",
"Latn",
}
m["naz"] = {
"Coatepec Nahuatl",
5138605,
"azc-nah",
"Latn",
}
m["nba"] = {
"Nyemba",
3346655,
"bnt-clu",
"Latn",
ancestors = "lch",
}
m["nbb"] = {
"Ndoe",
36134,
"nic-eko",
"Latn",
}
m["nbc"] = {
"Chang",
5071694,
"sit-kch",
"Latn",
}
m["nbd"] = {
"Ngbinda",
11132859,
"bnt-boa",
"Latn",
}
m["nbe"] = {
"Konyak Naga",
6430448,
"sit-kch",
"Latn",
}
m["nbg"] = {
"Nagarchal",
13299,
"dra-gon",
}
m["nbh"] = {
"Ngamo",
3438705,
"cdc-wst",
"Latn",
}
m["nbi"] = {
"Mao Naga",
12952905,
"tbq-anp",
"Latn",
}
m["nbj"] = {
"Ngarinman",
10600380,
nil,
"Latn",
}
m["nbk"] = {
"Nake",
11732496,
"ngf-han",
"Latn",
}
m["nbm"] = {
"Ngbaka Ma'bo",
3915331,
"nic-nkm",
"Latn",
}
m["nbn"] = {
"Kuri",
3200540,
"poz",
"Latn",
}
m["nbo"] = {
"Nkukoli",
3914482,
"nic-uce",
"Latn",
}
m["nbp"] = {
"Nnam",
36138,
"nic-eko",
"Latn",
}
m["nbq"] = {
"Nggem",
12952956,
"ngf-dan",
"Latn",
}
m["nbr"] = {
"Numana",
5529310,
"nic-nin",
"Latn",
}
m["nbs"] = {
"Namibian Sign Language",
6961792,
"sgn",
"Latn", -- when documented
}
m["nbt"] = {
"Na",
12952895,
"sit-tan",
"Deva, Latn",
}
m["nbu"] = {
"Rongmei Naga",
12952912,
"sit-zem",
"Latn",
}
m["nbv"] = {
"Ngamambo",
11129694,
"nic-mom",
"Latn",
}
m["nbw"] = {
"Southern Ngbandi",
17522635,
"nic-ngd",
"Latn",
}
m["nby"] = {
"Ningera",
11732524,
"paa-bew",
"Latn",
}
m["nca"] = {
"Iyo",
6101336,
"ngf-gmo",
"Latn",
}
m["ncb"] = {
"Central Nicobarese",
3335553,
"aav-nic",
"Deva, Latn",
}
m["ncc"] = {
"Ponam",
3396122,
"poz-aay",
"Latn",
}
m["ncd"] = {
"Nachering",
6957144,
"sit-kic",
"Deva",
}
m["nce"] = {
"Yale",
2992915,
"qfa-dis", -- Papuan; isolate in Glottolog and Palmer (2018); under proposed Senu River family in Usher (2020)
"Latn",
}
m["ncf"] = {
"Notsi",
3344784,
"poz-ocw",
"Latn",
}
m["ncg"] = {
"Nisga'a",
3342138,
"nai-tsi",
"Latn",
}
m["nch"] = {
"Central Huasteca Nahuatl",
2194290,
"azc-hua",
"Latn",
}
m["nci"] = {
"Classical Nahuatl",
559242,
"azc-nah",
"Latn",
strip_diacritics = {remove_diacritics = c.macron},
}
m["ncj"] = {
"Northern Puebla Nahuatl",
15705671,
"azc-nah",
"Latn",
}
m["nck"] = {
"Nakara",
6960662,
"aus-arn",
"Latn",
}
m["ncl"] = {
"Michoacán Nahuatl",
2896217,
"azc-nah",
"Latn",
}
m["ncm"] = {
"Nambo",
42173731,
"paa-nam",
"Latn",
}
m["ncn"] = {
"Nauna",
3337158,
"poz-aay",
"Latn",
}
m["nco"] = {
"Sibe",
56806,
"paa-sbo",
"Latn",
}
m["ncr"] = {
"Ncane",
11297920,
"nic-bbe",
"Latn",
ancestors = "nhu",
}
m["ncs"] = {
"Nicaraguan Sign Language",
33765,
"sgn",
"Sgnw",
}
m["nct"] = {
"Chothe Naga",
5105385,
"tbq-kuk",
"Beng, Latn",
}
m["ncu"] = {
"Chumburung",
35198,
"alv-gng",
"Latn",
}
m["ncx"] = {
"Central Puebla Nahuatl",
5061727,
"azc-nah",
"Latn",
}
m["ncz"] = {
"Natchez",
3111838,
nil,
"Latn",
}
m["nda"] = {
"Ndasa",
35904,
"bnt-kel",
"Latn",
}
m["ndb"] = {
"Kenswei Nsei",
7067553,
"nic-rnn",
"Latn",
}
m["ndc"] = {
"Ndau",
13311,
"bnt-sho",
"Latn",
}
m["ndd"] = {
"Nde-Nsele-Nta",
36131,
"nic-eko",
"Latn",
}
m["ndf"] = {
"Nadruvian",
6957967,
nil,
"Latn",
}
m["ndg"] = {
"Ndengereko",
6983726,
"bnt-mbi",
"Latn",
}
m["ndh"] = {
"Ndali",
6983678,
"bnt-run",
"Latn",
}
m["ndi"] = {
"Chamba Leko",
36381,
"alv-lek",
"Latn",
}
m["ndj"] = {
"Ndamba",
6983684,
"bnt-kil",
"Latn",
}
m["ndk"] = {
"Ndaka",
11164947,
"bnt-nya",
"Latn",
}
m["ndl"] = {
"Ndolo",
6983788,
"bnt-zbi",
"Latn",
ancestors = "lse",
}
m["ndm"] = {
"Ndam",
56283,
"cdc-est",
"Latn",
}
m["ndn"] = {
"Ngundi",
35916,
"bnt-ngn",
"Latn",
}
m["ndp"] = {
"Ndo",
6983774,
"csu-mle",
"Latn",
}
m["ndq"] = {
"Ndombe",
6983792,
"bnt-swb",
"Latn",
}
m["ndr"] = {
"Ndoola",
35837,
"nic-mmb",
"Latn",
}
m["nds"] = {
"Low German",
25433,
"gmw-lgm",
"Latn",
ancestors = "gml",
}
m["ndt"] = {
"Ndunga",
6983857,
"nic-mbc",
"Latn",
}
m["ndu"] = {
"Dugun",
11015189,
"alv-dur",
"Latn",
}
m["ndv"] = {
"Ndut",
36028,
"alv-cng",
"Latn",
}
m["ndw"] = {
"Ndobo",
11008568,
"bnt-ngn",
"Latn",
}
m["ndx"] = {
"Nduga",
6983833,
"ngf-ngn",
"Latn",
}
m["ndy"] = {
"Lutos",
6705910,
"csu-val",
"Latn",
}
m["ndz"] = {
"Ndogo",
35983,
"nic-ser",
"Latn",
}
m["nea"] = {
"Eastern Ngad'a",
12473454,
"poz-cet",
"Latn",
}
m["neb"] = {
"Toura",
7853636,
"dmn-mda",
"Latn",
}
m["nec"] = {
"Nedebang",
4925378,
"paa-alp",
"Latn",
}
m["ned"] = {
"Nde-Gbite",
11010279,
"nic-grf",
}
m["nee"] = {
"Kumak",
3347266,
"poz-cln",
"Latn",
}
m["nef"] = {
"Nefamese",
6987002,
"crp",
}
m["neg"] = {
"Negidal",
33676,
"tuw-ewe",
"Cyrl",
}
m["neh"] = {
"Nyenkha",
3695185,
"sit-ebo",
"Tibt, Latn",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["nej"] = {
"Neko",
6989840,
"ngf-gmo",
"Latn",
}
m["nek"] = {
"Neku",
14916900,
"poz-cln",
}
m["nem"] = {
"Nemi",
3338008,
"poz-cln",
"Latn",
}
m["nen"] = {
"Nengone",
3338052,
"poz-cln",
"Latn",
}
m["neo"] = {
"Ná-Meo",
15977293,
"hmn",
}
m["neq"] = {
"North Central Mixe",
25559729,
nil,
"Latn",
}
m["ner"] = {
"Yahadian",
8046778,
nil,
"Latn",
}
m["nes"] = {
"Bhoti Kinnauri",
21179921,
"sit-las",
}
m["net"] = {
"Nete",
6998869,
"ngf-oen",
"Latn",
}
m["neu"] = {
"Neo",
606917,
"art",
"Latn",
type = "appendix-constructed",
}
m["nev"] = {
"Nyaheun",
7070801,
"mkh-ban",
}
m["new"] = {
"Newar",
33979,
"sit-new",
"Deva, Newa, Ranj",
ancestors = "nwx",
translit = {
Deva = "new-translit",
Newa = "new-Newa-translit",
},
}
m["nex"] = {
"Neme",
12952941,
"paa-nam",
"Latn",
}
m["ney"] = {
"Neyo",
36410,
"kro",
}
m["nez"] = {
"Nez Perce",
3339226,
"nai-shp",
"Latn",
}
m["nfa"] = {
"Dhao",
2053828,
"poz",
"Latn",
}
m["nfd"] = {
"Ahwai",
3913957,
"nic-plt",
"Latn",
}
m["nfl"] = {
"Äiwoo",
56742,
"poz-tem",
"Latn",
}
m["nfr"] = {
"Nafaanra",
13297,
"alv-snf",
"Latn",
}
m["nfu"] = {
"Mfumte",
6826794,
"nic-nka",
"Latn",
}
m["nga"] = {
"Ngbaka",
36022,
"gba-eas",
"Latn",
}
m["ngb"] = {
"Northern Ngbandi",
17522631,
"nic-ngd",
"Latn",
}
m["ngc"] = {
"Ngombe (Congo)",
3123524,
"bnt-bun",
}
m["ngd"] = {
"Ngando (Central African Republic)",
35910,
"bnt-ngn",
}
m["nge"] = {
"Ngemba",
6750551,
"nic-nge",
"Latn",
}
m["ngg"] = { -- compare 'aiy'
"Ngbaka Manza",
11033316,
"gba-eas",
"Latn",
}
m["ngh"] = {
"Nǀuu",
2618974,
"khi-tuu",
"Latn",
}
m["ngi"] = {
"Ngizim",
3914924,
"cdc-wst",
"Latn",
}
m["ngj"] = {
"Ngie",
36361,
"nic-mom",
"Latn",
}
m["ngk"] = {
"Ngalkbun",
3913790,
"aus-gun",
"Latn",
}
m["ngl"] = {
"Lomwe",
35824,
"bnt-mak",
"Latn",
}
m["ngm"] = {
"Ngatik Men's Creole",
36400,
"crp",
ancestors = "en, pon",
}
m["ngn"] = {
"Ngwo",
36051,
"nic-mom",
"Latn",
}
m["ngo"] = {
"Ngoni",
7022547,
"bnt-ngu",
"Latn",
}
m["ngp"] = {
"Ngulu",
7193332,
"bnt-seu",
"Latn",
}
m["ngq"] = {
"Ngoreme",
7022573,
"bnt-lok",
"Latn",
}
m["ngr"] = {
"Nagu",
3063524,
"poz-tem",
"Latn",
}
m["ngs"] = {
"Gvoko",
3441188,
"cdc-cbm",
"Latn",
}
m["ngt"] = {
"Ngeq",
25559548,
"mkh-kat",
}
m["ngu"] = {
"Guerrero Nahuatl",
5614980,
"azc-nah",
"Latn",
}
m["ngv"] = {
"Nagumi",
35842,
"nic-jrn",
}
m["ngw"] = {
"Ngwaba",
3440480,
"cdc-cbm",
"Latn",
}
m["ngx"] = {
"Nggwahyi",
56265,
"cdc-cbm",
"Latn",
}
m["ngy"] = {
"Tibea",
36598,
"bnt-baf",
"Latn",
}
m["ngz"] = {
"Ngungwel",
35920,
"bnt-tkc",
"Latn",
}
m["nha"] = {
"Nhanda",
3339380,
"aus-psw",
"Latn",
}
m["nhb"] = {
"Beng",
3913311,
"dmn-nbe",
"Latn",
}
m["nhc"] = {
"Tabasco Nahuatl",
6047326,
"azc-nah",
"Latn",
}
m["nhd"] = {
"Chiripá",
2873230,
"gn",
"Latn",
}
m["nhe"] = {
"Nahuatl ng Silangang Huasteca", -- "Eastern Huasteca Nahuatl",
4358289,
"azc-hua",
"Latn",
}
m["nhf"] = {
"Nhuwala",
10600396,
"aus-nga",
"Latn",
}
m["nhg"] = {
"Tetelcingo Nahuatl",
3450252,
"azc-nah",
"Latn",
}
m["nhh"] = {
"Nahari",
6583560,
"inc-hal",
}
m["nhi"] = {
"Nahuatl ng Zacatlán-Ahuacatlán-Tepetzintla",
12953764,
"azc-nah",
"Latn",
}
m["nhk"] = {
"Nahuatl ng Cosoleacaque",
12953757,
"azc-nah",
"Latn",
}
m["nhm"] = {
"Nahuatl ng Morelos",
4800819,
"azc-nah",
"Latn",
}
m["nhn"] = {
"Gitnang Nahuatl",
6047309,
"azc-nah",
"Latn",
}
m["nho"] = {
"Takuu",
3409818,
"poz-pnp",
"Latn",
}
m["nhp"] = {
"Pajapan Nahuatl",
12953760,
"azc-nah",
"Latn",
}
m["nhq"] = {
"Huaxcaleca Nahuatl",
12953758,
"azc-nah",
"Latn",
}
m["nhr"] = {
"Naro",
2164778,
"khi-kal",
"Latn",
}
m["nht"] = {
"Ometepec Nahuatl",
7090132,
"azc-nah",
"Latn",
}
m["nhu"] = {
"Noone",
36072,
"nic-bbe",
"Latn",
}
m["nhv"] = {
"Temascaltepec Nahuatl",
2379405,
"azc-nah",
"Latn",
}
m["nhw"] = {
"Western Huasteca Nahuatl",
2678840,
"azc-hua",
"Latn",
}
m["nhx"] = {
"Mecayapan Nahuatl",
12953756,
"azc-nah",
"Latn",
}
m["nhy"] = {
"Northern Oaxaca Nahuatl",
12953763,
"azc-nah",
"Latn",
}
m["nhz"] = {
"Santa María La Alta Nahuatl",
15705753,
"azc-nah",
"Latn",
}
m["nia"] = {
"Nias",
2407831,
"poz-nws",
"Latn",
}
m["nib"] = {
"Nakame",
11732495,
"ngf-boa",
"Latn",
}
m["nid"] = {
"Ngandi",
7021977,
"aus-arn",
"Latn",
}
m["nie"] = {
"Niellim",
33662,
"alv-bua",
}
m["nif"] = {
"Nek",
6989781,
"ngf-boa",
"Latn",
}
m["nig"] = {
"Ngalakan",
3913796,
"aus-gun",
"Latn",
}
m["nih"] = {
"Nyiha",
11128374,
"bnt-mby",
"Latn",
}
m["nii"] = {
"Nii",
35237,
"ngf-wah",
"Latn",
}
m["nij"] = {
"Ngaju",
2992872,
"poz-brw",
"Latn",
}
m["nik"] = {
"Southern Nicobarese",
7570194,
"aav-nic",
}
m["nil"] = {
"Nila",
7036821,
}
m["nim"] = {
"Nilamba",
4121200,
"bnt-tkm",
"Latn",
}
m["nin"] = {
"Ninzo",
3914021,
"nic-nin",
}
m["nio"] = {
"Nganasan",
36743,
"syd",
"Cyrl",
translit = "nio-translit",
}
m["niq"] = {
"Nandi",
6956591,
"sdv-nma",
"Latn",
}
m["nir"] = {
"Nimboran",
301116,
"paa-nim",
"Latn",
}
m["nis"] = {
"Nimi",
11732523,
"ngf-era",
"Latn",
}
m["nit"] = {
"Southeastern Kolami",
56767,
"dra-knk",
"Deva, Telu",
translit = {
Telu = "te-translit"
},
}
m["niu"] = {
"Niuean",
33790,
"poz-ton",
"Latn",
}
m["niv"] = {
"Nivkh",
36464,
"qfa-iso",
"Cyrl, Latn",
translit = "niv-translit",
strip_diacritics = {
from = {"['’]"},
to = {"ʼ"}
},
sort_key = "niv-sortkey",
}
m["niw"] = {
"Nimo",
3504126,
"paa-lma",
"Latn",
}
m["nix"] = {
"Hema",
5710904,
"bnt-nyg",
"Latn",
}
m["niy"] = {
"Ngiti",
7022396,
"csu-lnd",
}
m["niz"] = {
"Ningil",
11732527,
"paa-wap",
"Latn",
}
m["nja"] = {
"Nzanyi",
3441299,
"cdc-cbm",
"Latn",
}
m["njb"] = {
"Nocte",
7046410,
"sit-tno",
}
m["njh"] = {
"Lotha Naga",
33590,
"sit-aao",
}
m["nji"] = {
"Gudanji",
3915692,
"aus-mir",
"Latn",
}
m["njj"] = {
"Njen",
36112,
"nic-mom",
"Latn",
}
m["njl"] = {
"Njalgulgule",
7071229,
"sdv-daj",
}
m["njm"] = {
"Angami",
56761,
"tbq-anp",
"Latn",
}
m["njn"] = {
"Liangmai Naga",
14194500,
"sit-zem",
"Latn",
}
m["njo"] = {
"Ao",
28433,
"sit-aao",
"Latn",
}
m["njr"] = {
"Njerep",
35844,
"nic-mmb",
"Latn",
}
m["njs"] = {
"Nisa",
13593518,
"paa-egb",
"Latn",
}
m["njt"] = {
"Ndyuka-Trio Pidgin",
13591205,
"crp",
ancestors = "djk, tri",
}
m["nju"] = {
"Ngadjunmaya",
7021846,
"aus-pam",
"Latn",
}
m["njx"] = {
"Kunyi",
3196559,
"bnt-kng",
"Latn",
}
m["njy"] = {
"Njyem",
35898,
"bnt-ndb",
"Latn",
}
m["njz"] = {
"Nyishi",
56870,
"sit-tan",
"Latn",
}
m["nka"] = {
"Nkoya",
7042633,
"bnt-lbn",
"Latn",
}
m["nkb"] = {
"Khoibu Naga",
21481876,
"sit-mar",
}
m["nkc"] = {
"Nkongho",
35863,
"bnt-saw",
"Latn",
}
m["nkd"] = {
"Koireng",
6426342,
"sit-zem",
}
m["nke"] = {
"Duke",
3041075,
"poz-ocw",
"Latn",
}
m["nkf"] = {
"Inpui Naga",
21481817,
"sit-zem",
}
m["nkg"] = {
"Nekgini",
11732509,
"ngf-gmo",
"Latn",
}
m["nkh"] = {
"Khezha Naga",
6401519,
"tbq-anp",
}
m["nki"] = {
"Thangal Naga",
56374,
"sit-zem",
}
m["nkj"] = {
"Nakai",
14916897,
"ngf-tna",
"Latn",
}
m["nkk"] = {
"Nokuku",
7048122,
"poz-vnn",
"Latn",
}
m["nkm"] = {
"Namat",
15634505,
"paa-nam",
"Latn",
}
m["nkn"] = {
"Nkangala",
10962292,
"bnt-clu",
"Latn",
ancestors = "mck",
}
m["nko"] = {
"Nkonya",
35867,
"alv-gng",
"Latn",
}
m["nkp"] = {
"Niuatoputapu",
3399095,
"poz-pnp",
"Latn",
}
m["nkq"] = {
"Nkami",
7042522,
"alv-gng",
"Latn",
}
m["nkr"] = {
"Nukuoro",
2635961,
"poz-pnp",
"Latn",
}
m["nks"] = {
"North Asmat",
11732049,
"ngf-asm",
"Latn",
}
m["nkt"] = {
"Nyika",
16917497,
"bnt-mwi",
"Latn",
}
m["nku"] = {
"Bouna Kulango",
20668241,
"alv-kul",
}
-- nkv is treated as nkt, see [[WT:LT]]
m["nkw"] = {
"Nkutu",
7193313,
"bnt-tet",
"Latn",
}
m["nkx"] = {
"Nkoroo",
36000,
"ijo",
}
m["nkz"] = {
"Nkari",
11130307,
"nic-ief",
ancestors = "ibr",
}
m["nla"] = {
"Ngombale",
36292,
"bai",
"Latn",
}
m["nlc"] = {
"Nalca",
6960839,
"ngf-mek",
"Latn",
}
m["nle"] = {
"East Nyala",
25559347,
"bnt-msl",
"Latn",
ancestors = "luy",
}
m["nlg"] = {
"Gela",
3063531,
"poz-sls",
"Latn",
}
m["nli"] = {
"Grangali",
3444203,
"inc-kun",
"Arab",
}
m["nlj"] = {
"Nyali",
7070830,
"bnt-nya",
"Latn",
}
m["nlk"] = {
"Ninia Yali",
12953310,
"ngf-yal",
"Latn",
}
m["nll"] = {
"Nihali",
33904,
"qfa-iso",
"Deva, Latn",
}
m["nlm"] = {
"Mankiyali",
47522426,
"inc-koh",
}
m["nlo"] = {
"Ngul",
35894,
"bnt-bdz",
"Latn",
}
m["nlq"] = {
"Lao Naga",
63283609,
"sit-tno",
}
m["nlu"] = {
"Nchumbulu",
36143,
"alv-gng",
"Latn",
}
m["nlv"] = {
"Orizaba Nahuatl",
3086050,
"azc-nah",
"Latn",
}
m["nlw"] = {
"Walangama",
7961277,
}
m["nlx"] = {
"Nahali",
33361,
"inc-bhi",
}
m["nly"] = {
"Nyamal",
7070837,
"aus-nga",
"Latn",
}
m["nlz"] = {
"Nalögo",
20527138,
"poz-tem",
"Latn",
}
m["nma"] = {
"Maram Naga",
56378,
"sit-zem",
}
m["nmb"] = {
"Big Nambas",
2902304,
"poz-vnc",
"Latn",
}
m["nmc"] = {
"Ngam",
3915446,
"csu-sar",
"Latn",
}
m["nmd"] = {
"Ndumu",
35901,
"bnt-mbt",
"Latn",
}
m["nme"] = {
"Mzieme Naga",
6949473,
"sit-zem",
}
m["nmf"] = {
"Tangkhul Naga",
7682992,
"sit-tng",
"Latn, Mtei",
}
m["nmg"] = {
"Kwasio",
34098,
"bnt-mnj",
"Latn",
}
m["nmh"] = {
"Monsang Naga",
6902496,
}
m["nmi"] = {
"Nyam",
3438738,
"cdc-wst",
"Latn",
}
m["nmj"] = {
"Ngombe (Central African Republic)",
3913949,
"gba-sou",
}
m["nmk"] = {
"Namakura",
3335410,
"poz-vnc",
"Latn",
}
m["nml"] = {
"Ndemli",
36089,
"nic-grf",
"Latn",
}
m["nmm"] = {
"Manangba",
6746900,
"sit-tam",
"Tibt, Deva",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["nmn"] = {
"ǃXóõ",
13229,
"khi-tuu",
"Latn",
}
m["nmo"] = {
"Moyon Naga",
6927748,
"tbq-kuk",
}
m["nmp"] = {
"Nimanbur",
16891606,
}
m["nmq"] = {
"Nambya",
11008869,
"bnt-sho",
"Latn",
}
m["nmr"] = {
"Nimbari",
36069,
"alv-lni",
}
m["nms"] = {
"Letemboi",
3236886,
"poz-vnc",
"Latn",
}
m["nmt"] = {
"Namonuito",
12908815,
"poz-mic",
}
m["nmu"] = {
"Northeast Maidu",
3278074,
"nai-mdu",
"Latn",
}
m["nmv"] = {
"Ngamini",
7021944,
"aus-kar",
"Latn",
}
m["nmw"] = {
"Nimoa",
7037729,
"poz-ocw",
"Latn",
}
m["nmx"] = {
"Nama",
20812287,
"paa-nam",
"Latn",
}
m["nmy"] = {
"Namuyi",
56844,
"sit-nax",
"Latn",
}
m["nmz"] = {
"Nawdm",
36085,
"nic-yon",
"Latn",
}
m["nna"] = {
"Nyangumarta",
33653,
}
m["nnb"] = {
"Nande",
3196953,
"bnt-glb",
"Latn",
}
m["nnc"] = {
"Nancere",
3140491,
"cdc-est",
"Latn",
}
m["nnd"] = {
"West Ambae",
2841479,
"poz-vnn",
"Latn",
}
m["nne"] = {
"Ngandyera",
10961003,
"bnt-ova",
"Latn",
}
m["nnf"] = {
"Ngaing",
11732510,
"ngf-gmo",
"Latn",
}
m["nng"] = {
"Maring Naga",
12952908,
"sit-mar",
}
m["nnh"] = {
"Ngiemboon",
36286,
"bai",
"Latn",
}
m["nni"] = {
"North Nuaulu",
12952968,
"poz-cma",
}
m["nnj"] = {
"Nyangatom",
4662604,
"sdv-ttu",
}
m["nnk"] = {
"Nankina",
11732502,
"ngf-yup",
"Latn",
}
m["nnl"] = {
"Northern Rengma Naga",
7067615,
"tbq-anp",
}
m["nnm"] = {
"Namia",
56363,
"paa-sep",
"Latn",
}
m["nnn"] = {
"Ngete",
56625,
"cdc-mas",
"Latn",
}
m["nnp"] = {
"Wancho",
7967085,
"sit-kch",
"Wcho, Deva, Latn",
}
m["nnq"] = {
"Ngindo",
7022366,
"bnt-mbi",
"Latn",
}
m["nnr"] = {
"Narungga",
13591127,
"aus-pam",
"Latn",
}
m["nnt"] = {
"Nanticoke",
3915517,
"alg-eas",
"Latn",
}
m["nnu"] = {
"Dwang",
35258,
"alv-gng",
"Latn",
}
m["nnv"] = {
"Nukunu",
10604066,
nil,
"Latn",
}
m["nnw"] = {
"Southern Nuni",
11152248,
"nic-gnn",
"Latn",
}
m["nnx"] = {
"Ngong",
12952915,
}
m["nny"] = { -- contrast aus-ynk
"Nyangga",
10604331,
"aus-tnk",
"Latn",
}
m["nnz"] = {
"Nda'nda'",
36016,
"bai",
"Latn",
}
m["noa"] = {
"Woun Meu",
3111873,
"sai-chc",
"Latn",
}
m["noc"] = {
"Nuk",
11732534,
"ngf-boa",
"Latn",
}
m["nod"] = {
"Northern Thai",
565110,
"tai-swe",
"Lana, Thai",
strip_diacritics = {remove_diacritics = c.ZWNJ},
sort_key = {
Lana = "Lana-sortkey",
Thai = "Thai-sortkey"
},
}
m["noe"] = {
"Nimadi",
3502294,
"raj",
"Deva",
translit = "hi-translit",
}
m["nof"] = {
"Nomane",
11732531,
"ngf-sim",
"Latn",
}
m["nog"] = {
"Nogai",
33871,
"trk-kno",
"Cyrl, Arab, Latn",
translit = "nog-translit",
override_translit = true,
}
m["noh"] = {
"Nomu",
11732532,
"ngf-dal",
"Latn",
}
m["noi"] = {
"Noiri",
12953774,
"inc-bhi",
}
m["noj"] = {
"Nonuya",
5372139,
"sai-wit",
"Latn",
}
m["nok"] = {
"Nooksack",
3343396,
"sal",
}
m["nol"] = {
"Nomlaki",
3343229,
"nai-wtq",
"Latn",
}
m["nom"] = {
"Nocamán",
7046289,
"sai-pan",
"Latn",
}
m["non"] = {
"Old Norse",
35505,
"gmq",
"Latn, Runr",
translit = {Runr = "Runr-translit"},
}
m["nop"] = {
"Numanggang",
7069052,
"ngf-boa",
"Latn",
}
m["noq"] = {
"Ngongo",
11057478,
"bnt-yak",
"Latn",
}
m["nos"] = {
"Eastern Nisu",
25559419,
"tbq-nis",
}
m["not"] = {
"Nomatsiguenga",
3342992,
"awd",
"Latn",
}
m["nou"] = {
"Ewage-Notu",
5418860,
"ngf-bin",
"Latn",
}
m["nov"] = {
"Novial",
36738,
"art",
"Latn",
type = "appendix-constructed"
}
m["now"] = {
"Nyambo",
4967930,
"bnt-haj",
"Latn",
}
m["noy"] = {
"Noy",
36321,
"alv-bua",
}
m["noz"] = {
"Nayi",
3183349,
"omv-diz",
}
m["npa"] = {
"Nar Phu",
4926353,
"sit-tam",
}
m["npb"] = {
"Nupbikha",
3695201,
"sit-ebo",
}
m["npg"] = {
"Ponyo",
7228475,
"sit-kch",
}
m["nph"] = {
"Phom",
7187109,
"sit-kch",
}
m["npl"] = {
"Southeastern Puebla Nahuatl",
4632950,
"azc-nah",
"Latn",
}
m["npn"] = {
"Mondropolon",
3320594,
"poz-aay",
}
m["npo"] = {
"Pochuri Naga",
7206342,
"tbq-anp",
}
m["nps"] = {
"Nipsan",
11732528,
"ngf-mek",
"Latn",
}
m["npu"] = {
"Puimei Naga",
7259044,
"sit-zem",
}
m["npx"] = {
"Noipä",
63283617,
"poz-tem",
"Latn",
}
m["npy"] = {
"Napu",
12953768,
}
m["nqg"] = {
"Ede Nago",
12952408,
"alv-ede",
"Latn",
}
m["nqk"] = {
"Kura Ede Nago",
12952409,
"alv-ede",
}
m["nql"] = {
"Ngendelengo",
63283693,
"bnt-swb",
"Latn",
}
m["nqm"] = {
"Ndom",
6983791,
"paa-kol",
"Latn",
}
m["nqn"] = {
"Nen",
20816352,
"paa-nam",
"Latn",
}
m["nqo"] = {
"N'Ko",
18546266,
"dmn-man",
"Nkoo",
}
m["nqq"] = {
"Kyan-Karyaw Naga",
63283784,
"sit-tno",
}
m["nqy"] = {
"Akyaung Ari",
4702035,
"sit-tng",
}
m["nra"] = {
"Ngom",
36087,
"bnt-kel",
"Latn",
}
m["nrb"] = {
"Nara",
36179,
"sdv-nes",
}
m["nrc"] = {
"Noric",
37023,
"cel",
"Ital",
-- Ital translit in [[Module:scripts/data]]
}
m["nre"] = {
"Southern Rengma Naga",
7313205,
"tbq-anp",
}
m["nrf"] = {
"Norman",
33850,
"roa-oil",
"Latn",
wikimedia_codes = "nrm",
ancestors = "fro-nor",
sort_key = s["roa-oil-sortkey"],
}
m["nrg"] = {
"Narango",
12952929,
"poz-vnn",
"Latn",
}
m["nri"] = {
"Chokri Naga",
5104247,
"tbq-anp",
}
m["nrk"] = {
"Ngarla",
3915860,
"aus-nga",
"Latn",
}
m["nrl"] = {
"Ngarluma",
7022078,
"aus-nga",
"Latn",
}
m["nrm"] = {
"Narom",
3336135,
"poz-swa",
"Latn",
}
m["nrn"] = {
"Norn",
36708,
"gmq-ins",
"Latn",
}
m["nrp"] = {
"North Picene",
430138,
"qfa-unc", -- extinct, might be a hoax
"Ital",
-- Ital translit in [[Module:scripts/data]]
}
m["nrr"] = {
"Norra",
12952967,
"tai",
}
m["nrt"] = {
"Northern Kalapuya",
3192121,
"nai-klp",
}
m["nru"] = {
"Narua",
21658869,
"sit-nas",
"Latn",
}
m["nrx"] = {
"Ngurmbur",
2591251,
}
m["nrz"] = {
"Lala (New Guinea)",
6480151,
"poz-ocw",
"Latn",
}
m["nsa"] = {
"Sangtam Naga",
7418144,
"sit-aao",
}
m["nsb"] = {
"Lower Nossob",
6693681,
"khi-tuu",
"Latn",
}
m["nsc"] = {
"Nshi",
11129508,
"nic-rnn",
"Latn",
}
m["nsd"] = {
"Southern Nisu",
63284284,
"tbq-nis",
}
m["nse"] = {
"Nsenga",
3081996,
"bnt-sna",
"Latn",
}
m["nsg"] = {
"Ngasa",
56345,
"sdv-lma",
}
m["nsh"] = {
"Ngoshie",
7022582,
"nic-mom",
"Latn",
}
m["nsi"] = {
"Nigerian Sign Language",
7033021,
"sgn",
}
m["nsk"] = {
"Naskapi",
1704302,
"alg",
"Cans, Latn",
ancestors = "cr",
translit = "nsk-translit",
}
m["nsl"] = {
"Norwegian Sign Language",
1781613,
"sgn",
}
m["nsm"] = {
"Sema",
3478238,
"tbq-anp",
}
m["nsn"] = {
"Nehan",
3337774,
"poz-ocw",
"Latn",
}
m["nso"] = {
"Northern Sotho",
33890,
"bnt-sts",
"Latn",
}
m["nsp"] = {
"Nepalese Sign Language",
3915492,
"sgn",
}
m["nsq"] = {
"Northern Sierra Miwok",
3344226,
"nai-utn",
"Latn",
}
m["nsr"] = {
"Maritime Sign Language",
3915483,
"sgn",
}
m["nss"] = {
"Nali",
3335385,
"poz-aay",
}
m["nst"] = {
"Tangsa",
56350,
"sit-tno",
"Latn, Tnsa",
}
m["nsu"] = {
"Sierra Negra Nahuatl",
63284326,
"azc-nah",
"Latn",
}
m["nsv"] = {
"Southwestern Nisu",
63308004,
"tbq-nis",
}
m["nsw"] = {
"Navut",
3337327,
"poz-vnn",
"Latn",
}
m["nsx"] = {
"Nsongo",
7067577,
"bnt-tmb",
"Latn",
}
m["nsy"] = {
"Nasal",
6966574,
}
m["nsz"] = {
"Nisenan",
33665,
"nai-mdu",
"Latn",
}
m["ntd"] = {
"Northern Tidung",
24938325,
"poz-san",
}
-- ISO merged "nte" into "eko"
m["ntg"] = {
"Ngantangarra",
33060509,
}
m["nti"] = {
"Natioro",
36140,
"alv-wan",
}
m["ntj"] = {
"Ngaanyatjarra",
3915409,
"aus-pam",
"Latn",
}
m["ntk"] = {
"Ikoma",
5996114,
"bnt-lok",
"Latn",
}
m["ntm"] = {
"Nateni",
3070731,
"nic-grm",
"Latn",
}
m["nto"] = {
"Ntomba",
11130292,
"bnt-mon",
"Latn",
}
m["ntp"] = {
"Northern Tepehuan",
15615651,
"azc-pim",
"Latn",
sort_key = {remove_diacritics = c.acute},
}
m["ntr"] = {
"Delo",
35195,
"nic-gne",
"Latn",
}
m["nts"] = {
"Natagaimas",
6967931,
}
m["ntu"] = {
"Natügu",
63308082,
"poz-tem",
"Latn",
}
m["ntw"] = {
"Nottoway",
3344791,
"iro-nor",
"Latn",
}
m["ntx"] = {
"Somra",
7560536,
"sit-tng",
}
m["nty"] = {
"Mantsi",
56878,
"sit-mnz",
}
m["nua"] = {
"Yuanga",
3573088,
"poz-cln",
"Latn",
}
m["nuc"] = {
"Nukuini",
3346231,
}
m["nud"] = {
"Ngala",
7021893,
"paa-ndu",
"Latn",
}
m["nue"] = {
"Ngundu",
12952953,
"bad-cnt",
"Latn",
}
m["nuf"] = {
"Nusu",
56413,
"tbq-nus",
"Latn",
}
m["nug"] = {
"Nungali",
7069826,
"aus-mir",
"Latn",
}
m["nuh"] = {
"Ndunda",
3913968,
"nic-mmb",
"Latn",
}
m["nui"] = {
"Ngumbi",
36459,
"bnt-yko",
}
m["nuj"] = {
"Nyole (Uganda)",
3739448,
"bnt-msl",
"Latn",
}
m["nuk"] = {
"Nootka",
2992876,
"wak",
"Latn",
}
m["nul"] = {
"Nusa Laut",
7070332,
"poz-cma",
}
m["num"] = {
"Niuafo'ou",
36173,
"poz-ton",
"Latn",
}
m["nun"] = {
"Anong",
2748232,
"sit-nng",
"Latn",
}
m["nuo"] = {
"Nguôn",
3915785,
"mkh-vie",
"Latn",
sort_key = "vi-sortkey",
}
m["nup"] = {
"Nupe",
36720,
"alv-ngb",
"Latn",
strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.macron .. c.caron},
sort_key = "nup-sortkey",
}
m["nuq"] = {
"Nukumanu",
12909019,
"poz-pnp",
"Latn",
}
m["nur"] = {
"Nuguria",
7068910,
"poz-pnp",
"Latn",
}
m["nus"] = {
"Nuer",
33675,
"sdv-dnu",
"Latn",
}
m["nut"] = {
"Nùng",
72695,
"tai",
"Latn, Hani",
sort_key = {Hani = "Hani-sortkey"},
}
m["nuu"] = {
"Ngbundu",
11126081,
"bad",
"Latn",
}
m["nuv"] = {
"Northern Nuni",
11016572,
"nic-gnn",
"Latn",
}
m["nuw"] = {
"Nguluwan",
6528643,
}
m["nux"] = {
"Mehek",
6809452,
"paa-sep",
"Latn",
}
m["nuy"] = {
"Nunggubuyu",
1747811,
"aus-arn",
"Latn",
}
m["nuz"] = {
"Tlamacazapa Nahuatl",
2073277,
"azc-nah",
"Latn",
}
m["nvh"] = {
"Nasarian",
6966614,
"poz-vnc",
"Latn",
}
m["nvm"] = {
"Namiae",
12952922,
"ngf-koi",
"Latn",
}
m["nvo"] = {
"Nyokon",
19573407,
"nic-mbw",
"Latn",
}
m["nwa"] = {
"Nawathinehena",
6982892,
"alg-ara",
"Latn",
}
m["nwb"] = {
"Nyabwa",
33664,
"kro-wee",
}
m["nwc"] = {
"Classical Newar",
5128301,
"sit-new",
"Brah, Deva, Newa, Ranj",
-- Brah translit in [[Module:scripts/data]] (NOTE: not present before, presumably an accidental omission)
}
m["nwe"] = {
"Ngwe",
36181,
"bai",
"Latn",
}
m["nwg"] = {
"Ngaiawang",
16920653,
"aus-pam",
"Latn",
}
m["nwi"] = {
"Southwest Tanna",
3504488,
"poz-vns",
"Latn",
}
m["nwm"] = {
"Nyamusa-Molo",
12747951,
"csu-bbk",
}
m["nwo"] = {
"Nauo",
6981305,
"aus-pam",
"Latn",
}
m["nwr"] = {
"Nawaru",
12638166,
"ngf-yar",
"Latn",
}
m["nwx"] = {
"Middle Newar",
65455877,
"sit-new",
"Deva, Newa, Ranj",
ancestors = "nwc",
}
m["nwy"] = {
"Nottoway-Meherrin",
65455878,
"iro-nor",
"Latn",
}
m["nxa"] = {
"Nauete",
6981095,
"poz-tim",
}
m["nxd"] = {
"Ngando (Congo)",
3913277,
"bnt-ske",
}
m["nxe"] = {
"Nage",
2295569,
"poz-cet",
}
m["nxg"] = {
"Ngadha",
1516651,
"poz-cet",
"Latn",
}
m["nxi"] = {
"Nindi",
7038230,
"bnt-mbi",
"Latn",
}
m["nxl"] = {
"South Nuaulu",
18544857,
"poz-cma",
}
m["nxm"] = {
"Numidian",
35761,
"afa",
"Tfng, Latn", --Tfng may not support all the needed characters
}
m["nxn"] = {
"Ngawun",
3915711,
"aus-pam",
"Latn",
}
m["nxo"] = {
"Ndambomo",
6983681,
"bnt-kel",
"Latn",
}
m["nxq"] = {
"Naxi",
2478711,
"sit-nas",
"Nkdb, Nkgb, Latn, Lisu",
-- Lisu translit, sort_key in [[Module:scripts/data]]
}
m["nxr"] = {
"Ninggerum",
11732526,
"ngf-lok",
"Latn",
}
-- nxu (Narau) merged into bpp (Kaure) per ISO 639-3 2020 merger
m["nxx"] = {
"Nafri",
6958211,
"paa-sen",
"Latn",
}
m["nyb"] = {
"Nyangbo",
36256,
"alv-ktg",
"Latn",
}
m["nyc"] = {
"Nyanga-li",
7070876,
"bnt-boa",
"Latn",
}
m["nyd"] = {
"Nyole (Kenya)",
7071227,
"bnt-msl",
"Latn",
}
m["nye"] = {
"Nyengo",
7071068,
"bnt-clu",
"Latn",
}
m["nyf"] = {
"Giryama",
3107606,
"bnt-mij",
"Latn",
}
m["nyg"] = {
"Nyindu",
11030685,
"bnt-shh",
"Latn",
}
m["nyh"] = {
"Nyigina",
3913780,
"aus-nyu",
"Latn",
}
m["nyi"] = {
"Nyimang",
34846,
"sdv-nyi",
"Latn",
}
m["nyj"] = {
"Nyanga (Congo)",
7070879,
"bnt-nyb",
"Latn",
}
m["nyk"] = {
"Nyaneka",
10962298,
"bnt-swb",
"Latn",
}
m["nyl"] = {
"Nyeu",
3033578,
"mkh-kat",
}
m["nym"] = {
"Nyamwezi",
4121131,
"bnt-tkm",
"Latn",
}
m["nyn"] = {
"Nyankole",
13207,
"bnt-nyg",
"Latn",
}
m["nyo"] = {
"Nyoro",
33794,
"bnt-nyg",
"Latn",
}
m["nyp"] = {
"Nyang'i",
7070894,
"ssa-klk",
}
m["nys"] = {
"Nyunga",
7049771,
"aus-pam",
"Latn",
}
m["nyt"] = {
"Nyawaygi",
3915783,
"aus-dyb",
"Latn",
}
m["nyu"] = {
"Nyungwe",
7071318,
"bnt-sna",
"Latn",
}
m["nyv"] = {
"Nyulnyul",
3442732,
"aus-nyu",
"Latn",
}
m["nyw"] = {
"Nyaw",
26425602,
"tai-nor", -- Chamberlain (1991), but Pittayaporn (2009) suggests tai-swe
"Thai, Tayo", -- Thailand
sort_key = "Thai-sortkey", -- no effect on Latn
}
m["nyx"] = {
"Nganyaywana",
3913800,
"aus-cww",
"Latn",
}
m["nyy"] = {
"Nyakyusa",
3272620,
"bnt-run",
"Latn",
}
m["nza"] = {
"Tigon Mbembe",
36518,
"nic-jkn",
"Latn",
}
m["nzb"] = {
"Njebi",
35923,
"bnt-nze",
"Latn",
}
m["nzd"] = {
"Nzadi",
17152586,
"bnt-bdz",
"Latn",
strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.caron},
}
m["nzi"] = {
"Nzima",
36337,
"alv-ctn",
"Latn",
}
m["nzk"] = {
"Nzakara",
3913339,
"znd",
"Latn",
}
m["nzm"] = {
"Zeme Naga",
21491053,
"sit-zem",
}
m["nzs"] = {
"New Zealand Sign Language",
36239,
"sgn",
}
m["nzu"] = {
"Central Teke",
36473,
"bnt-tkc",
"Latn",
}
m["nzy"] = {
"Nzakambay",
36374,
"alv-mbm",
"Latn",
}
m["nzz"] = {
"Nanga Dama Dogon",
6963443,
"nic-nwa",
}
return require("Module:languages").finalizeData(m, "language")
nosdy4maa4e6phfvm9t839f2u2w7og4
Module:quote
828
33065
178375
178155
2026-10-23T06:37:08Z
GinawaSaHapon
3989
178375
Scribunto
text/plain
--[=[
This module contains functions to implement quote-* templates.
Author: Benwing2; conversion into Lua of {{quote-meta/source}} template,
written by Sgconlaw with some help from Erutuon and Benwing2.
The main interface is quote_t(). Note that the source display is handled by source(), which reads both the
arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter.
]=]
local export = {}
--[=[
FIXME:
1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only.
The relevant code checks for a capitalized word; it should probably instead check for the actual month names or
abbrevs.
]=]
-- Named constants for all modules used, to make it easier to swap out sandbox versions.
local check_isxn_module = "Module:check isxn"
local debug_track_module = "Module:debug/track"
local en_utilities_module = "Module:en-utilities"
local italics_module = "Module:italics"
local labels_module = "Module:labels"
local languages_module = "Module:languages"
local languages_error_module = "Module:languages/error"
local links_module = "Module:links"
local number_utilities_module = "Module:number utilities"
local parameters_module = "Module:parameters"
local parse_utilities_module = "Module:parse utilities"
local qualifier_module = "Module:qualifier"
local roman_numerals_module = "Module:roman numerals"
local scribunto_module = "Module:Scribunto"
local script_utilities_module = "Module:script utilities"
local scripts_module = "Module:scripts"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local template_parser_module = "Module:template parser"
local usex_module = "Module:usex"
local usex_templates_module = "Module:usex/templates"
local utilities_module = "Module:utilities"
local yesno_module = "Module:yesno"
local concat = table.concat
local insert = table.insert
local new_title = mw.title.new
local remove = table.remove
local require = require
local sort = table.sort
local u = mw.ustring.char
local ugsub = mw.ustring.gsub
local umatch = mw.ustring.match
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- Use HTML entities here to avoid parsing issues (esp. with brackets)
local SEMICOLON_SPACE = "; "
local SPACE_LBRAC = " ["
local RBRAC = "]"
local TEMP_LT = u(0xFFF1)
local TEMP_GT = u(0xFFF2)
local TEMP_LBRAC = u(0xFFF3)
local TEMP_RBRAC = u(0xFFF4)
local TEMP_SEMICOLON = u(0xFFF5)
local function apply_subst(...)
apply_subst = require(usex_module).apply_subst
return apply_subst(...)
end
local function check_isbn(...)
check_isbn = require(check_isxn_module).check_isbn
return check_isbn(...)
end
local function check_issn(...)
check_issn = require(check_isxn_module).check_issn
return check_issn(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function embedded_language_links(...)
embedded_language_links = require(links_module).embedded_language_links
return embedded_language_links(...)
end
local function escape_wikicode(...)
escape_wikicode = require(parse_utilities_module).escape_wikicode
return escape_wikicode(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function find_parameters(...)
find_parameters = require(template_parser_module).find_parameters
return find_parameters(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_processed_labels(...)
format_processed_labels = require(labels_module).format_processed_labels
return format_processed_labels(...)
end
local function format_qualifier(...)
format_qualifier = require(qualifier_module).format_qualifier
return format_qualifier(...)
end
local function format_usex(...)
format_usex = require(usex_module).format_usex
return format_usex(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_number(...)
get_number = require(number_utilities_module).get_number
return get_number(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function gsplit(...)
gsplit = require(string_utilities_module).gsplit
return gsplit(...)
end
local function page_should_be_ignored(...)
page_should_be_ignored = require(usex_templates_module).page_should_be_ignored
return page_should_be_ignored(...)
end
local function parse_inline_modifiers(...)
parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers
return parse_inline_modifiers(...)
end
local function parse_inline_modifiers_from_segments(...)
parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments
return parse_inline_modifiers_from_segments(...)
end
local function parse_multi_delimiter_balanced_segment_run(...)
parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run
return parse_multi_delimiter_balanced_segment_run(...)
end
local function parse_term_with_lang(...)
parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang
return parse_term_with_lang(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function pluralize(...)
pluralize = require(en_utilities_module).pluralize
return pluralize(...)
end
local function process_params(...)
process_params = require(parameters_module).process
return process_params(...)
end
local function remove_links(...)
remove_links = require(links_module).remove_links
return remove_links(...)
end
local function roman_to_arabic(...)
roman_to_arabic = require(roman_numerals_module).roman_to_arabic
return roman_to_arabic(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function scribunto_parameter_key(...)
scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key
return scribunto_parameter_key(...)
end
local function serial_comma_join(...)
serial_comma_join = require(table_module).serialCommaJoin
return serial_comma_join(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function split_alternating_runs(...)
split_alternating_runs = require(parse_utilities_module).split_alternating_runs
return split_alternating_runs(...)
end
local function split_and_process_raw_labels(...)
split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels
return split_and_process_raw_labels(...)
end
local function split_on_comma(...)
split_on_comma = require(parse_utilities_module).split_on_comma
return split_on_comma(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_transcription(...)
tag_transcription = require(script_utilities_module).tag_transcription
return tag_transcription(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function unitalicize_brackets(...)
unitalicize_brackets = require(italics_module).unitalicize_brackets
return unitalicize_brackets(...)
end
local function upper(...)
upper = require(string_utilities_module).upper
return upper(...)
end
local function usub(...)
usub = require(string_utilities_module).sub
return usub(...)
end
local function yesno(...)
yesno = require(yesno_module)
return yesno(...)
end
local function track(page)
debug_track("quote/" .. page)
end
local function maintenance_line(text)
return '<span class="maintenance-line">(' .. text .. ")</span>"
end
local function isbn(text)
return "[[Special:BookSources/"
.. text
.. "|→ISBN]]"
.. check_isbn(
text,
' <span class="error" style="font-size:88%">Invalid ISBN</span>[[Category:Pages with ISBN errors]]'
)
end
local function issn(text)
return "[https://www.worldcat.org/issn/"
.. text
.. " →ISSN]"
.. check_issn(
text,
' <span class="error" style="font-size:88%">Invalid ISSN</span>[[Category:Pages with ISSN errors]]'
)
end
local function lccn(text)
text = text:gsub(" ", "")
if text:find("-") then
-- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]]
local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$")
if prefix then
if ulen(part2) < 6 then
part2 = ("0"):rep(6 - ulen(part2)) .. part2
end
text = prefix .. part1 .. part2
end
end
return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]"
end
local function format_date(text)
return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy")
end
-- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a
-- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs.
local function parse_and_format_labels(raw_lb, lang)
if not raw_lb then
return nil
end
local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true}
labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true}
if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances
return {labels}
end
end
-- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the
-- name of the parameter from which the list of language codes was fetched.
local function format_langs(langs)
local names = {}
for i, lang in ipairs(langs) do
names[i] = lang:getCanonicalName()
end
if #names == 1 then
return names[1]
end
return serial_comma_join(names)
end
local function get_first_lang(langs)
return langs[1] or get_lang("und")
end
--[=[
Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we
exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}},
{{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters,
plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it.
The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as
foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers).
Also exclude things that look like URL's from being parsed as having language code prefixes.
]=]
local function val_should_not_be_parsed_for_annotations(val)
return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://")
end
local param_mods = {
t = {
-- <t:...> and <gloss:...> are aliases.
item_dest = "gloss",
},
gloss = {},
alt = {},
tr = {},
ts = {},
subst = {},
sc = {type = "script"},
f = {
convert = function(arg, parse_err)
local prefix, val = arg:match("^(.-):([^ ].*)$")
if not prefix then
prefix = ""
val = arg
end
local tags, sc_code, sc = prefix:match("^(.*)/(.-)$")
if sc_code then
sc = get_script(sc_code) or
require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang")
else
tags = prefix
end
local quals
if tags ~= "" then
quals = split_on_comma(tags)
for i, qual in ipairs(quals) do
local obj = get_lang(qual, nil, "allow etym") or get_script(qual)
quals[i] = obj or qual
end
end
return {
quals = quals,
sc = sc,
val = val,
}
end,
store = "insert",
},
q = {},
qq = {},
}
local function generate_obj_annotated_text(text, parse_err, paramname)
local obj = {}
if text:find(":[^ ]") or text:find("%[%[") then
local display, is_wikipedia_wikisource
obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource =
parse_term_with_lang {
term = text,
parse_err = parse_err,
paramname = paramname
}
-- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link
-- to avoid the w: or s: prefix showing. We should probably avoid this by calling
-- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff
-- that we currently do; but we need to test that carefully to make sure it doesn't do things like
-- munge % signs.
if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then
-- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in
-- parse_inline_modifiers().
obj.display = display
end
else
obj.text = text
obj.link = text
end
return obj
end
--[=[
Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or
inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value
was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or
<gloss:...> inline modifier.
If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g.
'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following
fields:
`lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is
given.
`text`: The text after stripping off any language prefix and inline modifiers.
`link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`.
`alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil.
`subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter.
`sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil.
`tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil.
`ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil.
`gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise
the <t:...> or <gloss:...> modifiers if given, otherwise nil.
`f`: Foreign versions of the text.
`q`: Left qualifiers.
`qq`: Right qualifiers.
Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as
might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return
value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of
the text and CSS-tag the text accordingly, but to leave the text untagged.
This object can be passed to format_annotated_text() to format a string displaying the text (appropriately
script-tagged, unless `noscript` is set, as described above) and modifiers.
]=]
local function parse_annotated_text(val, fullname, explicit_gloss)
if not val then
return nil
end
-- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused
-- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having
-- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a
-- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script
-- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big
-- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the
-- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even
-- more.)
if val_should_not_be_parsed_for_annotations(val) then
return {text = val, link = val, noscript = true, gloss = explicit_gloss}
end
local obj
if val:find("<") then
-- Check for inline modifier.
obj = parse_inline_modifiers(val, {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_annotated_text,
})
else
obj = generate_obj_annotated_text(val, nil, fullname)
end
if explicit_gloss then
obj.gloss = explicit_gloss
end
return obj
end
local html_entity_char_to_replacement = {
["<"] = TEMP_LT,
[">"] = TEMP_GT,
["["] = TEMP_LBRAC,
["]"] = TEMP_RBRAC,
}
local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code)
-- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like)
-- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get
-- interpreted as a delimiter.
local ch = decode_entities(entity)
if ch ~= entity then
return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON
end
-- If the entity doesn't decode, escape it anyway iff it follows a valid format.
if hash == "" then
-- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as
-- invalid.
return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
elseif x == "" then
return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
local html_entity_replacement_to_char = {
[TEMP_LT] = "<",
[TEMP_GT] = ">",
[TEMP_LBRAC] = "[",
[TEMP_RBRAC] = "]",
[TEMP_SEMICOLON] = ";",
}
local function undo_html_entity_replacement(txt)
-- Pattern covers everything in html_entity_replacement_to_char.
return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char))
end
-- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]]
-- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no
-- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present)
-- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate
-- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter);
-- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a
-- delimiter); and (c) colons not followed by a space (which may indicate a language prefix).
local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement)
local obj = generate_obj_annotated_text(text, parse_err, paramname)
if not no_undo_html_entity_replacement then
obj.text = undo_html_entity_replacement(obj.text)
obj.link = undo_html_entity_replacement(obj.link)
end
return obj
end
--[=[
Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with
their own inline modifiers. Some examples:
* mainauthor=Paula Pattengale; Terea Sonsthagen
* author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson
* author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank
* author=G Ristori; et al.
* author=Jason Scott; zh:王晰宁<t:Wang Xining>
* editors=zh:包文俊; zh:金心雯
* quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen>
There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.:
* author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}]
* author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}})
* author=James (the Elder;) Humphrys
There may also be HTML entities with semicolons in them:
* author=[{{w|Gilbert Clerke}}]
* 2ndauthor=Martin Biddle & Sally Badham
* author=Peter Christen Asbjørnsen
There may be both embedded semicolons and HTML entities with semicolons in them:
* author=[{{w|Voltaire}} [pseudonym; François-Marie Arouet]]
In general we want to treat [ like an opening bracket and ] like a closing bracket. Beware that they may be
mismatched:
* author=Anonymous [{{w|Karl Maria Kertbeny}}]
Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was
retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...>
inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If
`explicit_gloss` is specified and multiple values were seen, an error results.)
Return value is a list of objects of the same sort as returned by parse_annotated_text().
]=]
local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname)
if not val then
return nil
end
-- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated
-- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or
-- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML
-- entities; in the places where this occurs, the variable name contains 'html' in it.
local splitchar, english_delim
if val:find("^,") then
splitchar = ","
english_delim = "comma"
val = val:gsub("^,", "")
else
splitchar = ";"
english_delim = "semicolon"
end
-- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers).
if not val:find("[<" .. splitchar .. "]") then
if val_should_not_be_parsed_for_annotations(val) then
return {{text = val, link = val, noscript = true}}
else
return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")}
end
end
-- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or
-- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand
-- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a
-- delimiter).
if not val:find("[<>%[%](){}&]") then
local entity_objs = {}
for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do
if val_should_not_be_parsed_for_annotations(entity) then
insert(entity_objs, {
text = entity,
link = entity,
noscript = true
})
else
insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement"))
end
end
return entity_objs
end
-- Escape HTML entities, and get rid of directionality markers.
local amp = val:find("&", nil, true)
if amp then
-- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities
-- that have non-ASCII characters in their codes.
val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement)
end
-- Pattern covers left-to-right (U+200E) and right-to-left (U+200F).
val = val:gsub("\226\128[\142\143]", "")
-- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket
-- as matching literal versions of the same characters.
local entity_runs = parse_multi_delimiter_balanced_segment_run(
val,
{{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}},
true
)
if type(entity_runs) == "string" then
local undo_val = undo_html_entity_replacement(val)
-- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off
-- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears
-- the text is already script-tagged).
return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}}
end
-- Split on semicolon (or comma), possibly surrounded by whitespace.
local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*")
-- Process each value.
local entity_objs = {}
for _, entity_group in ipairs(separated_groups) do
-- Rejoin runs that don't involve <...>.
local j = 2
while j <= #entity_group do
if not entity_group[j]:find("^<.*>$") then
entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1]
remove(entity_group, j)
remove(entity_group, j)
else
j = j + 2
end
end
local oneval = undo_html_entity_replacement(concat(entity_group))
-- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it,
-- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed
-- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more.
if val_should_not_be_parsed_for_annotations(oneval) then
insert(entity_objs, {
text = oneval,
link = oneval,
noscript = true
})
else
local obj
if #entity_group > 1 then
-- Check for inline modifier.
obj = parse_inline_modifiers_from_segments({
group = entity_group,
arg = oneval,
props = {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_multivalued_annotated_text,
},
})
else
obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname)
end
insert(entity_objs, obj)
end
end
if explicit_gloss then
if #entity_objs > 1 then
error(
(
"Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> "
.. "inline modifier attached to the individual entities"
):format(explicit_gloss_fullname, english_delim, fullname)
)
end
entity_objs[1].gloss = explicit_gloss
end
return entity_objs
end
--[=[
Format a text property that may be in a foreign language or script, along with annotations. This is conceptually
similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is
more appropriate for bibliographic entries. The output looks like this:
TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS]
`textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further
wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a
similar function for the gloss.
]=]
local function format_annotated_text(textobj, tag_text_func, tag_gloss_func)
if not textobj then
return nil
end
local text, link = textobj.text, textobj.link
local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss
-- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a
-- Wikipedia link is given.
local alt = textobj.alt or textobj.display
if alt then
if link:find("%[%[") or link:find("%]%]") then
local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt)
error(escape_wikicode(errmsg))
end
text = ("[[%s|%s]]"):format(link, alt)
end
-- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}.
-- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in
-- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language
-- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration.
if not textobj.noscript then
local lang = textobj.lang
-- As an optimization, don't do script detection on an argument that contains only ASCII.
local sc = textobj.sc
or lang and lang:findBestScript(text)
or not text:find("^[ -~]$") and find_best_script_without_lang(text)
or nil
-- As an optimization, don't do any of the following if there's no language, script, translit or transcription,
-- as will be the case with simple ASCII values.
if lang or sc or tr or ts then
if not lang then
lang = get_lang("und")
end
if tr == "-" then
tr = nil
elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn
-- might return nil
local text_for_tr = text
if subst then
text_for_tr = apply_subst(text_for_tr, subst)
else
text_for_tr = remove_links(text)
end
tr = (lang:transliterate(text_for_tr, sc))
end
if text:find("%[%[") then
-- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents,
-- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this
-- should not happen, and embedded_language_links() should do nothing if no embedded links
-- are present. To work around this, only call embedded_language_links() when there are
-- embedded links present.
text = embedded_language_links({
term = text,
lang = lang,
sc = sc,
})
end
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
text = tag_text(text, lang, sc)
end
if tr then
-- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not
-- likely to be a term that has an entry.
tr = tag_translit(tr, lang, "usex")
end
if ts then
ts = tag_transcription(ts, lang, "usex")
end
end
end
text = unitalicize_brackets(text)
if tag_text_func then
text = tag_text_func(text)
end
local parts = {}
if textobj.q then
insert(parts, format_qualifier(textobj.q) .. " ")
end
insert(parts, text)
if tr or ts or f or gloss then
insert(parts, SPACE_LBRAC)
local subparts = {}
if tr or ts then
local tr_ts
if ts then
ts = "/" .. ts .. "/"
end
if tr and ts then
tr_ts = tr .. " " .. ts
else
tr_ts = tr or ts
end
insert(subparts, tr_ts)
end
if f then
for _, ff in ipairs(f) do
local sc = ff.sc
local lang
if not sc and ff.quals then
local qual = ff.quals[1]
if type(qual) == "string" then
-- do nothing; we'll do script detection farther down
elseif qual:hasType("script") then
sc = qual
else -- language
sc = qual:findBestScript(ff.val)
lang = qual
end
end
if not lang then
lang = get_lang("und")
end
sc = sc or find_best_script_without_lang(ff.val)
local val = embedded_language_links({
term = ff.val,
lang = lang,
sc = sc,
})
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
val = tag_text(val, lang, sc)
end
local qual_prefix
if ff.quals then
for i, qual in ipairs(ff.quals) do
if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then
ff.quals[i] = qual:getCanonicalName()
end
end
qual_prefix = concat(ff.quals, "/") .. ": "
else
qual_prefix = ""
end
insert(subparts, qual_prefix .. val)
end
end
if gloss then
gloss = '<span class="e-translation">' .. gloss .. "</span>"
gloss = unitalicize_brackets(gloss)
if tag_gloss_func then
gloss = tag_gloss_func(gloss)
end
insert(subparts, gloss)
end
insert(parts, concat(subparts, ", "))
insert(parts, RBRAC)
end
if textobj.qq then
insert(parts, " " .. format_qualifier(textobj.qq))
end
return concat(parts)
end
--[=[
Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the
multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(),
joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using
serial_comma_join() with the specified conjunction.
`textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in
format_annotated_text().
]=]
local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func)
if not textobjs then
return nil
end
if #textobjs == 1 then
return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func)
end
local parts = {}
for _, textobj in ipairs(textobjs) do
insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func))
end
-- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.")
local use_semicolon = false
for _, obj in ipairs(textobjs) do
-- Use remove_links to ignore commas in links
if obj.text and remove_links(obj.text):find(", ") then
use_semicolon = true
break
end
end
local n = #parts
if n > 0 and parts[n]:match("^'*et al[.']*$") then
-- Special handling for 'et al.'
parts[n] = "''et al.''"
if n == 2 then
-- author et al.
return concat(parts, " ")
else
-- author 1, author 2, et al.
return concat(parts, (use_semicolon and "; ") or ", ")
end
if delimiter == "and" or delimiter == "or" then
delimiter = ", "
end
return concat(parts, delimiter)
end
if delimiter == "and" or delimiter == "or" then
return serial_comma_join(parts, {conj = delimiter})
end
return concat(parts, delimiter or ((use_semicolon and "; ") or ", "))
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then
return nil
elseif type(arg) ~= "string" then
return arg
end
arg = mw.text.trim(arg)
if arg == "" then
return nil
end
return arg
end
local abbrs = {
["a."] = {anchor = "a.", full = "ante"},
["c."] = {anchor = "c.", full = "circa"},
["p."] = {anchor = "p.", full = "post"},
}
-- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec.
-- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found,
-- returns an empty string and the full date.
local function process_ante_circa_post(date)
local prefix = usub(date, 1, 2)
local abbr = abbrs[prefix]
local abbr_prefix = ""
if abbr then
abbr_prefix = "''[[Apendise:Glosaryo#"
.. abbr.anchor
.. '|<abbr title="'
.. abbr.full
.. '">'
.. abbr.anchor
.. "</abbr>]]'' "
-- Remove lowercase letter, period, and space from beginning of date parameter.
date = ugsub(date, "^%l%.%s*", "")
end
return abbr_prefix, date
end
-- Format the arguments that specify the date of the quotation. These include the following:
-- |date=: The date. If |start_date= is given, this is the end date.
-- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given.
-- |start_date=: The start date, to specify a range.
-- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given.
-- |accessdate=: Date a website was accessed; processed if no other date was given.
-- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date.
--
-- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if
-- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=,
-- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is
-- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of
-- the range is |start_date_published=, etc.
--
-- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in
-- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to
-- have an index added to them (|date2=, |year2=, |month2=, etc.).
--
-- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used.
--
-- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value.
--
-- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e.
-- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and
-- neither |nodate= is given to indicate that there is no date, or |accessdate= is given).
--
-- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category
-- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added
-- (in which case the scond return value will always be nil).
local function format_date_args(
a,
get_full_paramname,
alias_map,
parampref,
paramsuf,
bold_year,
maintenance_line_no_date,
year_last
)
local output = {}
parampref = parampref or ""
paramsuf = paramsuf or ""
local function getp(param)
return a(parampref .. param .. paramsuf)
end
local function pname(param)
local fullname = get_full_paramname(parampref .. param .. paramsuf)
return alias_map[fullname] or fullname
end
-- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of
-- the parameter from which the timestamp was fetched, for error messages.
local function format_date_with_code(code, timestamp, param)
local language = mw.getContentLanguage()
local ok, date = pcall(language.formatDate, language, code, timestamp)
if ok then
return date
else
-- All the formats used in format_date_args() are fine, so the timestamp must be at fault.
error(
(
"Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the "
.. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]"
):format(pname(param), tostring(timestamp))
)
end
end
-- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following
-- algorithm:
-- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are
-- given, the day shows up as 1.
-- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given.
-- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized
-- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not.
--
-- `param` is the base name of the parameter from which the timestamp was fetched.
local function date_has_day_specified(timestamp, param)
local day = format_date_with_code("j", timestamp, param)
if day ~= "1" then
return true
end
local english_month = timestamp:find("%u")
local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " ")))
local seen_nums = split(canon_timestamp, " ", true)
local saw_one = false
for _, num in ipairs(seen_nums) do
if num == "1" or num == "01" then
saw_one = true
break
end
end
if not saw_one then
return false
end
return #seen_nums >= 3 or english_month and #seen_nums >= 2
end
-- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include
-- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param
-- from which the date was fetched, for error messages.
local function format_bold_date(date, explicit_day_given, date_param)
local day_month_code = explicit_day_given and "j F" or "F"
local month_day_code = explicit_day_given and "F j" or "F"
if year_last then
if bold_year then
-- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given).
return format_date_with_code(day_month_code .. " '''Y'''", date, date_param)
else
-- This formats like "3 August 2023" (or "August 2023" if day not explicitly given).
return format_date_with_code(day_month_code .. " Y", date, date_param)
end
else
if bold_year then
-- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given).
return format_date_with_code("'''Y''' " .. month_day_code, date, date_param)
else
-- This formats like "2023 August 3" (or "2023 August" if day not explicitly given).
return format_date_with_code("Y " .. month_day_code, date, date_param)
end
end
end
-- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't
-- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives
-- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for
-- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which
-- uses {{#formatdate:}}) accept similar date formats. See:
-- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]]
-- * [[mw:Help:Extension:ParserFunctions##time]]
-- * [[mw:Help:Magic_words#Formatting]]
-- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date";
-- `parampref` is the prefix added to "date" to get the parameter name.
local function fix_date(date, param_pref)
if tonumber(date) ~= nil then
error(
("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format(
pname(param_pref .. "date"),
pname(param_pref .. "year")
)
)
elseif date and date:find("%s*%a+,%s*%d+%s*$") then
error(
("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format(
pname(param_pref .. "date"),
pname(param_pref .. "month"),
pname(param_pref .. "year")
)
)
end
if date then
-- Commas are replaced with spaces to prevent parsing issues
local fixed_date = ugsub(date, ", *", " ")
return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1"))
end
end
local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "")
local year = getp("year")
local month = getp("month")
local start_year = getp("start_year")
local start_month = getp("start_month")
if date and year then
error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year")))
end
if date and month then
error(
("|%s= should only be specified in conjunction with |%s=, not with |%s="):format(
pname("month"),
pname("year"),
pname("date")
)
)
end
if start_date and start_year then
error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year")))
end
if start_date and start_month then
error(
("|%s= should only be specified in conjunction with |%s=, not with |%s="):format(
pname("start_month"),
pname("start_year"),
pname("start_date")
)
)
end
if (start_date or start_year) and not (date or year) then
error(
("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format(
pname("start_date"),
pname("start_year"),
pname("start_month"),
pname("date"),
pname("year"),
pname("month")
)
)
end
local dash = " – "
local day_explicitly_given = date and date_has_day_specified(date, "date")
local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date")
-- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or
-- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based
-- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already.
-- `date_param` is the base name of the param from which the date was fetched, for error messages.
local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param)
if date then
return format_bold_date(date, explicit_day_given, date_param)
else
-- Boldface a year spec if it's not already boldface.
if bold_year and not yearobj.text:find("'''") then
-- Clone the year object before modifying it because we may use it later to check against the current
-- year (if we're dealing with start_year).
yearobj = shallow_copy(yearobj)
yearobj.text = "'''" .. yearobj.text .. "'''"
if yearobj.alt then
yearobj.alt = "'''" .. yearobj.alt .. "'''"
end
end
if year_last then
return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj)
else
return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "")
end
end
end
local yearobj = parse_annotated_text(year, pname("year"))
local monthobj = parse_annotated_text(month, pname("month"))
local start_yearobj = parse_annotated_text(start_year, pname("start_year"))
local start_monthobj = parse_annotated_text(start_month, pname("start_month"))
if start_yearobj then
local abbr_prefix
abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text)
start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link))
insert(output, abbr_prefix)
elseif yearobj then
local abbr_prefix
abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text)
yearobj.link = select(2, process_ante_circa_post(yearobj.link))
insert(output, abbr_prefix)
end
if start_date or start_year then
local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date")
local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil
local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil
local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date")
local beg_month = start_monthobj and start_monthobj.text
or start_date and format_date_with_code("F", start_date, "start_date")
or nil
local beg_day = start_date
and start_day_explicitly_given
and format_date_with_code("j", start_date, "start_date")
or nil
if year_last then
if beg_day then
insert(output, beg_day .. " " .. beg_month)
else
insert(output, beg_month)
end
if beg_year ~= cur_year then
insert(output, " " .. beg_year)
end
else
insert(output, format_date_or_year_month(
start_date,
start_yearobj,
start_monthobj,
start_day_explicitly_given,
"start_date"
))
end
if cur_year ~= beg_year then
-- Different years; insert current date in full.
if beg_month or cur_month then
insert(output, dash)
else
insert(output, "–")
end
insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date"))
elseif cur_month and cur_month ~= beg_month then
local month_ins = monthobj and format_annotated_text(monthobj) or cur_month
-- Same year but different months; insert current month and (if available) current day.
if cur_day then
insert(output, dash)
if year_last then
insert(output, cur_day .. " " .. month_ins)
else
insert(output, month_ins .. " " .. cur_day)
end
else
if beg_day then
insert(output, dash)
else
insert(output, "–")
end
insert(output, month_ins)
end
elseif cur_day and cur_day ~= beg_day then
-- Same year and month but different days; insert current day.
insert(output, "–")
insert(output, cur_day)
else
-- Same year, month and day; or same year and month, and day not available; or same year, and month and
-- day not available. Do nothing. FIXME: Should we throw an error?
end
if year_last and beg_year == cur_year then
if cur_month then
insert(output, " " .. cur_year)
else
insert(output, " " .. cur_year)
end
end
elseif date or yearobj then
insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date"))
elseif not maintenance_line_no_date then
-- Not main quote date. Return nil, caller will handle.
return nil, nil
elseif not getp("nodate") then
local accessdate = getp("accessdate")
if accessdate then
local explicit_day_given = date_has_day_specified(accessdate, "accessdate")
insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)")
else
if mw.title.getCurrentTitle().namespace ~= 10 then
return maintenance_line(maintenance_line_no_date), true
end
return nil, nil
end
end
return ine(concat(output)), nil
end
local function tag_with_cite(txt)
return "<cite>" .. txt .. "</cite>"
end
-- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this
-- module (formerly contained in {{quote-meta/source}}).
function export.source(args, alias_map, format_as_cite, other_controls)
local tracking_categories = {}
local argslang = args[1] or args.lang
if not argslang then
-- For the moment, only trigger an error on mainspace pages and
-- other pages that are not user pages or pages containing discussions.
-- These are the same pages that appear in the appropriate tracking
-- categories. User and discussion pages have not generally been
-- fixed up to include a language code and so it's more helpful
-- to use a maintenance line than signal an error.
local current_title = mw.title.getCurrentTitle()
if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then
require(languages_error_module)(nil, 1)
end
end
-- Given a canonical param, convert it to the original parameter specified by the user (which may have been an
-- alias).
local function alias(param)
return alias_map[param] or param
end
local output, sep = {}
local overrides = other_controls and other_controls.overrides or {}
-- Add text to the output. The text goes into a list, and we concatenate all the list components together at the
-- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that
-- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and
-- there's no title and no URL, then the first time we add anything after the title, we don't want to add a
-- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or
-- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator
-- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting
-- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text.
local function add(text)
if sep then
insert(output, sep)
end
insert(output, text)
sep = nil
end
local function add_with_sep(text, next_sep)
add(text)
sep = next_sep or ", "
end
-- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient.
-- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last").
-- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=,
-- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.).
local function make_get_full_paramname(ind)
return function(param)
return param .. ind
end
end
-- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above).
-- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have
-- wrapper functions that access params and define them only once.
local get_full_paramname
-- Return two values: the value of a parameter given the base param name (which may have a numeric index added),
-- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch
-- the parameter value from args[] given this name). The base parameter can be a list of such base params, which
-- are checked in turn, or nil, in which case nil is returned.
local function a_with_name(param)
if not param then
return nil
elseif type(param) ~= "table" then
local fullname = get_full_paramname(param)
return args[fullname], alias(fullname)
end
for _, par in ipairs(param) do
local val, fullname = a_with_name(par)
if val then
return val, alias(fullname)
end
end
return nil
end
-- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base
-- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned.
local function a(param)
return (a_with_name(param))
end
-- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's.
local function aurl_with_name(param)
local value, fullname = a_with_name(param)
if value and value:find(" ") and not value:find("%[") then
error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value))
end
return value, fullname
end
-- Identical to a(param) except that it verifies that no space is present. Should be used for URL's.
local function aurl(param)
return (aurl_with_name(param))
end
-- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have
-- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string.
-- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second
-- return value.
local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local obj = parse_annotated_text(val, fullname)
return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname
end
-- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have
-- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string.
-- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see
-- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g.
-- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss.
local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func)
return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func))
end
-- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may
-- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a
-- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two
-- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in
-- format_multivalued_annotated_text().
local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local objs = parse_multivalued_annotated_text(val, fullname)
local num_objs = objs and #objs or 0
return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs
end
-- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may
-- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a
-- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in
-- format_multivalued_annotated_text().
local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func)
return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func))
end
-- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by
-- Mary Bloggs" (if there's an author preceding).
local author_outputted = false
-- When formatting as a citation, the priority is to display a name and a date before the book/chapter title
-- this tracks whether or not the author/date has been displayed
local date_outputted, formatted_date, formatted_origdate, need_date = false
local function add_date(no_paren)
if not date_outputted then
if no_paren then
sep = ", "
else
sep = " "
end
if formatted_date then
if no_paren then
add(formatted_date)
else
add("(" .. formatted_date .. ")")
end
end
if formatted_origdate then
add(SPACE_LBRAC .. formatted_origdate .. RBRAC)
end
sep = ", "
date_outputted = true
end
end
local function is_anonymous(val)
return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$")
end
-- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split
-- among various parameters):
-- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is
-- the full parameter name holding that value;
-- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and
-- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter);
-- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`,
-- and `authorlink_fullname` is the full parameter name holding that value;
-- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of
-- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such
-- parameter);
-- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full
-- parameter name holding that value;
-- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name
-- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for
-- no such parameter);
-- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full
-- parameter name holding that value;
-- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name
-- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for
-- no such parameter).
-- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first"
local function add_author(
author,
author_fullname,
trans_author,
trans_author_fullname,
authorlink,
authorlink_fullname,
trans_authorlink,
trans_authorlink_fullname,
first,
first_fullname,
trans_first,
trans_first_fullname,
last,
last_fullname,
trans_last,
trans_last_fullname,
last_first
)
local function make_author_with_url(txt, txtparam, authorlink, authorlink_param)
if authorlink then
if authorlink:find("%[%[") then
error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink))
end
if txt:find("%[%[") then
error(("Can't specify links in %s=%s"):format(txtparam, txt))
end
return "[[w:" .. authorlink .. "|" .. txt .. "]]"
else
return txt
end
end
local num_authorobjs
if author then
local authorobjs =
parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname)
num_authorobjs = #authorobjs
if num_authorobjs == 1 then
if is_anonymous(authorobjs[1].text) then
authorobjs[1].text = "di-kilalang may-akda"
authorobjs[1].link = "anonymous author"
end
if authorlink then
authorobjs[1].text = make_author_with_url(
authorobjs[1].text,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
authorobjs[1].link = make_author_with_url(
authorobjs[1].link,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
end
if authorobjs[1].gloss and trans_authorlink then
authorobjs[1].gloss = make_author_with_url(
authorobjs[1].gloss,
("<t:...> in |%s"):format(author_fullname),
trans_authorlink,
"|" .. trans_author_fullname
)
end
add(format_multivalued_annotated_text(authorobjs))
elseif trans_authorlink then
error(
(
"Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the "
.. "<t:...> inline modifier attached to the individual entities and put the link directly "
.. "in the value of the inline modifier"
):format(trans_authorlink_fullname, author_fullname)
)
else
-- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills
-- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it
-- all.
local formatted_text = format_multivalued_annotated_text(authorobjs)
if authorlink then
formatted_text = make_author_with_url(
formatted_text,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
end
add(formatted_text)
end
else
num_authorobjs = 1
-- Author separated into first name + last name. We don't currently support non-Latin-script
-- authors separated this way and probably never will.
if first then
if last_first then
author = last .. ", " .. first
else
author = first .. " " .. last
end
else
author = last
end
if authorlink then
local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname
author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname)
end
local trans_author
if trans_last then
if trans_first then
trans_author = trans_first .. " " .. trans_last
else
trans_author = trans_last
end
if trans_authorlink then
local trans_authorparam = trans_first
and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname)
or "|" .. trans_last_fullname
trans_author = make_author_with_url(
trans_author,
trans_authorparam,
trans_authorlink,
trans_authorlink_fullname
)
end
end
add(author)
if trans_author then
add(SPACE_LBRAC)
add(trans_author)
add(RBRAC)
end
end
author_outputted = true
return num_authorobjs
end
local function add_authorlike(
param,
prefix_with_preceding_authors,
suffix_without_preceding_authors,
suffix_if_multiple,
anonymous_suffix
)
local delimiter = author_outputted and "at" or ", "
local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter)
if not entities then
return
end
if is_anonymous(entities) then
-- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific
-- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix.
if not anonymous_suffix then
local cleaned_suffix = suffix_without_preceding_authors
:gsub(" ", " ")
:gsub(" ", " ")
:gsub(" ", " ")
:gsub("[", "[")
:gsub("]", "]")
cleaned_suffix = mw.text.trim(cleaned_suffix)
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$")
end
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$")
end
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$")
end
if not anonymous_suffix then
anonymous_suffix = suffix_without_preceding_authors
end
end
add_with_sep("anonymous" .. anonymous_suffix)
elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then
add_with_sep(prefix_with_preceding_authors .. entities)
elseif suffix_if_multiple and num_entities > 1 then
add_with_sep(entities .. suffix_if_multiple)
else
add_with_sep(entities .. suffix_without_preceding_authors)
end
author_outputted = true
end
local function add_authorlabel()
local default_authorlabel = a("default-authorlabel")
if default_authorlabel and yesno(a("authorlabel"), true) then
sep = nil
add_with_sep(" " .. default_authorlabel)
end
end
local function has_new_title_or_author()
return args["2ndauthor"]
or args["2ndlast"]
or args.chapter2
or args.title2
or args.tlr2
or args.mainauthor2
or args.editor2
or args.editors2
or args.compiler2
or args.compilers2
or args.director2
or args.directors2
end
local function has_newversion()
return args.newversion or args.location2 or has_new_title_or_author()
end
-- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or
-- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for
-- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with
-- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"):
-- * chapterurl=: URL of the chapter.
-- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>).
-- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=).
-- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added.
-- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series).
-- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=).
--
-- Returns nil if no value specified for the main parameter, otherwise the formatted value.
local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix)
local chap, chap_fullname = a_with_name(param)
local chap_num, chap_num_fullname = a_with_name(param .. "_number")
local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain")
if chap_num and chap_plain then
error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname))
end
local chap_series, chap_series_fullname =
parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite)
local chap_seriesvolume, chap_seriesvolume_fullname =
parse_and_format_annotated_text_with_name(param .. "_seriesvolume")
if chap_series then
chap_series = ", " .. chap_series
end
if chap_seriesvolume then
if not chap_series then
error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname))
end
chap_series = chap_series .. " (" .. chap_seriesvolume .. ")"
end
local chapterurl
local function make_chapter_with_url(chap)
if chapterurl then
return "[" .. chapterurl .. " " .. chap .. "]"
else
return chap
end
end
if not chap then
if chap_num then
error(
("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format(
chap_num_fullname,
chap_fullname,
chap_fullname
)
)
end
if chap_plain then
chapterurl = aurl(param .. "url")
return make_chapter_with_url(chap_plain .. (chap_series or ""))
end
return nil
end
local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "")
chapterurl = aurl(param .. "url")
local formatted
if numeric_prefix and get_number(cleaned_chap) then
-- Arabic chapter number
formatted = numeric_prefix .. make_chapter_with_url(chap)
elseif
numeric_prefix
and cleaned_chap:match("^[mdclxviMDCLXVI]+$")
and roman_to_arabic(cleaned_chap, true)
and (not overrides[param] or not overrides[param].noroman)
then
-- Roman chapter number
formatted = numeric_prefix .. make_chapter_with_url(upper(chap))
else
-- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill")
if chap:find("^!") then
chap = chap:gsub("^!", "")
end
-- Must be a chapter name
local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param))
chapterobj.text = make_chapter_with_url(chapterobj.text)
chapterobj.link = make_chapter_with_url(chapterobj.link)
formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "")
end
if chap_num or chap_plain then
-- NOTE: Up above we throw an error if both chap_num and chap_plain are specified.
formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")"
end
if chap_series then
formatted = formatted .. chap_series
end
return formatted
end
-- This handles everything after displaying the author, starting with the chapter and ending with page, column,
-- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to
-- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a
-- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value.
local function postauthor(ind, num_authors, format_as_cite)
get_full_paramname = make_get_full_paramname(ind)
if author_outputted then
add_authorlabel()
end
local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at")
if coauthors then
local with_prefix = ""
if author_outputted then
with_prefix = "kasama si "
if num_authors == 1 then
sep = " "
end
end
add_with_sep(with_prefix .. coauthors)
author_outputted = true
end
add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit")
if format_as_cite and author_outputted and not date_outputted then
add_date()
sep = ", "
end
add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
local function add_sg_and_pl_authorlike(noun, verbed)
local sgparam = noun
local plparam = noun .. "s"
local sgval, sgval_fullname = a_with_name(sgparam)
local plval, plval_fullname = a_with_name(plparam)
if sgval and plval then
error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname))
end
if sgval or plval then
local verbed_by = verbed .. " ni "
local comma_sgnoun = ", " .. noun
local comma_plnoun = ", " .. noun .. "s"
add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun)
add_authorlike(plparam, verbed_by, comma_plnoun)
end
end
local formatted_entry = format_chapterlike("entry", nil, "“", "”")
local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”")
local function add_entry()
if formatted_entry then
add_with_sep(formatted_entry)
if not a("notitle") then
add("sa ") -- tl change: in
author_outputted = false
else
author_outputted = true
end
formatted_entry = nil
end
end
local function add_chapter()
add_entry()
if formatted_chapter then
add_with_sep(formatted_chapter)
if not a("notitle") then
add("sa ")
author_outputted = false
end
formatted_chapter = nil
end
end
local function add_actor_role(format_as_cite)
local role = parse_and_format_multivalued_annotated_text("role", "at")
local actor_val, actor_fullname = a_with_name("actor")
local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname)
local actor = format_multivalued_annotated_text(actor_objs, "at")
if format_as_cite then
if role then
if actor then
add_with_sep(actor .. " bilang ")
end
sep = nil
add_with_sep(role)
elseif actor then
add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")")
end
else
if role then
add_with_sep("sinalita ni " .. role)
if actor then
sep = nil
add_with_sep(" (" .. actor .. ")")
end
elseif actor then
add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")")
end
end
end
if format_as_cite then
if date_outputted then
add_chapter()
end
local output_len = #output
local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor")
if mainauthor then
add_with_sep(mainauthor)
end
-- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag
author_outputted = false
add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
author_outputted = false
add_sg_and_pl_authorlike("editor", "patnugot ni")
add_sg_and_pl_authorlike("compiler", "kinompila ni")
add_sg_and_pl_authorlike("director", "direksiyon ni")
add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat")
add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik")
add_authorlike("composer", nil, " (musika)", nil, " kompositor")
add_actor_role("format_as_cite")
-- if the output length has changed, a credit name has been printed
-- and we can print the date
if output_len ~= #output then
author_outputted = true
add_date()
end
add_chapter()
else
add_chapter()
local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor")
if mainauthor then
add_with_sep(mainauthor)
author_outputted = true
end
add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
add_sg_and_pl_authorlike("editor", "patnugot ni")
add_sg_and_pl_authorlike("compiler", "kinompila ni")
add_sg_and_pl_authorlike("director", "direksiyon ni")
add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat")
add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik")
add_authorlike("composer", nil, " (musika)", nil, " kompositor")
end
local title, title_fullname = a_with_name("title")
local need_comma = false
if title then
local titleobj = parse_annotated_text(title, title_fullname, a("trans-title"))
add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite))
local series = parse_and_format_annotated_text("series")
if series then
add(" (" .. series)
local seriesvolume = parse_and_format_annotated_text("seriesvolume")
if seriesvolume then
add(SEMICOLON_SPACE .. seriesvolume)
end
add(")")
end
need_comma = true
elseif ind == "" then
if not a("notitle") then
add(maintenance_line("Please provide the book title or journal name"))
need_comma = true
end
end
local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl")
local url, url_fullname = aurl_with_name("url")
local urls, urls_fullname = aurl_with_name("urls")
if url and urls then
error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname))
end
local function verify_title_supplied(url_name)
-- There are too many cases of this to throw an error at this time.
-- if not title then
-- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname))
-- end
end
if archiveurl or url then
verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname)
sep = nil
add("‎<sup>[" .. (archiveurl or url) .. "]</sup>")
elseif urls then
verify_title_supplied(urls_fullname)
sep = nil
add("‎<sup>" .. urls .. "</sup>")
end
-- display (in Language) if language is provided and is not English and not overriden by termlang or worklang
if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then
local lang = get_first_lang(args[1] or args.lang)
if lang then
local langcode = lang:getCode()
if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog
local langs = format_langs(args[1] or args.lang)
if langs then
add(" (sa wikang " .. langs .. ")")
end
end
end
end
if need_comma then
sep = ", "
end
local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition")
local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain")
if edition and edition_plain then
error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname))
end
if edition then
add_with_sep("ika-" .. edition .. " labas")
end
if edition_plain then
add_with_sep(edition_plain)
end
-- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually
-- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized
-- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if
-- ind == "2"). Only one of the first three can be specified; an error results if more than one are given.
-- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly
-- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a
-- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed
-- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page ").
-- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is
-- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case
-- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers
-- (including with optional inline modifiers), and such text is handled appropriately.
local function format_numeric_param(paramname, singular_desc)
local sgval = a_with_name(paramname)
local sgobj = parse_annotated_text(sgval, paramname)
local plparamname = paramname .. "s"
local plval = a_with_name(plparamname)
local plobj = parse_annotated_text(plval, plparamname)
local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain")
local numspec
if not sgval and not plval and not plainval then
return
elseif plainval and (sgval or plval) then
error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname))
elseif sgval and plval then
-- if both singular and plural, display "page 1 of 1-10"
numspec = singular_desc .. " " .. sgval .. " of " .. plval
else
-- Merge page= and pages= and treat alike because people often mix them up in both directions.
if plainval then
numspec = plainval
else
local val = sgobj and sgobj.text or plobj.text
if val == "unnumbered" then
numspec = "unnumbered " .. singular_desc
else
local desc
if val:find("^!") then
val = val:gsub("^!", "")
desc = sgval and singular_desc or pluralize(singular_desc)
else
local check_val = val
if check_val:find("%[") then
check_val = remove_links(check_val)
-- convert URL's of the form [URL DISPLAY] to the displayed value
check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1")
end
-- in case of negative page numbers (do they exist?), don't treat as multiple pages
check_val = check_val:gsub("^%-", "")
-- replace HTML entity en-dashes and em-dashes with their literal codes
check_val = check_val:gsub("–", "–")
check_val = check_val:gsub("–", "–")
check_val = check_val:gsub("—", "—")
check_val = check_val:gsub("—", "—")
-- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b)
-- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators).
if
umatch(check_val, "[–—]")
or check_val:find(" and ")
or check_val:match("%d+[^ ]* *%- *%d+")
or check_val:match("%d+[^ ]* *, +%d+")
then
desc = pluralize(singular_desc)
else
desc = singular_desc
end
end
local obj = sgobj or plobj
obj.text = val
if obj.link:find("^!") then
obj.link = obj.link:gsub("^!", "")
end
val = format_annotated_text(obj)
numspec = desc .. " " .. val
end
end
end
local url = a(paramname .. "url")
if url then
return "[" .. url .. " " .. numspec .. "]"
else
return numspec
end
end
local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum")
if volume then
add_with_sep(volume)
end
local issue = format_numeric_param("issue", a("issue_prefix") or "bilang")
if issue then
add_with_sep(issue)
end
-- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number)
local number = format_numeric_param("number", a("number_prefix") or "bilang")
if number then
add_with_sep(number)
end
local annotations = {}
local genre = a("genre")
if genre then
insert(annotations, genre)
end
local format = a("format")
if format then
insert(annotations, format)
end
local medium = a("medium")
if medium then
insert(annotations, medium)
end
-- Now handle the display of language annotations like "(in French)" or
-- "(quotation in Nauruan; overall work in German)".
local quotelang = args[1] or args.lang
if not quotelang then
if ind == "" then
-- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown
-- above.
insert(annotations, maintenance_line("Please specify the language of the quote using |1="))
else
-- do nothing in newversion= portion
end
elseif ind == "" then
local worklang = a("worklang")
local termlang = a("termlang")
worklang = worklang or quotelang
termlang = termlang or quotelang
if worklang == quotelang then
if worklang == termlang then
-- do nothing
else
insert(annotations, "sa wikang " .. format_langs(quotelang))
end
else
if quotelang ~= termlang then
insert(annotations, "sinipi sa wikang " .. format_langs(quotelang))
end
insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang))
end
else
local lang2 = a("lang2")
if lang2 then
insert(annotations, "sa wikang " .. format_langs(lang2))
end
end
if #annotations > 0 then
sep = nil
add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")")
end
local artist = parse_and_format_multivalued_annotated_text("artist", "at")
if artist then
add_with_sep("itinanghal ni " .. artist)
end
local feat = parse_and_format_multivalued_annotated_text("feat", "at")
if feat then
sep = " "
add_with_sep("ft. " .. feat)
end
if not format_as_cite then
add_actor_role()
end
local others = parse_and_format_annotated_text("others")
if others then
add_with_sep(others)
end
local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite)
if quoted_in then
add_with_sep("binanggit sa " .. quoted_in)
insert(tracking_categories, "Quotations using quoted-in parameter")
end
local location = parse_and_format_multivalued_annotated_text("location", "; ")
local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ")
if publisher then
if location then
add_with_sep(location) -- colon
sep = ": " -- colon
end
add_with_sep(publisher)
elseif location then
add_with_sep(location)
end
if not date_outputted then
add_date("no_paren")
end
local source = parse_and_format_multivalued_annotated_text("source", "at")
if source then
add_with_sep("nagmula sa " .. source)
end
local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite)
local by = parse_and_format_multivalued_annotated_text("by", "at")
local origtype = a("deriv") or "salin"
if original or by then
add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or ""))
end
-- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly
-- given.
local origlang = a("origlang")
local origworklang = a("origworklang")
local origlangtext, origworklangtext
if origlang then
origlangtext = "in " .. format_langs(origlang)
end
if origworklang then
origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang)
end
if origlang or origworklang then
if original or by then
local orig_annotations = {}
if origlangtext then
insert(orig_annotations, origlangtext)
end
if origworklangtext then
insert(orig_annotations, origworklangtext)
end
sep = nil
add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")")
else
add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or ""))
if origworklangtext then
sep = nil
add_with_sep(" (" .. origworklangtext .. ")")
end
end
end
if ind ~= "" and has_newversion() then
local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true)
if formatted_new_date then
add_with_sep(formatted_new_date)
end
end
-- Fetch date_published=/year_published=/month_published= and format appropriately.
local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true)
local platform = parse_and_format_multivalued_annotated_text("platform", "at")
if formatted_date_published then
add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or ""))
elseif platform then
add_with_sep("sa pamamagitan ng " .. platform)
end
-- From here on out, there should always be a preceding item, so we
-- can dispense with add_with_sep() and always insert the comma.
sep = nil
local function small(txt)
add(", <small>")
add(txt)
add("</small>")
end
-- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params`
-- is a string identifying the base param, or a list of such strings to check in turn. If found, the value
-- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()),
-- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`,
-- and running the resulting string through small(), which first adds a comma and then the URL in small font.
local function add_identifier(param_or_params, pretext, posttext, process)
local val = a(param_or_params)
if val then
val = (process or mw.uri.encode)(val)
small(pretext .. val .. posttext)
end
end
add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]")
add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>")
add_identifier("isbn", "", "", isbn)
add_identifier("issn", "", "", issn)
add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]")
add_identifier("lccn", "", "", lccn)
add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]")
add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]")
add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]")
add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]")
add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]")
-- add_identifier("urn", "", "", urn)
local id = a("id")
if id then
small(id)
end
archiveurl, archiveurl_fullname = aurl_with_name("archiveurl")
if archiveurl then
add(", archived from ")
local url, url_fullname = aurl_with_name("url")
if not url then
-- attempt to infer original URL from archive URL; this works at
-- least for Wayback Machine (web.archive.org) URL's
url = archiveurl:match("/(https?:.*)$")
if not url then
error(
("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname)
)
end
end
add("[" .. url .. " ang orihinal] sa ")
local archivedate, archivedate_fullname = a_with_name("archivedate")
if archivedate then
add(format_date(archivedate))
elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then
-- If the archive is from the Wayback Machine, then it already contains the date
-- Get the date and format it
local wayback_date = string.sub(archiveurl, 29, 29 + 7)
wayback_date = string.sub(wayback_date, 1, 4)
.. "-"
.. string.sub(wayback_date, 5, 6)
.. "-"
.. string.sub(wayback_date, 7, 8)
add(format_date(wayback_date))
elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then
local megalodon_date = string.sub(archiveurl, 22, 25)
.. "-"
.. string.sub(archiveurl, 27, 28)
.. "-"
.. string.sub(archiveurl, 29, 30)
add(format_date(megalodon_date))
else
error(
("When |%s= is specified, |%s= must also be included"):format(
archiveurl_fullname,
archivedate_fullname
)
)
end
end
if a("accessdate") then
--Otherwise do not display here, as already used as a fallback for missing date= or year= earlier.
if (a("date") or a("nodate") or a("year")) and not a("archivedate") then
add(", retrieved " .. format_date(a("accessdate")))
end
end
local formatted_section = format_chapterlike("section", "bahagi ")
if formatted_section then
add(", ")
add(formatted_section)
end
-- video game stuff
local system = parse_and_format_annotated_text("system")
if system then
add(", " .. system)
end
local scene = parse_and_format_annotated_text("scene")
if scene then
add(", eksena: " .. scene)
end
local level = parse_and_format_annotated_text("level")
if level then
add(", level/area: " .. level)
end
local note = parse_and_format_annotated_text("note")
if note then
add(", " .. note)
end
local note_plain = parse_and_format_annotated_text("note_plain")
if note_plain then
add(" " .. note_plain)
end
-- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text.
local function handle_numeric_param(paramname, singular_desc, pretext)
local numspec = format_numeric_param(paramname, singular_desc)
if numspec then
add((pretext or "") .. numspec)
end
end
handle_numeric_param("page", a("page_prefix") or "page", ", ")
handle_numeric_param("column", a("column_prefix") or "column", ", ")
handle_numeric_param("line", a("line_prefix") or "line", ", ")
-- FIXME: Does this make sense? What is other=?
local other = parse_and_format_annotated_text("other")
if other then
add(", " .. other)
end
end
local function add_authors(args, last_first)
-- Find maximum indexed author or last name.
local maxind = math.max(args.author.maxindex, args.last.maxindex)
-- Include max index of ancillary params so we get an error message about their use without the primary params.
local ancillary_params =
{"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"}
for _, ancillary in ipairs(ancillary_params) do
maxind = math.max(maxind, args[ancillary].maxindex)
end
local num_authors = 0
for i = 1, maxind do
local ind = i == 1 and "" or i
local author, last = args.author[i], args.last[i]
if author or last then
local this_num_authors = add_author(
author,
"author" .. ind,
args["trans-author"][i],
"trans-author" .. ind,
args.authorlink[i],
"authorlink" .. ind,
args["trans-authorlink"][i],
"trans-authorlink" .. ind,
args.first[i],
"first" .. ind,
args["trans-first"][i],
"trans-first" .. ind,
last,
"last" .. ind,
args["trans-last"][i],
"trans-last" .. ind,
last_first
)
num_authors = num_authors + this_num_authors
sep = last_first and "; " or ", "
else
for _, cant_have in ipairs(ancillary_params) do
if args[cant_have][i] then
error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind))
end
end
end
end
return num_authors
end
local function add_newversion()
-- If there's a "newversion" section, add the new-version text.
if has_newversion() then
sep = nil
--Test for new version of work.
add(SEMICOLON_SPACE)
if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as".
add(args.newversion)
elseif not args.edition2 then
if has_new_title_or_author() then
add("nilathala bilang")
else
add("muling nilathala")
end
end
add(" ")
return ""
else
return ", "
end
end
------------------- Now we start outputting text ----------------------
local need_comma = false
-- Set this now so a() works just below.
get_full_paramname = make_get_full_paramname("")
if args.brackets then
add("[")
end
bold_year = not format_as_cite
year_last = format_as_cite
formatted_date, need_date = format_date_args(
a,
get_full_paramname,
alias_map,
nil,
nil,
bold_year,
"Can we [[:Category:Requests for date|date]] this quote?",
year_last
)
-- Fetch origdate=/origyear=/origmonth= and format appropriately.
formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last)
local num_authors
if format_as_cite then
num_authors = add_authors(args, "last_first")
if author_outputted then
sep = " "
end
-- Display all the text that comes after the author, for the main portion.
postauthor("", num_authors, "format_as_cite")
author_outputted = false
sep = add_newversion()
-- Add the newversion author(s).
if args["2ndauthor"] or args["2ndlast"] then
num_authors = add_author(
args["2ndauthor"],
"2ndauthor",
nil,
nil,
args["2ndauthorlink"],
"2ndauthorlink",
nil,
nil,
args["2ndfirst"],
"2ndfirst",
nil,
nil,
args["2ndlast"],
"2ndlast",
nil,
nil,
"last_first"
)
sep = ", "
else
for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do
if args[cant_have] then
error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have))
end
end
end
-- Display all the text that comes after the author, for the "newversion" section.
postauthor(2, num_authors, "format_as_cite")
else
if formatted_date then
need_comma = true
add(formatted_date)
end
if formatted_origdate then
need_comma = true
add(SPACE_LBRAC .. formatted_origdate .. RBRAC)
end
if need_comma then
sep = ", "
end
date_outputted = true
num_authors = add_authors(args)
-- Display all the text that comes after the author, for the main portion.
postauthor("", num_authors)
author_outputted = false
sep = add_newversion()
-- Add the newversion author(s).
if args["2ndauthor"] or args["2ndlast"] then
num_authors = add_author(
args["2ndauthor"],
"2ndauthor",
nil,
nil,
args["2ndauthorlink"],
"2ndauthorlink",
nil,
nil,
args["2ndfirst"],
"2ndfirst",
nil,
nil,
args["2ndlast"],
"2ndlast",
nil,
nil
)
sep = ", "
else
for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do
if args[cant_have] then
error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have))
end
end
end
-- Display all the text that comes after the author, for the "newversion" section.
postauthor(2, num_authors)
end
if not args.nocolon then
sep = nil
add(":")
elseif args.usenodot and not args.nodot then
add(".")
end
-- Concatenate output portions to form output text.
local output_text = concat(output)
-- Remainder of code handles adding categories. We add one or more of the following categories:
--
-- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to
-- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace
-- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same
-- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances
-- because typically when there's no quotation to format, it's because it's formatted manually underneath the
-- citation, or using {{ja-x}}, {{th-x}} or similar.)
-- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace,
-- Reconstruction:, Appendix: and Citations: pages unless nocat= is given.
-- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:,
-- Appendix: and Citations: pages.
local categories = {}
local termlang = get_first_lang(args.termlang or argslang)
if args.nocat then
if format_as_cite then
insert(tracking_categories, "Citations using nocat parameter")
else
insert(tracking_categories, "Quotations using nocat parameter")
end
else
-- don't create language tracking categories for citations
if not format_as_cite then
local title
if args.pagename then -- for testing, doc pages, etc.
title = mw.title.new(args.pagename)
if not title then
error(("Bad value for `args.pagename`: '%s'"):format(args.pagename))
end
else
title = mw.title.getCurrentTitle()
end
-- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists.
local ok_to_add_cat
if title.nsText ~= "Citations" then
ok_to_add_cat = true
else
local mainspace_title = mw.title.new(title.text)
if mainspace_title and mainspace_title.exists then
ok_to_add_cat = true
end
end
if ok_to_add_cat then
insert(categories, termlang:getFullName() .. " terms with quotations")
end
end
if need_date then
local argslangobj = get_first_lang(argslang)
insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries")
end
end
return output_text .. (
not termlang and "" or
(#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. (
#tracking_categories > 0
and format_categories(
tracking_categories,
termlang,
args.sort,
nil,
not page_should_be_ignored(mw.title.getCurrentTitle().fullText)
)
or ""
)
)
end
-- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical
-- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2"
-- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should
-- process this spec if type2= is being handled.
local type_alias_specs = {
av = {
{"author", "writer,writers", true},
{"chapter", "episode", true},
{"chapterurl", "episodeurl", true},
{"trans-chapter", "trans-episode", true},
{"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true},
{"chapter_series", "episode_series", true},
{"chapter_seriesvolume", "episode_seriesvolume", true},
{"chapter_number", "episode_number", true},
{"chapter_plain", "episode_plain", true},
{"volume", "season", true},
{"volumes", "seasons", true},
{"volume_plain", "season_plain", true},
{"volumeurl", "seasonurl", true},
{"platform", "network", true},
},
book = {
{"author", "3"},
{"title", "4"},
{"url", "5"},
{"year", "2"},
{"page", "6"},
{"text", "7"},
{"t", "8"},
},
journal = {
{"year", "2"},
{"author", "3"},
{"chapter", "title,article,4", true},
{"chapterurl", "titleurl,articleurl", true},
{"trans-chapter", "trans-title,trans-article", true},
{"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true},
{"chapter_series", "title_series,article_series", true},
{"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true},
{"chapter_number", "title_number,article_number", true},
{"chapter_plain", "title_plain,article_plain", true},
{"title", "journal,magazine,newspaper,work,5", true},
{"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true},
{"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true},
{"url", "6,journalurl,magazineurl,newspaperurl,workurl", true},
{"page", "7"},
{"source", "newsagency,news_agency", true},
{"text", "8"},
{"t", "9"},
},
}
-- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of
-- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings
-- seen.
local function process_type_aliases(args, typ, newversion, alias_map)
local ind = newversion and "2" or ""
local deprecated = ine(args.lang)
if not type_alias_specs[typ] then
local possible_values = {}
for possible, _ in pairs(type_alias_specs) do
insert(possible_values, possible)
end
sort(possible_values)
error(
("Unrecognized value '%s' for type%s=; possible values are %s"):format(
typ,
ind,
concat(possible_values, ",")
)
)
end
for _, alias_spec in ipairs(type_alias_specs[typ]) do
local canon, aliases, with_newversion = unpack(alias_spec)
if with_newversion or not newversion then
canon = canon .. ind
aliases = split(aliases, ",", true)
local saw_alias = nil
for _, alias in ipairs(aliases) do
if alias:match("^%d+$") then
alias = tonumber(alias)
if deprecated then
alias = alias - 1
end
else
alias = alias .. ind
end
if args[alias] then
if saw_alias == nil then
saw_alias = alias
else
error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias))
end
end
end
if saw_alias and (not newversion or type(saw_alias) == "string") then
if args[canon] then
error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon))
end
args[canon] = args[saw_alias]
-- Wipe out the original after copying. This is important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_alias] = nil
alias_map[canon] = saw_alias
end
end
end
end
-- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores.
local function clone_args(direct_args, parent_args)
local args = {}
-- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is
-- specified but is blank, it will still override the parent arg (with nil).
for pname, param in pairs(parent_args) do
-- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]]
track("param/" .. pname)
args[pname] = ine(param)
end
-- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to
-- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and
-- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias
-- processing, saying that title= and its alias album= are both present.
local ignores = ine(direct_args.ignore)
if ignores then
for ignore in gsplit(ignores, "%s*,%s*") do
args[ignore] = nil
end
end
local alias_map = {}
local other_controls = {}
-- noroman
local noroman = ine(direct_args.noroman)
if noroman then
other_controls.overrides = other_controls.overrides or {}
for param in gsplit(noroman, "%s*,%s*") do
other_controls.overrides[param] = (other_controls.overrides[param] or {})
other_controls.overrides[param].noroman = true
end
end
-- Process internally-specified aliases using type= or type2=.
local typ = args.type or direct_args.type
if typ then
process_type_aliases(args, typ, false, alias_map)
end
local typ2 = args.type2 or direct_args.type2
if typ2 then
process_type_aliases(args, typ2, true, alias_map)
end
-- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which
-- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an
-- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for
-- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or
-- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias
-- must be specified before the journal/work -> title alias.
--
-- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so
-- that when we would display an error message about DEST, we display SOURCE instead.
--
-- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up
-- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does
-- this).
--
-- FIXME: Delete this once we've converted all alias processing to internal.
local aliases = ine(direct_args.alias)
if aliases then
-- Allow and discard a trailing semicolon, to make managing multiple aliases easier.
aliases = ugsub(aliases, "%s*;$", "")
for alias_spec in gsplit(aliases, "%s*;%s*") do
local alias_spec_parts = split(alias_spec, "%s*:%s*")
if #alias_spec_parts ~= 2 then
error(("Alias spec '%s' should have one colon in it"):format(alias_spec))
end
local dest, sources = unpack(alias_spec_parts)
sources = split(sources, "%s*,%s*")
local saw_source = nil
for _, source in ipairs(sources) do
if source:match("^%d+$") then
source = tonumber(source)
end
if args[source] then
if saw_source == nil then
saw_source = source
else
error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source))
end
end
end
if saw_source then
if args[dest] then
error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest))
end
args[dest] = args[saw_source]
-- Wipe out the original after copying. This important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_source] = nil
alias_map[dest] = saw_source
end
end
end
-- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen
-- in parent_args (they are params we overwrite in the direct args).
local error_ifs = ine(direct_args.error_if)
if error_ifs then
for error_if in gsplit(error_ifs, "%s*,%s*") do
if ine(parent_args[error_if]) then
error(
("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format(
error_if,
ine(parent_args[error_if])
)
)
end
end
end
for pname, param in pairs(direct_args) do
-- ignore control params
if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then
args[pname] = ine(param)
end
end
return args, alias_map, other_controls
end
local function get_args(frame_args, parent_args, require_lang)
-- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is
-- wasteful of memory.
local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args)
local deprecated = ine(parent_args.lang)
local alias_of_t = {alias_of = "t"}
local boolean = {type = "boolean"}
local language_sublist = {type = "language", sublist = true}
local list_allow_holes = {list = true, allow_holes = true}
local script = {type = "script"}
-- First, the "single" params that don't have FOO2 or FOOn versions.
local params = {
[deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"},
["lang2"] = language_sublist,
["newversion"] = true,
["author"] = list_allow_holes,
["2ndauthor"] = true,
["trans-author"] = list_allow_holes,
["authorlink"] = list_allow_holes,
["2ndauthorlink"] = true,
["trans-authorlink"] = list_allow_holes,
["first"] = list_allow_holes,
["2ndfirst"] = true,
["trans-first"] = list_allow_holes,
["last"] = list_allow_holes,
["2ndlast"] = true,
["trans-last"] = list_allow_holes,
["nocat"] = boolean,
["nocolon"] = boolean,
-- quote params
text = true,
passage = {alias_of = "text"},
tr = true,
transliteration = {alias_of = "tr"},
ts = true,
transcription = {alias_of = "ts"},
norm = true,
normalization = {alias_of = "norm"},
sc = script,
normsc = script,
sort = true,
subst = true,
footer = true,
lit = true,
t = true,
translation = alias_of_t,
gloss = alias_of_t,
lb = true,
brackets = boolean,
-- original quote params
origtext = true,
origtr = true,
origts = true,
orignorm = true,
origsc = script,
orignormsc = script,
origsubst = true,
origlb = true,
usenodot = boolean,
nodot = boolean,
inline = boolean,
asquote = boolean,
ascite = boolean,
}
-- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to
-- allow PARAMN variants for any N.
local function add_with_2(param, value)
params[param] = value
params[param .. "2"] = value
end
local function alias_with_2(alias, canon)
params[alias] = {alias_of = canon}
params[alias .. "2"] = {alias_of = canon .. "2"}
end
for _, param12 in ipairs{
"worklang",
"termlang",
"origlang",
"origworklang"
} do
add_with_2(param12, language_sublist)
end
-- Then the newversion params (which have FOO2 versions).
for _, param12 in ipairs{
-- author-like params; author params themselves are either list params (author=, last=, etc.) or single params
-- (2ndauthor=, 2ndlast=, etc.)
"coauthors",
"quotee",
"tlr",
"editor",
"editors",
"mainauthor",
"compiler",
"compilers",
"director",
"directors",
"lyricist",
"lyrics-translator",
"composer",
"role",
"actor",
"artist",
"feat",
-- author control params
"default-authorlabel",
"authorlabel",
-- title
"title",
"trans-title",
"series",
"seriesvolume",
"notitle",
-- entry
"entry",
"entryurl",
"trans-entry",
-- chapter
"chapter",
"chapterurl",
"chapter_number",
"chapter_plain",
"chapter_series",
"chapter_seriesvolume",
"trans-chapter",
"chapter_tlr",
-- section
"section",
"sectionurl",
"section_number",
"section_plain",
"section_series",
"section_seriesvolume",
"trans-section",
-- other video-game params
"system",
"scene",
"level",
-- URL
"url",
"urls",
"archiveurl",
-- edition
"edition",
"edition_plain",
-- ID params
"bibcode",
"doi",
"isbn",
"issn",
"jstor",
"lccn",
"oclc",
"ol",
"pmid",
"pmcid",
"ssrn",
"urn",
"id",
-- misc date params; most date params handled below
"archivedate",
"accessdate",
"nodate",
-- numeric params handled below
-- other params
"type",
"genre",
"format",
"medium",
"others",
"quoted_in",
"location",
"publisher",
"original",
"by",
"deriv",
"note",
"note_plain",
"other",
"source",
"platform",
} do
add_with_2(param12, true)
end
-- Then the aliases of newversion params (which have FOO2 versions).
for _, param12_aliased in ipairs{
{"role", "roles"},
{"role", "speaker"},
{"tlr", "tlrs"},
{"tlr", "translator"},
{"tlr", "translators"},
{"chapter_tlr", "chapter_tlrs"},
{"chapter_tlr", "chapter_translator"},
{"chapter_tlr", "chapter_translators"},
{"doi", "DOI"},
{"isbn", "ISBN"},
{"issn", "ISSN"},
{"jstor", "JSTOR"},
{"lccn", "LCCN"},
{"oclc", "OCLC"},
{"ol", "OL"},
{"pmid", "PMID"},
{"pmcid", "PMCID"},
{"ssrn", "SSRN"},
{"urn", "URN"},
} do
local canon, alias = unpack(param12_aliased)
alias_with_2(alias, canon)
end
-- Then the date params.
for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do
local pref, suf = unpack(datelike)
for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do
add_with_2(pref .. arg .. suf, true)
end
end
local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"}
-- Then the numeric params.
for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do
for _, suf in ipairs(numeric_param_suffixes) do
add_with_2(numeric .. suf, true)
end
end
-- And the aliases of numeric params.
for _, numeric_aliased in ipairs{{"volume", "vol"}} do
local canon, alias = unpack(numeric_aliased)
for _, suf in ipairs(numeric_param_suffixes) do
alias_with_2(alias .. suf, canon .. suf)
end
end
return process_params(cloned_args, params), alias_map, other_controls
end
local function get_origtext_params(args)
local origtext, origtextlang, origsc, orignormsc
if args.origtext then
-- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or
-- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology
-- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been
-- eliminated.)
origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$")
if not origtextlang then
-- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL.
origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$")
end
if not origtextlang then
error("origtext= should begin with a language code prefix")
end
origtextlang = get_lang(origtextlang, nil, "allow etym") or
error("origtext= should begin with a language code prefix")
origsc = args.origsc
orignormsc = args.orignormsc
else
for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do
if args[noparam] then
error(("Cannot specify %s= without origtext="):format(noparam))
end
end
end
return origtext, origtextlang, origsc, orignormsc
end
local function get_quote(args, is_cite)
local text = args.text
local gloss = args.t
local tr = args.tr
local ts = args.ts
local norm = args.norm
local sc = args.sc
local normsc = args.normsc
-- Fetch original-text parameters.
local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args)
-- If any quote-related args are present, display the actual quote; otherwise, display nothing.
if text or gloss or tr or ts or norm or args.origtext then
-- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages
-- in any case in source() if the language is omitted.
local lang = get_first_lang(args[1] or args.lang)
local termlang = args.termlang and get_first_lang(args.termlang) or lang
local usex_data = {
lang = lang,
termlang = termlang,
usex = text,
sc = sc,
translation = gloss,
normalization = norm,
normsc = normsc,
transliteration = tr,
transcription = ts,
brackets = args.brackets,
subst = args.subst,
lit = args.lit,
footer = args.footer,
qq = parse_and_format_labels(args.lb, lang),
quote = "quote-meta",
orig = origtext,
origlang = origtextlang,
origsc = origsc,
orignorm = args.orignorm,
orignormsc = orignormsc,
origtr = args.origtr,
origts = args.origts,
origsubst = args.origsubst,
origqq = parse_and_format_labels(args.origlb, lang),
noreq = args.noreq,
nocat = is_cite or args.nocat,
}
if args.inline then
-- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text
usex_data.footer = nil
usex_data.inline = 1
text = format_usex(usex_data)
if text then
text = " “" .. text .. "”"
else
text = ""
end
if args.footer then
text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>"
end
else
text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>"
end
elseif args.footer then
text = "<dl><dd>" .. args.footer .. "</dd></dl>"
end
return text
end
-- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary
-- interface for {{quote-*}} templates.
function export.quote_t(frame)
local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang")
if args.ascite then
return export.cite_t(frame)
end
return show_quote(args, alias_map, other_controls)
end
function show_quote(args, alias_map, other_controls)
local parts = {}
insert(parts, '<div class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, nil, other_controls))
insert(parts, "</span>")
insert(parts, get_quote(args))
insert(parts, "</div>")
local retval = concat(parts)
return deprecated and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
}) or retval
end
-- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary
-- interface for {{cite-*}} templates.
function export.cite_t(frame)
local parent_args = {}
for k, v in pairs(frame:getParent().args) do
parent_args[k] = v
end
-- use "und" as lang if none provided
if parent_args[1] == nil then
parent_args[1] = "und"
end
local args, alias_map, other_controls = get_args(frame.args, parent_args)
if args.asquote then
return show_quote(args, alias_map, other_controls)
end
return show_cite(args, alias_map, other_controls)
end
function show_cite(args, alias_map, other_controls)
local parts = {}
-- don't nag for translations
if args.text and not args.t then
args.noreq = 1
end
local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0
if len_visible == 0 then
if not args.t or args.t == "-" then
args.nocolon = true
end
elseif args.inline == nil then
args.inline = not (
args.block_text
or len_visible > 300
or (args.t and not args.t == "-" and len_visible < 80)
or string.match(args.text, "<br>")
)
end
insert(parts, '<span class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, "format_as_cite", other_controls))
insert(parts, "</span>")
insert(parts, get_quote(args, "is_cite"))
insert(parts, "</span>")
local retval = concat(parts)
return deprecated
and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
})
or retval
end
-- External interface, meant to be called from a template.
function export.call_quote_template(frame)
return export.call_template(frame)
end
-- External interface, for calling a template with overloaded parameters.
function export.overload(frame)
local iargs, overloaded_args = process_params(frame.args, {
[1] = {required = true}
}, true)
local parent_args = frame:getParent().args
for k, v in pairs(parent_args) do
overloaded_args[k] = v
end
return frame:expandTemplate{title = iargs[1], args = overloaded_args}
end
-- External interface, meant to be called from a template.
function export.call_template(frame)
local parameter_sublist = {type = "parameter", sublist = true}
local iargs, other_direct_args = process_params(frame.args, {
["template"] = true,
["textparam"] = parameter_sublist,
["pageparam"] = parameter_sublist,
["propagateparams"] = parameter_sublist,
["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently.
}, true)
local function fetch_param(source, params)
for _, param in ipairs(params) do
if source[param] then
return source[param]
end
end
return nil
end
local params = {
["text"] = true,
["passage"] = true,
["footer"] = true, -- always propagates, but gets special formatting
}
-- paramaters that can be used during template declaration or included in template calls
-- if the template is called with param=- it will set any declared value to nil
local always_propagate = {
["brackets"] = true,
["usenodot"] = true,
["nodot"] = true,
["ascite"] = true,
["asquote"] = true,
}
for k,v in pairs(always_propagate) do
params[k] = v
end
local textparam = iargs.textparam or {}
for _, param in ipairs(textparam) do
params[param] = true
end
local pageparam = iargs.pageparam or {}
local pageparam1 = pageparam[1]
if pageparam1 ~= nil then
params["page"], params["pages"] = true, true
for _, param in ipairs(pageparam) do
params[param] = true
end
end
local allowparams, allow_all, list = iargs.allowparams, false
if allowparams ~= nil then
for _, allow in ipairs(allowparams) do
local param = allow:match("^(.*):list$")
if param then
if list == nil then
list = {list = true}
end
params[scribunto_parameter_key(param)] = list
elseif allow == "*" then
track("no parameter checking")
allow_all = true
else
params[scribunto_parameter_key(allow)] = true
end
end
else
local parent = frame:getParent()
local template_name = parent:getTitle()
local template_title = new_title(template_name)
local content = template_title:getContent()
local allowed_params, seen = {}, {}
-- Detect all params used by the parent template. param:get_name() takes the
-- parent frame arg table as an argument so that preprocessing will take
-- them into account, since it will matter if the name contains another
-- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change
-- depending on the value for bar=). `seen` memoizes results based on the
-- raw parameter text (which is stored as a string in the parameter object),
-- which avoids unnecessary param:get_name() calls, which are non-trivial.
for param in find_parameters(content) do
local raw = param.raw
if not seen[raw] then
allow = param:get_name(template_args)
params[scribunto_parameter_key(allow)] = true
seen[raw] = true
end
end
end
local propagateparams = iargs.propagateparams or {}
for _, param in ipairs(propagateparams) do
params[param] = true
end
local parent_args = frame:getParent().args
local args = process_params(parent_args, params, allow_all)
parent_args = shallow_copy(parent_args)
if textparam[1] ~= "-" then
other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam)
end
if not (pageparam1 == nil or pageparam1 == "-") then
other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil
other_direct_args.pages = args.pages or other_direct_args.pages or nil
if other_direct_args.page == "-" then
other_direct_args.page = nil
end
if other_direct_args.pages == "-" then
other_direct_args.pages = nil
end
end
if args.footer then
other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}}
end
for param, _ in pairs(always_propagate) do
if args[param] == "-" then
other_direct_args[param] = nil
else
other_direct_args[param] = args[param] or other_direct_args[param] or nil
end
end
-- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to
-- the actual {{quote-*}} code.
if other_direct_args.authorlink == "-" then
other_direct_args.authorlink = nil
end
for _, param in ipairs(propagateparams) do
if args[param] then
other_direct_args[param] = args[param]
end
end
return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args}
end
local paramdoc_param_replacements = {
passage = {
param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}",
param_no_synonym = "{{para|text}} or {{para|passage}}",
text = [=[
* <<params>> – the passage to be quoted.]=],
},
page = {
param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}",
param_no_synonym = "{{para|page}} or {{para|pages}}",
text = [=[
* <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following:
** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}.
** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to the online version of the work.]=],
},
page_with_roman_preface = {
param_with_synonym = {"inherit", "page"},
param_no_synonym = {"inherit", "page"},
text = [=[
* <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following:
** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}.
** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to the online version of the work.]=],
},
chapter = {
param_with_synonym = "<<synonym>> or {{para|chapter}}",
param_no_synonym = "{{para|chapter}}",
text = [=[
* <<params>> – the name of the chapter quoted from.]=],
},
roman_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in uppercase Roman numerals.]=],
},
arabic_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in Arabic numerals.]=],
},
trailing_params = {
text = [=[
* {{para|footer}} – a comment on the passage quoted.
* {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=],
},
}
function export.paramdoc(frame)
local parargs = frame:getParent().args
local args = process_params(parargs, {
[1] = true,
})
local text = args[1]
local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym)
local function sub_param(synonym)
local subbed_paramtext
if synonym then
subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}")
else
subbed_paramtext = paramtext_no_synonym
end
return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext))))
end
text = text:gsub("<<" .. pattern_escape(param) .. ">>", function()
return sub_param()
end)
text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param)
end
local function fetch_text(param_to_replace, key)
local spec = paramdoc_param_replacements[param_to_replace]
local val = spec[key]
if type(val) == "string" then
return val
end
if type(val) == "table" and val[1] == "inherit" then
return fetch_text(val[2], key)
end
error(
"Internal error: Unrecognized value for param '"
.. param_to_replace
.. "', key '"
.. key
.. "': "
.. mw.dumpObject(val)
)
end
for param_to_replace, spec in pairs(paramdoc_param_replacements) do
if not spec.param_no_synonym then
-- Text to substitute directly.
text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function()
return frame:preprocess(fetch_text(param_to_replace, "text"))
end)
else
do_param_with_optional_synonym(
param_to_replace,
fetch_text(param_to_replace, "text"),
fetch_text(param_to_replace, "param_with_synonym"),
fetch_text(param_to_replace, "param_no_synonym")
)
end
end
-- Remove final newline so template code can add a newline after invocation
text = text:gsub("\n$", "")
return text
end
return export
ik5lq7n4i54jof2p5e4xuo7831c4apf
178376
178375
2026-10-23T06:39:09Z
GinawaSaHapon
3989
178376
Scribunto
text/plain
--[=[
This module contains functions to implement quote-* templates.
Author: Benwing2; conversion into Lua of {{quote-meta/source}} template,
written by Sgconlaw with some help from Erutuon and Benwing2.
The main interface is quote_t(). Note that the source display is handled by source(), which reads both the
arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter.
]=]
local export = {}
--[=[
FIXME:
1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only.
The relevant code checks for a capitalized word; it should probably instead check for the actual month names or
abbrevs.
]=]
-- Named constants for all modules used, to make it easier to swap out sandbox versions.
local check_isxn_module = "Module:check isxn"
local debug_track_module = "Module:debug/track"
local en_utilities_module = "Module:en-utilities"
local italics_module = "Module:italics"
local labels_module = "Module:labels"
local languages_module = "Module:languages"
local languages_error_module = "Module:languages/error"
local links_module = "Module:links"
local number_utilities_module = "Module:number utilities"
local parameters_module = "Module:parameters"
local parse_utilities_module = "Module:parse utilities"
local qualifier_module = "Module:qualifier"
local roman_numerals_module = "Module:roman numerals"
local scribunto_module = "Module:Scribunto"
local script_utilities_module = "Module:script utilities"
local scripts_module = "Module:scripts"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local template_parser_module = "Module:template parser"
local usex_module = "Module:usex"
local usex_templates_module = "Module:usex/templates"
local utilities_module = "Module:utilities"
local yesno_module = "Module:yesno"
local concat = table.concat
local insert = table.insert
local new_title = mw.title.new
local remove = table.remove
local require = require
local sort = table.sort
local u = mw.ustring.char
local ugsub = mw.ustring.gsub
local umatch = mw.ustring.match
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- Use HTML entities here to avoid parsing issues (esp. with brackets)
local SEMICOLON_SPACE = "; "
local SPACE_LBRAC = " ["
local RBRAC = "]"
local TEMP_LT = u(0xFFF1)
local TEMP_GT = u(0xFFF2)
local TEMP_LBRAC = u(0xFFF3)
local TEMP_RBRAC = u(0xFFF4)
local TEMP_SEMICOLON = u(0xFFF5)
local function apply_subst(...)
apply_subst = require(usex_module).apply_subst
return apply_subst(...)
end
local function check_isbn(...)
check_isbn = require(check_isxn_module).check_isbn
return check_isbn(...)
end
local function check_issn(...)
check_issn = require(check_isxn_module).check_issn
return check_issn(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function embedded_language_links(...)
embedded_language_links = require(links_module).embedded_language_links
return embedded_language_links(...)
end
local function escape_wikicode(...)
escape_wikicode = require(parse_utilities_module).escape_wikicode
return escape_wikicode(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function find_parameters(...)
find_parameters = require(template_parser_module).find_parameters
return find_parameters(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_processed_labels(...)
format_processed_labels = require(labels_module).format_processed_labels
return format_processed_labels(...)
end
local function format_qualifier(...)
format_qualifier = require(qualifier_module).format_qualifier
return format_qualifier(...)
end
local function format_usex(...)
format_usex = require(usex_module).format_usex
return format_usex(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_number(...)
get_number = require(number_utilities_module).get_number
return get_number(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function gsplit(...)
gsplit = require(string_utilities_module).gsplit
return gsplit(...)
end
local function page_should_be_ignored(...)
page_should_be_ignored = require(usex_templates_module).page_should_be_ignored
return page_should_be_ignored(...)
end
local function parse_inline_modifiers(...)
parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers
return parse_inline_modifiers(...)
end
local function parse_inline_modifiers_from_segments(...)
parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments
return parse_inline_modifiers_from_segments(...)
end
local function parse_multi_delimiter_balanced_segment_run(...)
parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run
return parse_multi_delimiter_balanced_segment_run(...)
end
local function parse_term_with_lang(...)
parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang
return parse_term_with_lang(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function pluralize(...)
pluralize = require(en_utilities_module).pluralize
return pluralize(...)
end
local function process_params(...)
process_params = require(parameters_module).process
return process_params(...)
end
local function remove_links(...)
remove_links = require(links_module).remove_links
return remove_links(...)
end
local function roman_to_arabic(...)
roman_to_arabic = require(roman_numerals_module).roman_to_arabic
return roman_to_arabic(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function scribunto_parameter_key(...)
scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key
return scribunto_parameter_key(...)
end
local function serial_comma_join(...)
serial_comma_join = require(table_module).serialCommaJoin
return serial_comma_join(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function split_alternating_runs(...)
split_alternating_runs = require(parse_utilities_module).split_alternating_runs
return split_alternating_runs(...)
end
local function split_and_process_raw_labels(...)
split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels
return split_and_process_raw_labels(...)
end
local function split_on_comma(...)
split_on_comma = require(parse_utilities_module).split_on_comma
return split_on_comma(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_transcription(...)
tag_transcription = require(script_utilities_module).tag_transcription
return tag_transcription(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function unitalicize_brackets(...)
unitalicize_brackets = require(italics_module).unitalicize_brackets
return unitalicize_brackets(...)
end
local function upper(...)
upper = require(string_utilities_module).upper
return upper(...)
end
local function usub(...)
usub = require(string_utilities_module).sub
return usub(...)
end
local function yesno(...)
yesno = require(yesno_module)
return yesno(...)
end
local function track(page)
debug_track("quote/" .. page)
end
local function maintenance_line(text)
return '<span class="maintenance-line">(' .. text .. ")</span>"
end
local function isbn(text)
return "[[Special:BookSources/"
.. text
.. "|→ISBN]]"
.. check_isbn(
text,
' <span class="error" style="font-size:88%">Invalid ISBN</span>[[Category:Pages with ISBN errors]]'
)
end
local function issn(text)
return "[https://www.worldcat.org/issn/"
.. text
.. " →ISSN]"
.. check_issn(
text,
' <span class="error" style="font-size:88%">Invalid ISSN</span>[[Category:Pages with ISSN errors]]'
)
end
local function lccn(text)
text = text:gsub(" ", "")
if text:find("-") then
-- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]]
local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$")
if prefix then
if ulen(part2) < 6 then
part2 = ("0"):rep(6 - ulen(part2)) .. part2
end
text = prefix .. part1 .. part2
end
end
return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]"
end
local function format_date(text)
return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy")
end
-- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a
-- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs.
local function parse_and_format_labels(raw_lb, lang)
if not raw_lb then
return nil
end
local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true}
labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true}
if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances
return {labels}
end
end
-- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the
-- name of the parameter from which the list of language codes was fetched.
local function format_langs(langs)
local names = {}
for i, lang in ipairs(langs) do
names[i] = lang:getCanonicalName()
end
if #names == 1 then
return names[1]
end
return serial_comma_join(names)
end
local function get_first_lang(langs)
return langs[1] or get_lang("und")
end
--[=[
Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we
exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}},
{{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters,
plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it.
The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as
foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers).
Also exclude things that look like URL's from being parsed as having language code prefixes.
]=]
local function val_should_not_be_parsed_for_annotations(val)
return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://")
end
local param_mods = {
t = {
-- <t:...> and <gloss:...> are aliases.
item_dest = "gloss",
},
gloss = {},
alt = {},
tr = {},
ts = {},
subst = {},
sc = {type = "script"},
f = {
convert = function(arg, parse_err)
local prefix, val = arg:match("^(.-):([^ ].*)$")
if not prefix then
prefix = ""
val = arg
end
local tags, sc_code, sc = prefix:match("^(.*)/(.-)$")
if sc_code then
sc = get_script(sc_code) or
require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang")
else
tags = prefix
end
local quals
if tags ~= "" then
quals = split_on_comma(tags)
for i, qual in ipairs(quals) do
local obj = get_lang(qual, nil, "allow etym") or get_script(qual)
quals[i] = obj or qual
end
end
return {
quals = quals,
sc = sc,
val = val,
}
end,
store = "insert",
},
q = {},
qq = {},
}
local function generate_obj_annotated_text(text, parse_err, paramname)
local obj = {}
if text:find(":[^ ]") or text:find("%[%[") then
local display, is_wikipedia_wikisource
obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource =
parse_term_with_lang {
term = text,
parse_err = parse_err,
paramname = paramname
}
-- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link
-- to avoid the w: or s: prefix showing. We should probably avoid this by calling
-- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff
-- that we currently do; but we need to test that carefully to make sure it doesn't do things like
-- munge % signs.
if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then
-- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in
-- parse_inline_modifiers().
obj.display = display
end
else
obj.text = text
obj.link = text
end
return obj
end
--[=[
Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or
inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value
was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or
<gloss:...> inline modifier.
If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g.
'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following
fields:
`lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is
given.
`text`: The text after stripping off any language prefix and inline modifiers.
`link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`.
`alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil.
`subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter.
`sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil.
`tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil.
`ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil.
`gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise
the <t:...> or <gloss:...> modifiers if given, otherwise nil.
`f`: Foreign versions of the text.
`q`: Left qualifiers.
`qq`: Right qualifiers.
Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as
might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return
value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of
the text and CSS-tag the text accordingly, but to leave the text untagged.
This object can be passed to format_annotated_text() to format a string displaying the text (appropriately
script-tagged, unless `noscript` is set, as described above) and modifiers.
]=]
local function parse_annotated_text(val, fullname, explicit_gloss)
if not val then
return nil
end
-- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused
-- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having
-- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a
-- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script
-- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big
-- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the
-- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even
-- more.)
if val_should_not_be_parsed_for_annotations(val) then
return {text = val, link = val, noscript = true, gloss = explicit_gloss}
end
local obj
if val:find("<") then
-- Check for inline modifier.
obj = parse_inline_modifiers(val, {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_annotated_text,
})
else
obj = generate_obj_annotated_text(val, nil, fullname)
end
if explicit_gloss then
obj.gloss = explicit_gloss
end
return obj
end
local html_entity_char_to_replacement = {
["<"] = TEMP_LT,
[">"] = TEMP_GT,
["["] = TEMP_LBRAC,
["]"] = TEMP_RBRAC,
}
local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code)
-- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like)
-- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get
-- interpreted as a delimiter.
local ch = decode_entities(entity)
if ch ~= entity then
return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON
end
-- If the entity doesn't decode, escape it anyway iff it follows a valid format.
if hash == "" then
-- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as
-- invalid.
return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
elseif x == "" then
return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
local html_entity_replacement_to_char = {
[TEMP_LT] = "<",
[TEMP_GT] = ">",
[TEMP_LBRAC] = "[",
[TEMP_RBRAC] = "]",
[TEMP_SEMICOLON] = ";",
}
local function undo_html_entity_replacement(txt)
-- Pattern covers everything in html_entity_replacement_to_char.
return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char))
end
-- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]]
-- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no
-- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present)
-- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate
-- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter);
-- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a
-- delimiter); and (c) colons not followed by a space (which may indicate a language prefix).
local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement)
local obj = generate_obj_annotated_text(text, parse_err, paramname)
if not no_undo_html_entity_replacement then
obj.text = undo_html_entity_replacement(obj.text)
obj.link = undo_html_entity_replacement(obj.link)
end
return obj
end
--[=[
Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with
their own inline modifiers. Some examples:
* mainauthor=Paula Pattengale; Terea Sonsthagen
* author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson
* author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank
* author=G Ristori; et al.
* author=Jason Scott; zh:王晰宁<t:Wang Xining>
* editors=zh:包文俊; zh:金心雯
* quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen>
There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.:
* author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}]
* author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}})
* author=James (the Elder;) Humphrys
There may also be HTML entities with semicolons in them:
* author=[{{w|Gilbert Clerke}}]
* 2ndauthor=Martin Biddle & Sally Badham
* author=Peter Christen Asbjørnsen
There may be both embedded semicolons and HTML entities with semicolons in them:
* author=[{{w|Voltaire}} [pseudonym; François-Marie Arouet]]
In general we want to treat [ like an opening bracket and ] like a closing bracket. Beware that they may be
mismatched:
* author=Anonymous [{{w|Karl Maria Kertbeny}}]
Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was
retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...>
inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If
`explicit_gloss` is specified and multiple values were seen, an error results.)
Return value is a list of objects of the same sort as returned by parse_annotated_text().
]=]
local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname)
if not val then
return nil
end
-- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated
-- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or
-- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML
-- entities; in the places where this occurs, the variable name contains 'html' in it.
local splitchar, english_delim
if val:find("^,") then
splitchar = ","
english_delim = "comma"
val = val:gsub("^,", "")
else
splitchar = ";"
english_delim = "semicolon"
end
-- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers).
if not val:find("[<" .. splitchar .. "]") then
if val_should_not_be_parsed_for_annotations(val) then
return {{text = val, link = val, noscript = true}}
else
return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")}
end
end
-- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or
-- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand
-- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a
-- delimiter).
if not val:find("[<>%[%](){}&]") then
local entity_objs = {}
for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do
if val_should_not_be_parsed_for_annotations(entity) then
insert(entity_objs, {
text = entity,
link = entity,
noscript = true
})
else
insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement"))
end
end
return entity_objs
end
-- Escape HTML entities, and get rid of directionality markers.
local amp = val:find("&", nil, true)
if amp then
-- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities
-- that have non-ASCII characters in their codes.
val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement)
end
-- Pattern covers left-to-right (U+200E) and right-to-left (U+200F).
val = val:gsub("\226\128[\142\143]", "")
-- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket
-- as matching literal versions of the same characters.
local entity_runs = parse_multi_delimiter_balanced_segment_run(
val,
{{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}},
true
)
if type(entity_runs) == "string" then
local undo_val = undo_html_entity_replacement(val)
-- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off
-- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears
-- the text is already script-tagged).
return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}}
end
-- Split on semicolon (or comma), possibly surrounded by whitespace.
local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*")
-- Process each value.
local entity_objs = {}
for _, entity_group in ipairs(separated_groups) do
-- Rejoin runs that don't involve <...>.
local j = 2
while j <= #entity_group do
if not entity_group[j]:find("^<.*>$") then
entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1]
remove(entity_group, j)
remove(entity_group, j)
else
j = j + 2
end
end
local oneval = undo_html_entity_replacement(concat(entity_group))
-- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it,
-- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed
-- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more.
if val_should_not_be_parsed_for_annotations(oneval) then
insert(entity_objs, {
text = oneval,
link = oneval,
noscript = true
})
else
local obj
if #entity_group > 1 then
-- Check for inline modifier.
obj = parse_inline_modifiers_from_segments({
group = entity_group,
arg = oneval,
props = {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_multivalued_annotated_text,
},
})
else
obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname)
end
insert(entity_objs, obj)
end
end
if explicit_gloss then
if #entity_objs > 1 then
error(
(
"Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> "
.. "inline modifier attached to the individual entities"
):format(explicit_gloss_fullname, english_delim, fullname)
)
end
entity_objs[1].gloss = explicit_gloss
end
return entity_objs
end
--[=[
Format a text property that may be in a foreign language or script, along with annotations. This is conceptually
similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is
more appropriate for bibliographic entries. The output looks like this:
TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS]
`textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further
wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a
similar function for the gloss.
]=]
local function format_annotated_text(textobj, tag_text_func, tag_gloss_func)
if not textobj then
return nil
end
local text, link = textobj.text, textobj.link
local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss
-- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a
-- Wikipedia link is given.
local alt = textobj.alt or textobj.display
if alt then
if link:find("%[%[") or link:find("%]%]") then
local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt)
error(escape_wikicode(errmsg))
end
text = ("[[%s|%s]]"):format(link, alt)
end
-- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}.
-- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in
-- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language
-- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration.
if not textobj.noscript then
local lang = textobj.lang
-- As an optimization, don't do script detection on an argument that contains only ASCII.
local sc = textobj.sc
or lang and lang:findBestScript(text)
or not text:find("^[ -~]$") and find_best_script_without_lang(text)
or nil
-- As an optimization, don't do any of the following if there's no language, script, translit or transcription,
-- as will be the case with simple ASCII values.
if lang or sc or tr or ts then
if not lang then
lang = get_lang("und")
end
if tr == "-" then
tr = nil
elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn
-- might return nil
local text_for_tr = text
if subst then
text_for_tr = apply_subst(text_for_tr, subst)
else
text_for_tr = remove_links(text)
end
tr = (lang:transliterate(text_for_tr, sc))
end
if text:find("%[%[") then
-- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents,
-- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this
-- should not happen, and embedded_language_links() should do nothing if no embedded links
-- are present. To work around this, only call embedded_language_links() when there are
-- embedded links present.
text = embedded_language_links({
term = text,
lang = lang,
sc = sc,
})
end
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
text = tag_text(text, lang, sc)
end
if tr then
-- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not
-- likely to be a term that has an entry.
tr = tag_translit(tr, lang, "usex")
end
if ts then
ts = tag_transcription(ts, lang, "usex")
end
end
end
text = unitalicize_brackets(text)
if tag_text_func then
text = tag_text_func(text)
end
local parts = {}
if textobj.q then
insert(parts, format_qualifier(textobj.q) .. " ")
end
insert(parts, text)
if tr or ts or f or gloss then
insert(parts, SPACE_LBRAC)
local subparts = {}
if tr or ts then
local tr_ts
if ts then
ts = "/" .. ts .. "/"
end
if tr and ts then
tr_ts = tr .. " " .. ts
else
tr_ts = tr or ts
end
insert(subparts, tr_ts)
end
if f then
for _, ff in ipairs(f) do
local sc = ff.sc
local lang
if not sc and ff.quals then
local qual = ff.quals[1]
if type(qual) == "string" then
-- do nothing; we'll do script detection farther down
elseif qual:hasType("script") then
sc = qual
else -- language
sc = qual:findBestScript(ff.val)
lang = qual
end
end
if not lang then
lang = get_lang("und")
end
sc = sc or find_best_script_without_lang(ff.val)
local val = embedded_language_links({
term = ff.val,
lang = lang,
sc = sc,
})
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
val = tag_text(val, lang, sc)
end
local qual_prefix
if ff.quals then
for i, qual in ipairs(ff.quals) do
if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then
ff.quals[i] = qual:getCanonicalName()
end
end
qual_prefix = concat(ff.quals, "/") .. ": "
else
qual_prefix = ""
end
insert(subparts, qual_prefix .. val)
end
end
if gloss then
gloss = '<span class="e-translation">' .. gloss .. "</span>"
gloss = unitalicize_brackets(gloss)
if tag_gloss_func then
gloss = tag_gloss_func(gloss)
end
insert(subparts, gloss)
end
insert(parts, concat(subparts, ", "))
insert(parts, RBRAC)
end
if textobj.qq then
insert(parts, " " .. format_qualifier(textobj.qq))
end
return concat(parts)
end
--[=[
Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the
multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(),
joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using
serial_comma_join() with the specified conjunction.
`textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in
format_annotated_text().
]=]
local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func)
if not textobjs then
return nil
end
if #textobjs == 1 then
return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func)
end
local parts = {}
for _, textobj in ipairs(textobjs) do
insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func))
end
-- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.")
local use_semicolon = false
for _, obj in ipairs(textobjs) do
-- Use remove_links to ignore commas in links
if obj.text and remove_links(obj.text):find(", ") then
use_semicolon = true
break
end
end
local n = #parts
if n > 0 and parts[n]:match("^'*et al[.']*$") then
-- Special handling for 'et al.'
parts[n] = "''et al.''"
if n == 2 then
-- author et al.
return concat(parts, " ")
else
-- author 1, author 2, et al.
return concat(parts, (use_semicolon and "; ") or ", ")
end
if delimiter == "and" or delimiter == "or" then
delimiter = ", "
end
return concat(parts, delimiter)
end
if delimiter == "and" or delimiter == "or" then
return serial_comma_join(parts, {conj = delimiter})
end
return concat(parts, delimiter or ((use_semicolon and "; ") or ", "))
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then
return nil
elseif type(arg) ~= "string" then
return arg
end
arg = mw.text.trim(arg)
if arg == "" then
return nil
end
return arg
end
local abbrs = {
["a."] = {anchor = "a.", full = "ante"},
["c."] = {anchor = "c.", full = "circa"},
["p."] = {anchor = "p.", full = "post"},
}
-- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec.
-- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found,
-- returns an empty string and the full date.
local function process_ante_circa_post(date)
local prefix = usub(date, 1, 2)
local abbr = abbrs[prefix]
local abbr_prefix = ""
if abbr then
abbr_prefix = "''[[Apendise:Glosaryo#"
.. abbr.anchor
.. '|<abbr title="'
.. abbr.full
.. '">'
.. abbr.anchor
.. "</abbr>]]'' "
-- Remove lowercase letter, period, and space from beginning of date parameter.
date = ugsub(date, "^%l%.%s*", "")
end
return abbr_prefix, date
end
-- Format the arguments that specify the date of the quotation. These include the following:
-- |date=: The date. If |start_date= is given, this is the end date.
-- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given.
-- |start_date=: The start date, to specify a range.
-- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given.
-- |accessdate=: Date a website was accessed; processed if no other date was given.
-- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date.
--
-- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if
-- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=,
-- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is
-- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of
-- the range is |start_date_published=, etc.
--
-- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in
-- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to
-- have an index added to them (|date2=, |year2=, |month2=, etc.).
--
-- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used.
--
-- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value.
--
-- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e.
-- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and
-- neither |nodate= is given to indicate that there is no date, or |accessdate= is given).
--
-- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category
-- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added
-- (in which case the scond return value will always be nil).
local function format_date_args(
a,
get_full_paramname,
alias_map,
parampref,
paramsuf,
bold_year,
maintenance_line_no_date,
year_last
)
local output = {}
parampref = parampref or ""
paramsuf = paramsuf or ""
local function getp(param)
return a(parampref .. param .. paramsuf)
end
local function pname(param)
local fullname = get_full_paramname(parampref .. param .. paramsuf)
return alias_map[fullname] or fullname
end
-- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of
-- the parameter from which the timestamp was fetched, for error messages.
local function format_date_with_code(code, timestamp, param)
local language = mw.getContentLanguage()
local ok, date = pcall(language.formatDate, language, code, timestamp)
if ok then
return date
else
-- All the formats used in format_date_args() are fine, so the timestamp must be at fault.
error(
(
"Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the "
.. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]"
):format(pname(param), tostring(timestamp))
)
end
end
-- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following
-- algorithm:
-- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are
-- given, the day shows up as 1.
-- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given.
-- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized
-- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not.
--
-- `param` is the base name of the parameter from which the timestamp was fetched.
local function date_has_day_specified(timestamp, param)
local day = format_date_with_code("j", timestamp, param)
if day ~= "1" then
return true
end
local english_month = timestamp:find("%u")
local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " ")))
local seen_nums = split(canon_timestamp, " ", true)
local saw_one = false
for _, num in ipairs(seen_nums) do
if num == "1" or num == "01" then
saw_one = true
break
end
end
if not saw_one then
return false
end
return #seen_nums >= 3 or english_month and #seen_nums >= 2
end
-- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include
-- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param
-- from which the date was fetched, for error messages.
local function format_bold_date(date, explicit_day_given, date_param)
local day_month_code = explicit_day_given and "j F" or "F"
local month_day_code = explicit_day_given and "F j" or "F"
if year_last then
if bold_year then
-- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given).
return format_date_with_code(day_month_code .. " '''Y'''", date, date_param)
else
-- This formats like "3 August 2023" (or "August 2023" if day not explicitly given).
return format_date_with_code(day_month_code .. " Y", date, date_param)
end
else
if bold_year then
-- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given).
return format_date_with_code("'''Y''' " .. month_day_code, date, date_param)
else
-- This formats like "2023 August 3" (or "2023 August" if day not explicitly given).
return format_date_with_code("Y " .. month_day_code, date, date_param)
end
end
end
-- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't
-- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives
-- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for
-- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which
-- uses {{#formatdate:}}) accept similar date formats. See:
-- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]]
-- * [[mw:Help:Extension:ParserFunctions##time]]
-- * [[mw:Help:Magic_words#Formatting]]
-- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date";
-- `parampref` is the prefix added to "date" to get the parameter name.
local function fix_date(date, param_pref)
if tonumber(date) ~= nil then
error(
("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format(
pname(param_pref .. "date"),
pname(param_pref .. "year")
)
)
elseif date and date:find("%s*%a+,%s*%d+%s*$") then
error(
("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format(
pname(param_pref .. "date"),
pname(param_pref .. "month"),
pname(param_pref .. "year")
)
)
end
if date then
-- Commas are replaced with spaces to prevent parsing issues
local fixed_date = ugsub(date, ", *", " ")
return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1"))
end
end
local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "")
local year = getp("year")
local month = getp("month")
local start_year = getp("start_year")
local start_month = getp("start_month")
if date and year then
error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year")))
end
if date and month then
error(
("|%s= should only be specified in conjunction with |%s=, not with |%s="):format(
pname("month"),
pname("year"),
pname("date")
)
)
end
if start_date and start_year then
error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year")))
end
if start_date and start_month then
error(
("|%s= should only be specified in conjunction with |%s=, not with |%s="):format(
pname("start_month"),
pname("start_year"),
pname("start_date")
)
)
end
if (start_date or start_year) and not (date or year) then
error(
("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format(
pname("start_date"),
pname("start_year"),
pname("start_month"),
pname("date"),
pname("year"),
pname("month")
)
)
end
local dash = " – "
local day_explicitly_given = date and date_has_day_specified(date, "date")
local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date")
-- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or
-- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based
-- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already.
-- `date_param` is the base name of the param from which the date was fetched, for error messages.
local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param)
if date then
return format_bold_date(date, explicit_day_given, date_param)
else
-- Boldface a year spec if it's not already boldface.
if bold_year and not yearobj.text:find("'''") then
-- Clone the year object before modifying it because we may use it later to check against the current
-- year (if we're dealing with start_year).
yearobj = shallow_copy(yearobj)
yearobj.text = "'''" .. yearobj.text .. "'''"
if yearobj.alt then
yearobj.alt = "'''" .. yearobj.alt .. "'''"
end
end
if year_last then
return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj)
else
return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "")
end
end
end
local yearobj = parse_annotated_text(year, pname("year"))
local monthobj = parse_annotated_text(month, pname("month"))
local start_yearobj = parse_annotated_text(start_year, pname("start_year"))
local start_monthobj = parse_annotated_text(start_month, pname("start_month"))
if start_yearobj then
local abbr_prefix
abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text)
start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link))
insert(output, abbr_prefix)
elseif yearobj then
local abbr_prefix
abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text)
yearobj.link = select(2, process_ante_circa_post(yearobj.link))
insert(output, abbr_prefix)
end
if start_date or start_year then
local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date")
local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil
local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil
local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date")
local beg_month = start_monthobj and start_monthobj.text
or start_date and format_date_with_code("F", start_date, "start_date")
or nil
local beg_day = start_date
and start_day_explicitly_given
and format_date_with_code("j", start_date, "start_date")
or nil
if year_last then
if beg_day then
insert(output, beg_day .. " " .. beg_month)
else
insert(output, beg_month)
end
if beg_year ~= cur_year then
insert(output, " " .. beg_year)
end
else
insert(output, format_date_or_year_month(
start_date,
start_yearobj,
start_monthobj,
start_day_explicitly_given,
"start_date"
))
end
if cur_year ~= beg_year then
-- Different years; insert current date in full.
if beg_month or cur_month then
insert(output, dash)
else
insert(output, "–")
end
insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date"))
elseif cur_month and cur_month ~= beg_month then
local month_ins = monthobj and format_annotated_text(monthobj) or cur_month
-- Same year but different months; insert current month and (if available) current day.
if cur_day then
insert(output, dash)
if year_last then
insert(output, cur_day .. " " .. month_ins)
else
insert(output, month_ins .. " " .. cur_day)
end
else
if beg_day then
insert(output, dash)
else
insert(output, "–")
end
insert(output, month_ins)
end
elseif cur_day and cur_day ~= beg_day then
-- Same year and month but different days; insert current day.
insert(output, "–")
insert(output, cur_day)
else
-- Same year, month and day; or same year and month, and day not available; or same year, and month and
-- day not available. Do nothing. FIXME: Should we throw an error?
end
if year_last and beg_year == cur_year then
if cur_month then
insert(output, " " .. cur_year)
else
insert(output, " " .. cur_year)
end
end
elseif date or yearobj then
insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date"))
elseif not maintenance_line_no_date then
-- Not main quote date. Return nil, caller will handle.
return nil, nil
elseif not getp("nodate") then
local accessdate = getp("accessdate")
if accessdate then
local explicit_day_given = date_has_day_specified(accessdate, "accessdate")
insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (huling na-access)")
else
if mw.title.getCurrentTitle().namespace ~= 10 then
return maintenance_line(maintenance_line_no_date), true
end
return nil, nil
end
end
return ine(concat(output)), nil
end
local function tag_with_cite(txt)
return "<cite>" .. txt .. "</cite>"
end
-- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this
-- module (formerly contained in {{quote-meta/source}}).
function export.source(args, alias_map, format_as_cite, other_controls)
local tracking_categories = {}
local argslang = args[1] or args.lang
if not argslang then
-- For the moment, only trigger an error on mainspace pages and
-- other pages that are not user pages or pages containing discussions.
-- These are the same pages that appear in the appropriate tracking
-- categories. User and discussion pages have not generally been
-- fixed up to include a language code and so it's more helpful
-- to use a maintenance line than signal an error.
local current_title = mw.title.getCurrentTitle()
if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then
require(languages_error_module)(nil, 1)
end
end
-- Given a canonical param, convert it to the original parameter specified by the user (which may have been an
-- alias).
local function alias(param)
return alias_map[param] or param
end
local output, sep = {}
local overrides = other_controls and other_controls.overrides or {}
-- Add text to the output. The text goes into a list, and we concatenate all the list components together at the
-- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that
-- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and
-- there's no title and no URL, then the first time we add anything after the title, we don't want to add a
-- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or
-- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator
-- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting
-- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text.
local function add(text)
if sep then
insert(output, sep)
end
insert(output, text)
sep = nil
end
local function add_with_sep(text, next_sep)
add(text)
sep = next_sep or ", "
end
-- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient.
-- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last").
-- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=,
-- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.).
local function make_get_full_paramname(ind)
return function(param)
return param .. ind
end
end
-- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above).
-- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have
-- wrapper functions that access params and define them only once.
local get_full_paramname
-- Return two values: the value of a parameter given the base param name (which may have a numeric index added),
-- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch
-- the parameter value from args[] given this name). The base parameter can be a list of such base params, which
-- are checked in turn, or nil, in which case nil is returned.
local function a_with_name(param)
if not param then
return nil
elseif type(param) ~= "table" then
local fullname = get_full_paramname(param)
return args[fullname], alias(fullname)
end
for _, par in ipairs(param) do
local val, fullname = a_with_name(par)
if val then
return val, alias(fullname)
end
end
return nil
end
-- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base
-- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned.
local function a(param)
return (a_with_name(param))
end
-- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's.
local function aurl_with_name(param)
local value, fullname = a_with_name(param)
if value and value:find(" ") and not value:find("%[") then
error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value))
end
return value, fullname
end
-- Identical to a(param) except that it verifies that no space is present. Should be used for URL's.
local function aurl(param)
return (aurl_with_name(param))
end
-- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have
-- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string.
-- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second
-- return value.
local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local obj = parse_annotated_text(val, fullname)
return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname
end
-- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have
-- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string.
-- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see
-- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g.
-- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss.
local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func)
return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func))
end
-- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may
-- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a
-- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two
-- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in
-- format_multivalued_annotated_text().
local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local objs = parse_multivalued_annotated_text(val, fullname)
local num_objs = objs and #objs or 0
return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs
end
-- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may
-- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a
-- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in
-- format_multivalued_annotated_text().
local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func)
return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func))
end
-- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by
-- Mary Bloggs" (if there's an author preceding).
local author_outputted = false
-- When formatting as a citation, the priority is to display a name and a date before the book/chapter title
-- this tracks whether or not the author/date has been displayed
local date_outputted, formatted_date, formatted_origdate, need_date = false
local function add_date(no_paren)
if not date_outputted then
if no_paren then
sep = ", "
else
sep = " "
end
if formatted_date then
if no_paren then
add(formatted_date)
else
add("(" .. formatted_date .. ")")
end
end
if formatted_origdate then
add(SPACE_LBRAC .. formatted_origdate .. RBRAC)
end
sep = ", "
date_outputted = true
end
end
local function is_anonymous(val)
return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$")
end
-- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split
-- among various parameters):
-- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is
-- the full parameter name holding that value;
-- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and
-- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter);
-- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`,
-- and `authorlink_fullname` is the full parameter name holding that value;
-- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of
-- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such
-- parameter);
-- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full
-- parameter name holding that value;
-- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name
-- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for
-- no such parameter);
-- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full
-- parameter name holding that value;
-- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name
-- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for
-- no such parameter).
-- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first"
local function add_author(
author,
author_fullname,
trans_author,
trans_author_fullname,
authorlink,
authorlink_fullname,
trans_authorlink,
trans_authorlink_fullname,
first,
first_fullname,
trans_first,
trans_first_fullname,
last,
last_fullname,
trans_last,
trans_last_fullname,
last_first
)
local function make_author_with_url(txt, txtparam, authorlink, authorlink_param)
if authorlink then
if authorlink:find("%[%[") then
error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink))
end
if txt:find("%[%[") then
error(("Can't specify links in %s=%s"):format(txtparam, txt))
end
return "[[w:" .. authorlink .. "|" .. txt .. "]]"
else
return txt
end
end
local num_authorobjs
if author then
local authorobjs =
parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname)
num_authorobjs = #authorobjs
if num_authorobjs == 1 then
if is_anonymous(authorobjs[1].text) then
authorobjs[1].text = "di-kilalang may-akda"
authorobjs[1].link = "anonymous author"
end
if authorlink then
authorobjs[1].text = make_author_with_url(
authorobjs[1].text,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
authorobjs[1].link = make_author_with_url(
authorobjs[1].link,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
end
if authorobjs[1].gloss and trans_authorlink then
authorobjs[1].gloss = make_author_with_url(
authorobjs[1].gloss,
("<t:...> in |%s"):format(author_fullname),
trans_authorlink,
"|" .. trans_author_fullname
)
end
add(format_multivalued_annotated_text(authorobjs))
elseif trans_authorlink then
error(
(
"Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the "
.. "<t:...> inline modifier attached to the individual entities and put the link directly "
.. "in the value of the inline modifier"
):format(trans_authorlink_fullname, author_fullname)
)
else
-- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills
-- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it
-- all.
local formatted_text = format_multivalued_annotated_text(authorobjs)
if authorlink then
formatted_text = make_author_with_url(
formatted_text,
"|" .. author_fullname,
authorlink,
"|" .. authorlink_fullname
)
end
add(formatted_text)
end
else
num_authorobjs = 1
-- Author separated into first name + last name. We don't currently support non-Latin-script
-- authors separated this way and probably never will.
if first then
if last_first then
author = last .. ", " .. first
else
author = first .. " " .. last
end
else
author = last
end
if authorlink then
local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname
author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname)
end
local trans_author
if trans_last then
if trans_first then
trans_author = trans_first .. " " .. trans_last
else
trans_author = trans_last
end
if trans_authorlink then
local trans_authorparam = trans_first
and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname)
or "|" .. trans_last_fullname
trans_author = make_author_with_url(
trans_author,
trans_authorparam,
trans_authorlink,
trans_authorlink_fullname
)
end
end
add(author)
if trans_author then
add(SPACE_LBRAC)
add(trans_author)
add(RBRAC)
end
end
author_outputted = true
return num_authorobjs
end
local function add_authorlike(
param,
prefix_with_preceding_authors,
suffix_without_preceding_authors,
suffix_if_multiple,
anonymous_suffix
)
local delimiter = author_outputted and "at" or ", "
local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter)
if not entities then
return
end
if is_anonymous(entities) then
-- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific
-- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix.
if not anonymous_suffix then
local cleaned_suffix = suffix_without_preceding_authors
:gsub(" ", " ")
:gsub(" ", " ")
:gsub(" ", " ")
:gsub("[", "[")
:gsub("]", "]")
cleaned_suffix = mw.text.trim(cleaned_suffix)
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$")
end
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$")
end
if not anonymous_suffix then
anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$")
end
if not anonymous_suffix then
anonymous_suffix = suffix_without_preceding_authors
end
end
add_with_sep("anonymous" .. anonymous_suffix)
elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then
add_with_sep(prefix_with_preceding_authors .. entities)
elseif suffix_if_multiple and num_entities > 1 then
add_with_sep(entities .. suffix_if_multiple)
else
add_with_sep(entities .. suffix_without_preceding_authors)
end
author_outputted = true
end
local function add_authorlabel()
local default_authorlabel = a("default-authorlabel")
if default_authorlabel and yesno(a("authorlabel"), true) then
sep = nil
add_with_sep(" " .. default_authorlabel)
end
end
local function has_new_title_or_author()
return args["2ndauthor"]
or args["2ndlast"]
or args.chapter2
or args.title2
or args.tlr2
or args.mainauthor2
or args.editor2
or args.editors2
or args.compiler2
or args.compilers2
or args.director2
or args.directors2
end
local function has_newversion()
return args.newversion or args.location2 or has_new_title_or_author()
end
-- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or
-- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for
-- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with
-- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"):
-- * chapterurl=: URL of the chapter.
-- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>).
-- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=).
-- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added.
-- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series).
-- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=).
--
-- Returns nil if no value specified for the main parameter, otherwise the formatted value.
local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix)
local chap, chap_fullname = a_with_name(param)
local chap_num, chap_num_fullname = a_with_name(param .. "_number")
local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain")
if chap_num and chap_plain then
error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname))
end
local chap_series, chap_series_fullname =
parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite)
local chap_seriesvolume, chap_seriesvolume_fullname =
parse_and_format_annotated_text_with_name(param .. "_seriesvolume")
if chap_series then
chap_series = ", " .. chap_series
end
if chap_seriesvolume then
if not chap_series then
error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname))
end
chap_series = chap_series .. " (" .. chap_seriesvolume .. ")"
end
local chapterurl
local function make_chapter_with_url(chap)
if chapterurl then
return "[" .. chapterurl .. " " .. chap .. "]"
else
return chap
end
end
if not chap then
if chap_num then
error(
("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format(
chap_num_fullname,
chap_fullname,
chap_fullname
)
)
end
if chap_plain then
chapterurl = aurl(param .. "url")
return make_chapter_with_url(chap_plain .. (chap_series or ""))
end
return nil
end
local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "")
chapterurl = aurl(param .. "url")
local formatted
if numeric_prefix and get_number(cleaned_chap) then
-- Arabic chapter number
formatted = numeric_prefix .. make_chapter_with_url(chap)
elseif
numeric_prefix
and cleaned_chap:match("^[mdclxviMDCLXVI]+$")
and roman_to_arabic(cleaned_chap, true)
and (not overrides[param] or not overrides[param].noroman)
then
-- Roman chapter number
formatted = numeric_prefix .. make_chapter_with_url(upper(chap))
else
-- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill")
if chap:find("^!") then
chap = chap:gsub("^!", "")
end
-- Must be a chapter name
local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param))
chapterobj.text = make_chapter_with_url(chapterobj.text)
chapterobj.link = make_chapter_with_url(chapterobj.link)
formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "")
end
if chap_num or chap_plain then
-- NOTE: Up above we throw an error if both chap_num and chap_plain are specified.
formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")"
end
if chap_series then
formatted = formatted .. chap_series
end
return formatted
end
-- This handles everything after displaying the author, starting with the chapter and ending with page, column,
-- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to
-- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a
-- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value.
local function postauthor(ind, num_authors, format_as_cite)
get_full_paramname = make_get_full_paramname(ind)
if author_outputted then
add_authorlabel()
end
local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "at")
if coauthors then
local with_prefix = ""
if author_outputted then
with_prefix = "kasama si "
if num_authors == 1 then
sep = " "
end
end
add_with_sep(with_prefix .. coauthors)
author_outputted = true
end
add_authorlike("quotee", "binabanggit si ", ", binanggit", ", binanggit")
if format_as_cite and author_outputted and not date_outputted then
add_date()
sep = ", "
end
add_authorlike("chapter_tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
local function add_sg_and_pl_authorlike(noun, verbed)
local sgparam = noun
local plparam = noun .. "s"
local sgval, sgval_fullname = a_with_name(sgparam)
local plval, plval_fullname = a_with_name(plparam)
if sgval and plval then
error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname))
end
if sgval or plval then
local verbed_by = verbed .. " ni "
local comma_sgnoun = ", " .. noun
local comma_plnoun = ", " .. noun .. "s"
add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun)
add_authorlike(plparam, verbed_by, comma_plnoun)
end
end
local formatted_entry = format_chapterlike("entry", nil, "“", "”")
local formatted_chapter = format_chapterlike("chapter", "kabanata ", "“", "”")
local function add_entry()
if formatted_entry then
add_with_sep(formatted_entry)
if not a("notitle") then
add("sa ") -- tl change: in
author_outputted = false
else
author_outputted = true
end
formatted_entry = nil
end
end
local function add_chapter()
add_entry()
if formatted_chapter then
add_with_sep(formatted_chapter)
if not a("notitle") then
add("sa ")
author_outputted = false
end
formatted_chapter = nil
end
end
local function add_actor_role(format_as_cite)
local role = parse_and_format_multivalued_annotated_text("role", "at")
local actor_val, actor_fullname = a_with_name("actor")
local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname)
local actor = format_multivalued_annotated_text(actor_objs, "at")
if format_as_cite then
if role then
if actor then
add_with_sep(actor .. " bilang ")
end
sep = nil
add_with_sep(role)
elseif actor then
add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")")
end
else
if role then
add_with_sep("sinalita ni " .. role)
if actor then
sep = nil
add_with_sep(" (" .. actor .. ")")
end
elseif actor then
add_with_sep(actor .. " (" .. (#actor_objs > 1 and "(mga) aktor" or "aktor") .. ")")
end
end
end
if format_as_cite then
if date_outputted then
add_chapter()
end
local output_len = #output
local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor")
if mainauthor then
add_with_sep(mainauthor)
end
-- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag
author_outputted = false
add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
author_outputted = false
add_sg_and_pl_authorlike("editor", "patnugot ni")
add_sg_and_pl_authorlike("compiler", "kinompila ni")
add_sg_and_pl_authorlike("director", "direksiyon ni")
add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat")
add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik")
add_authorlike("composer", nil, " (musika)", nil, " kompositor")
add_actor_role("format_as_cite")
-- if the output length has changed, a credit name has been printed
-- and we can print the date
if output_len ~= #output then
author_outputted = true
add_date()
end
add_chapter()
else
add_chapter()
local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor")
if mainauthor then
add_with_sep(mainauthor)
author_outputted = true
end
add_authorlike("tlr", "sinalin ni ", ", sinalin ", nil, " nagsalin")
add_sg_and_pl_authorlike("editor", "patnugot ni")
add_sg_and_pl_authorlike("compiler", "kinompila ni")
add_sg_and_pl_authorlike("director", "direksiyon ni")
add_authorlike("lyricist", nil, " (titik)", nil, " nagsulat")
add_authorlike("lyrics-translator", nil, " (salin)", nil, " nagsalin ng titik")
add_authorlike("composer", nil, " (musika)", nil, " kompositor")
end
local title, title_fullname = a_with_name("title")
local need_comma = false
if title then
local titleobj = parse_annotated_text(title, title_fullname, a("trans-title"))
add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite))
local series = parse_and_format_annotated_text("series")
if series then
add(" (" .. series)
local seriesvolume = parse_and_format_annotated_text("seriesvolume")
if seriesvolume then
add(SEMICOLON_SPACE .. seriesvolume)
end
add(")")
end
need_comma = true
elseif ind == "" then
if not a("notitle") then
add(maintenance_line("Please provide the book title or journal name"))
need_comma = true
end
end
local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl")
local url, url_fullname = aurl_with_name("url")
local urls, urls_fullname = aurl_with_name("urls")
if url and urls then
error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname))
end
local function verify_title_supplied(url_name)
-- There are too many cases of this to throw an error at this time.
-- if not title then
-- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname))
-- end
end
if archiveurl or url then
verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname)
sep = nil
add("‎<sup>[" .. (archiveurl or url) .. "]</sup>")
elseif urls then
verify_title_supplied(urls_fullname)
sep = nil
add("‎<sup>" .. urls .. "</sup>")
end
-- display (in Language) if language is provided and is not English and not overriden by termlang or worklang
if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then
local lang = get_first_lang(args[1] or args.lang)
if lang then
local langcode = lang:getCode()
if not (langcode == "und" or langcode == "tl") then -- tlchange itago kapag tagalog
local langs = format_langs(args[1] or args.lang)
if langs then
add(" (sa wikang " .. langs .. ")")
end
end
end
end
if need_comma then
sep = ", "
end
local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition")
local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain")
if edition and edition_plain then
error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname))
end
if edition then
add_with_sep("ika-" .. edition .. " labas")
end
if edition_plain then
add_with_sep(edition_plain)
end
-- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually
-- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized
-- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if
-- ind == "2"). Only one of the first three can be specified; an error results if more than one are given.
-- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly
-- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a
-- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed
-- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page ").
-- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is
-- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case
-- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers
-- (including with optional inline modifiers), and such text is handled appropriately.
local function format_numeric_param(paramname, singular_desc)
local sgval = a_with_name(paramname)
local sgobj = parse_annotated_text(sgval, paramname)
local plparamname = paramname .. "s"
local plval = a_with_name(plparamname)
local plobj = parse_annotated_text(plval, plparamname)
local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain")
local numspec
if not sgval and not plval and not plainval then
return
elseif plainval and (sgval or plval) then
error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname))
elseif sgval and plval then
-- if both singular and plural, display "page 1 of 1-10"
numspec = singular_desc .. " " .. sgval .. " of " .. plval
else
-- Merge page= and pages= and treat alike because people often mix them up in both directions.
if plainval then
numspec = plainval
else
local val = sgobj and sgobj.text or plobj.text
if val == "unnumbered" then
numspec = "unnumbered " .. singular_desc
else
local desc
if val:find("^!") then
val = val:gsub("^!", "")
desc = sgval and singular_desc or pluralize(singular_desc)
else
local check_val = val
if check_val:find("%[") then
check_val = remove_links(check_val)
-- convert URL's of the form [URL DISPLAY] to the displayed value
check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1")
end
-- in case of negative page numbers (do they exist?), don't treat as multiple pages
check_val = check_val:gsub("^%-", "")
-- replace HTML entity en-dashes and em-dashes with their literal codes
check_val = check_val:gsub("–", "–")
check_val = check_val:gsub("–", "–")
check_val = check_val:gsub("—", "—")
check_val = check_val:gsub("—", "—")
-- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b)
-- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators).
if
umatch(check_val, "[–—]")
or check_val:find(" and ")
or check_val:match("%d+[^ ]* *%- *%d+")
or check_val:match("%d+[^ ]* *, +%d+")
then
desc = pluralize(singular_desc)
else
desc = singular_desc
end
end
local obj = sgobj or plobj
obj.text = val
if obj.link:find("^!") then
obj.link = obj.link:gsub("^!", "")
end
val = format_annotated_text(obj)
numspec = desc .. " " .. val
end
end
end
local url = a(paramname .. "url")
if url then
return "[" .. url .. " " .. numspec .. "]"
else
return numspec
end
end
local volume = format_numeric_param("volume", a("volume_prefix") or "bolyum")
if volume then
add_with_sep(volume)
end
local issue = format_numeric_param("issue", a("issue_prefix") or "bilang")
if issue then
add_with_sep(issue)
end
-- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number)
local number = format_numeric_param("number", a("number_prefix") or "bilang")
if number then
add_with_sep(number)
end
local annotations = {}
local genre = a("genre")
if genre then
insert(annotations, genre)
end
local format = a("format")
if format then
insert(annotations, format)
end
local medium = a("medium")
if medium then
insert(annotations, medium)
end
-- Now handle the display of language annotations like "(in French)" or
-- "(quotation in Nauruan; overall work in German)".
local quotelang = args[1] or args.lang
if not quotelang then
if ind == "" then
-- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown
-- above.
insert(annotations, maintenance_line("Please specify the language of the quote using |1="))
else
-- do nothing in newversion= portion
end
elseif ind == "" then
local worklang = a("worklang")
local termlang = a("termlang")
worklang = worklang or quotelang
termlang = termlang or quotelang
if worklang == quotelang then
if worklang == termlang then
-- do nothing
else
insert(annotations, "sa wikang " .. format_langs(quotelang))
end
else
if quotelang ~= termlang then
insert(annotations, "sinipi sa wikang " .. format_langs(quotelang))
end
insert(annotations, "kabuuang gawa sa wikang " .. format_langs(worklang))
end
else
local lang2 = a("lang2")
if lang2 then
insert(annotations, "sa wikang " .. format_langs(lang2))
end
end
if #annotations > 0 then
sep = nil
add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")")
end
local artist = parse_and_format_multivalued_annotated_text("artist", "at")
if artist then
add_with_sep("itinanghal ni " .. artist)
end
local feat = parse_and_format_multivalued_annotated_text("feat", "at")
if feat then
sep = " "
add_with_sep("ft. " .. feat)
end
if not format_as_cite then
add_actor_role()
end
local others = parse_and_format_annotated_text("others")
if others then
add_with_sep(others)
end
local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite)
if quoted_in then
add_with_sep("binanggit sa " .. quoted_in)
insert(tracking_categories, "Quotations using quoted-in parameter")
end
local location = parse_and_format_multivalued_annotated_text("location", "; ")
local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ")
if publisher then
if location then
add_with_sep(location) -- colon
sep = ": " -- colon
end
add_with_sep(publisher)
elseif location then
add_with_sep(location)
end
if not date_outputted then
add_date("no_paren")
end
local source = parse_and_format_multivalued_annotated_text("source", "at")
if source then
add_with_sep("nagmula sa " .. source)
end
local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite)
local by = parse_and_format_multivalued_annotated_text("by", "at")
local origtype = a("deriv") or "salin"
if original or by then
add_with_sep(origtype .. " ng " .. (original or "orihinal") .. (by and " ni " .. by or ""))
end
-- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly
-- given.
local origlang = a("origlang")
local origworklang = a("origworklang")
local origlangtext, origworklangtext
if origlang then
origlangtext = "in " .. format_langs(origlang)
end
if origworklang then
origworklangtext = "kabuuang gawa sa " .. format_langs(origworklang)
end
if origlang or origworklang then
if original or by then
local orig_annotations = {}
if origlangtext then
insert(orig_annotations, origlangtext)
end
if origworklangtext then
insert(orig_annotations, origworklangtext)
end
sep = nil
add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")")
else
add_with_sep(origtype .. " ng orihinal" .. (origlangtext and " " .. origlangtext or ""))
if origworklangtext then
sep = nil
add_with_sep(" (" .. origworklangtext .. ")")
end
end
end
if ind ~= "" and has_newversion() then
local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true)
if formatted_new_date then
add_with_sep(formatted_new_date)
end
end
-- Fetch date_published=/year_published=/month_published= and format appropriately.
local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true)
local platform = parse_and_format_multivalued_annotated_text("platform", "at")
if formatted_date_published then
add_with_sep("nilathala " .. formatted_date_published .. (platform and " sa pamamagitan ng " .. platform or ""))
elseif platform then
add_with_sep("sa pamamagitan ng " .. platform)
end
-- From here on out, there should always be a preceding item, so we
-- can dispense with add_with_sep() and always insert the comma.
sep = nil
local function small(txt)
add(", <small>")
add(txt)
add("</small>")
end
-- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params`
-- is a string identifying the base param, or a list of such strings to check in turn. If found, the value
-- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()),
-- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`,
-- and running the resulting string through small(), which first adds a comma and then the URL in small font.
local function add_identifier(param_or_params, pretext, posttext, process)
local val = a(param_or_params)
if val then
val = (process or mw.uri.encode)(val)
small(pretext .. val .. posttext)
end
end
add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]")
add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>")
add_identifier("isbn", "", "", isbn)
add_identifier("issn", "", "", issn)
add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]")
add_identifier("lccn", "", "", lccn)
add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]")
add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]")
add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]")
add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]")
add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]")
-- add_identifier("urn", "", "", urn)
local id = a("id")
if id then
small(id)
end
archiveurl, archiveurl_fullname = aurl_with_name("archiveurl")
if archiveurl then
add(", archived from ")
local url, url_fullname = aurl_with_name("url")
if not url then
-- attempt to infer original URL from archive URL; this works at
-- least for Wayback Machine (web.archive.org) URL's
url = archiveurl:match("/(https?:.*)$")
if not url then
error(
("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname)
)
end
end
add("[" .. url .. " ang orihinal] sa ")
local archivedate, archivedate_fullname = a_with_name("archivedate")
if archivedate then
add(format_date(archivedate))
elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then
-- If the archive is from the Wayback Machine, then it already contains the date
-- Get the date and format it
local wayback_date = string.sub(archiveurl, 29, 29 + 7)
wayback_date = string.sub(wayback_date, 1, 4)
.. "-"
.. string.sub(wayback_date, 5, 6)
.. "-"
.. string.sub(wayback_date, 7, 8)
add(format_date(wayback_date))
elseif string.sub(archiveurl, 1, 21) == "https://megalodon.jp/" then
local megalodon_date = string.sub(archiveurl, 22, 25)
.. "-"
.. string.sub(archiveurl, 27, 28)
.. "-"
.. string.sub(archiveurl, 29, 30)
add(format_date(megalodon_date))
else
error(
("When |%s= is specified, |%s= must also be included"):format(
archiveurl_fullname,
archivedate_fullname
)
)
end
end
if a("accessdate") then
--Otherwise do not display here, as already used as a fallback for missing date= or year= earlier.
if (a("date") or a("nodate") or a("year")) and not a("archivedate") then
add(", retrieved " .. format_date(a("accessdate")))
end
end
local formatted_section = format_chapterlike("section", "bahagi ")
if formatted_section then
add(", ")
add(formatted_section)
end
-- video game stuff
local system = parse_and_format_annotated_text("system")
if system then
add(", " .. system)
end
local scene = parse_and_format_annotated_text("scene")
if scene then
add(", eksena: " .. scene)
end
local level = parse_and_format_annotated_text("level")
if level then
add(", level/area: " .. level)
end
local note = parse_and_format_annotated_text("note")
if note then
add(", " .. note)
end
local note_plain = parse_and_format_annotated_text("note_plain")
if note_plain then
add(" " .. note_plain)
end
-- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text.
local function handle_numeric_param(paramname, singular_desc, pretext)
local numspec = format_numeric_param(paramname, singular_desc)
if numspec then
add((pretext or "") .. numspec)
end
end
handle_numeric_param("page", a("page_prefix") or "pahina", ", ")
handle_numeric_param("column", a("column_prefix") or "hanay", ", ")
handle_numeric_param("line", a("line_prefix") or "linya", ", ")
-- FIXME: Does this make sense? What is other=?
local other = parse_and_format_annotated_text("other")
if other then
add(", " .. other)
end
end
local function add_authors(args, last_first)
-- Find maximum indexed author or last name.
local maxind = math.max(args.author.maxindex, args.last.maxindex)
-- Include max index of ancillary params so we get an error message about their use without the primary params.
local ancillary_params =
{"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"}
for _, ancillary in ipairs(ancillary_params) do
maxind = math.max(maxind, args[ancillary].maxindex)
end
local num_authors = 0
for i = 1, maxind do
local ind = i == 1 and "" or i
local author, last = args.author[i], args.last[i]
if author or last then
local this_num_authors = add_author(
author,
"author" .. ind,
args["trans-author"][i],
"trans-author" .. ind,
args.authorlink[i],
"authorlink" .. ind,
args["trans-authorlink"][i],
"trans-authorlink" .. ind,
args.first[i],
"first" .. ind,
args["trans-first"][i],
"trans-first" .. ind,
last,
"last" .. ind,
args["trans-last"][i],
"trans-last" .. ind,
last_first
)
num_authors = num_authors + this_num_authors
sep = last_first and "; " or ", "
else
for _, cant_have in ipairs(ancillary_params) do
if args[cant_have][i] then
error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind))
end
end
end
end
return num_authors
end
local function add_newversion()
-- If there's a "newversion" section, add the new-version text.
if has_newversion() then
sep = nil
--Test for new version of work.
add(SEMICOLON_SPACE)
if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as".
add(args.newversion)
elseif not args.edition2 then
if has_new_title_or_author() then
add("nilathala bilang")
else
add("muling nilathala")
end
end
add(" ")
return ""
else
return ", "
end
end
------------------- Now we start outputting text ----------------------
local need_comma = false
-- Set this now so a() works just below.
get_full_paramname = make_get_full_paramname("")
if args.brackets then
add("[")
end
bold_year = not format_as_cite
year_last = format_as_cite
formatted_date, need_date = format_date_args(
a,
get_full_paramname,
alias_map,
nil,
nil,
bold_year,
"Can we [[:Category:Requests for date|date]] this quote?",
year_last
)
-- Fetch origdate=/origyear=/origmonth= and format appropriately.
formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last)
local num_authors
if format_as_cite then
num_authors = add_authors(args, "last_first")
if author_outputted then
sep = " "
end
-- Display all the text that comes after the author, for the main portion.
postauthor("", num_authors, "format_as_cite")
author_outputted = false
sep = add_newversion()
-- Add the newversion author(s).
if args["2ndauthor"] or args["2ndlast"] then
num_authors = add_author(
args["2ndauthor"],
"2ndauthor",
nil,
nil,
args["2ndauthorlink"],
"2ndauthorlink",
nil,
nil,
args["2ndfirst"],
"2ndfirst",
nil,
nil,
args["2ndlast"],
"2ndlast",
nil,
nil,
"last_first"
)
sep = ", "
else
for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do
if args[cant_have] then
error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have))
end
end
end
-- Display all the text that comes after the author, for the "newversion" section.
postauthor(2, num_authors, "format_as_cite")
else
if formatted_date then
need_comma = true
add(formatted_date)
end
if formatted_origdate then
need_comma = true
add(SPACE_LBRAC .. formatted_origdate .. RBRAC)
end
if need_comma then
sep = ", "
end
date_outputted = true
num_authors = add_authors(args)
-- Display all the text that comes after the author, for the main portion.
postauthor("", num_authors)
author_outputted = false
sep = add_newversion()
-- Add the newversion author(s).
if args["2ndauthor"] or args["2ndlast"] then
num_authors = add_author(
args["2ndauthor"],
"2ndauthor",
nil,
nil,
args["2ndauthorlink"],
"2ndauthorlink",
nil,
nil,
args["2ndfirst"],
"2ndfirst",
nil,
nil,
args["2ndlast"],
"2ndlast",
nil,
nil
)
sep = ", "
else
for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do
if args[cant_have] then
error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have))
end
end
end
-- Display all the text that comes after the author, for the "newversion" section.
postauthor(2, num_authors)
end
if not args.nocolon then
sep = nil
add(":")
elseif args.usenodot and not args.nodot then
add(".")
end
-- Concatenate output portions to form output text.
local output_text = concat(output)
-- Remainder of code handles adding categories. We add one or more of the following categories:
--
-- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to
-- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace
-- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same
-- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances
-- because typically when there's no quotation to format, it's because it's formatted manually underneath the
-- citation, or using {{ja-x}}, {{th-x}} or similar.)
-- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace,
-- Reconstruction:, Appendix: and Citations: pages unless nocat= is given.
-- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:,
-- Appendix: and Citations: pages.
local categories = {}
local termlang = get_first_lang(args.termlang or argslang)
if args.nocat then
if format_as_cite then
insert(tracking_categories, "Citations using nocat parameter")
else
insert(tracking_categories, "Quotations using nocat parameter")
end
else
-- don't create language tracking categories for citations
if not format_as_cite then
local title
if args.pagename then -- for testing, doc pages, etc.
title = mw.title.new(args.pagename)
if not title then
error(("Bad value for `args.pagename`: '%s'"):format(args.pagename))
end
else
title = mw.title.getCurrentTitle()
end
-- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists.
local ok_to_add_cat
if title.nsText ~= "Citations" then
ok_to_add_cat = true
else
local mainspace_title = mw.title.new(title.text)
if mainspace_title and mainspace_title.exists then
ok_to_add_cat = true
end
end
if ok_to_add_cat then
insert(categories, termlang:getFullName() .. " terms with quotations")
end
end
if need_date then
local argslangobj = get_first_lang(argslang)
insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries")
end
end
return output_text .. (
not termlang and "" or
(#categories > 0 and format_categories(categories, termlang, args.sort) or "") .. (
#tracking_categories > 0
and format_categories(
tracking_categories,
termlang,
args.sort,
nil,
not page_should_be_ignored(mw.title.getCurrentTitle().fullText)
)
or ""
)
)
end
-- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical
-- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2"
-- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should
-- process this spec if type2= is being handled.
local type_alias_specs = {
av = {
{"author", "writer,writers", true},
{"chapter", "episode", true},
{"chapterurl", "episodeurl", true},
{"trans-chapter", "trans-episode", true},
{"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true},
{"chapter_series", "episode_series", true},
{"chapter_seriesvolume", "episode_seriesvolume", true},
{"chapter_number", "episode_number", true},
{"chapter_plain", "episode_plain", true},
{"volume", "season", true},
{"volumes", "seasons", true},
{"volume_plain", "season_plain", true},
{"volumeurl", "seasonurl", true},
{"platform", "network", true},
},
book = {
{"author", "3"},
{"title", "4"},
{"url", "5"},
{"year", "2"},
{"page", "6"},
{"text", "7"},
{"t", "8"},
},
journal = {
{"year", "2"},
{"author", "3"},
{"chapter", "title,article,4", true},
{"chapterurl", "titleurl,articleurl", true},
{"trans-chapter", "trans-title,trans-article", true},
{"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true},
{"chapter_series", "title_series,article_series", true},
{"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true},
{"chapter_number", "title_number,article_number", true},
{"chapter_plain", "title_plain,article_plain", true},
{"title", "journal,magazine,newspaper,work,5", true},
{"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true},
{"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true},
{"url", "6,journalurl,magazineurl,newspaperurl,workurl", true},
{"page", "7"},
{"source", "newsagency,news_agency", true},
{"text", "8"},
{"t", "9"},
},
}
-- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of
-- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings
-- seen.
local function process_type_aliases(args, typ, newversion, alias_map)
local ind = newversion and "2" or ""
local deprecated = ine(args.lang)
if not type_alias_specs[typ] then
local possible_values = {}
for possible, _ in pairs(type_alias_specs) do
insert(possible_values, possible)
end
sort(possible_values)
error(
("Unrecognized value '%s' for type%s=; possible values are %s"):format(
typ,
ind,
concat(possible_values, ",")
)
)
end
for _, alias_spec in ipairs(type_alias_specs[typ]) do
local canon, aliases, with_newversion = unpack(alias_spec)
if with_newversion or not newversion then
canon = canon .. ind
aliases = split(aliases, ",", true)
local saw_alias = nil
for _, alias in ipairs(aliases) do
if alias:match("^%d+$") then
alias = tonumber(alias)
if deprecated then
alias = alias - 1
end
else
alias = alias .. ind
end
if args[alias] then
if saw_alias == nil then
saw_alias = alias
else
error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias))
end
end
end
if saw_alias and (not newversion or type(saw_alias) == "string") then
if args[canon] then
error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon))
end
args[canon] = args[saw_alias]
-- Wipe out the original after copying. This is important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_alias] = nil
alias_map[canon] = saw_alias
end
end
end
end
-- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores.
local function clone_args(direct_args, parent_args)
local args = {}
-- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is
-- specified but is blank, it will still override the parent arg (with nil).
for pname, param in pairs(parent_args) do
-- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]]
track("param/" .. pname)
args[pname] = ine(param)
end
-- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to
-- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and
-- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias
-- processing, saying that title= and its alias album= are both present.
local ignores = ine(direct_args.ignore)
if ignores then
for ignore in gsplit(ignores, "%s*,%s*") do
args[ignore] = nil
end
end
local alias_map = {}
local other_controls = {}
-- noroman
local noroman = ine(direct_args.noroman)
if noroman then
other_controls.overrides = other_controls.overrides or {}
for param in gsplit(noroman, "%s*,%s*") do
other_controls.overrides[param] = (other_controls.overrides[param] or {})
other_controls.overrides[param].noroman = true
end
end
-- Process internally-specified aliases using type= or type2=.
local typ = args.type or direct_args.type
if typ then
process_type_aliases(args, typ, false, alias_map)
end
local typ2 = args.type2 or direct_args.type2
if typ2 then
process_type_aliases(args, typ2, true, alias_map)
end
-- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which
-- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an
-- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for
-- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or
-- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias
-- must be specified before the journal/work -> title alias.
--
-- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so
-- that when we would display an error message about DEST, we display SOURCE instead.
--
-- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up
-- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does
-- this).
--
-- FIXME: Delete this once we've converted all alias processing to internal.
local aliases = ine(direct_args.alias)
if aliases then
-- Allow and discard a trailing semicolon, to make managing multiple aliases easier.
aliases = ugsub(aliases, "%s*;$", "")
for alias_spec in gsplit(aliases, "%s*;%s*") do
local alias_spec_parts = split(alias_spec, "%s*:%s*")
if #alias_spec_parts ~= 2 then
error(("Alias spec '%s' should have one colon in it"):format(alias_spec))
end
local dest, sources = unpack(alias_spec_parts)
sources = split(sources, "%s*,%s*")
local saw_source = nil
for _, source in ipairs(sources) do
if source:match("^%d+$") then
source = tonumber(source)
end
if args[source] then
if saw_source == nil then
saw_source = source
else
error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source))
end
end
end
if saw_source then
if args[dest] then
error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest))
end
args[dest] = args[saw_source]
-- Wipe out the original after copying. This important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_source] = nil
alias_map[dest] = saw_source
end
end
end
-- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen
-- in parent_args (they are params we overwrite in the direct args).
local error_ifs = ine(direct_args.error_if)
if error_ifs then
for error_if in gsplit(error_ifs, "%s*,%s*") do
if ine(parent_args[error_if]) then
error(
("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format(
error_if,
ine(parent_args[error_if])
)
)
end
end
end
for pname, param in pairs(direct_args) do
-- ignore control params
if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then
args[pname] = ine(param)
end
end
return args, alias_map, other_controls
end
local function get_args(frame_args, parent_args, require_lang)
-- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is
-- wasteful of memory.
local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args)
local deprecated = ine(parent_args.lang)
local alias_of_t = {alias_of = "t"}
local boolean = {type = "boolean"}
local language_sublist = {type = "language", sublist = true}
local list_allow_holes = {list = true, allow_holes = true}
local script = {type = "script"}
-- First, the "single" params that don't have FOO2 or FOOn versions.
local params = {
[deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"},
["lang2"] = language_sublist,
["newversion"] = true,
["author"] = list_allow_holes,
["2ndauthor"] = true,
["trans-author"] = list_allow_holes,
["authorlink"] = list_allow_holes,
["2ndauthorlink"] = true,
["trans-authorlink"] = list_allow_holes,
["first"] = list_allow_holes,
["2ndfirst"] = true,
["trans-first"] = list_allow_holes,
["last"] = list_allow_holes,
["2ndlast"] = true,
["trans-last"] = list_allow_holes,
["nocat"] = boolean,
["nocolon"] = boolean,
-- quote params
text = true,
passage = {alias_of = "text"},
tr = true,
transliteration = {alias_of = "tr"},
ts = true,
transcription = {alias_of = "ts"},
norm = true,
normalization = {alias_of = "norm"},
sc = script,
normsc = script,
sort = true,
subst = true,
footer = true,
lit = true,
t = true,
translation = alias_of_t,
gloss = alias_of_t,
lb = true,
brackets = boolean,
-- original quote params
origtext = true,
origtr = true,
origts = true,
orignorm = true,
origsc = script,
orignormsc = script,
origsubst = true,
origlb = true,
usenodot = boolean,
nodot = boolean,
inline = boolean,
asquote = boolean,
ascite = boolean,
}
-- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to
-- allow PARAMN variants for any N.
local function add_with_2(param, value)
params[param] = value
params[param .. "2"] = value
end
local function alias_with_2(alias, canon)
params[alias] = {alias_of = canon}
params[alias .. "2"] = {alias_of = canon .. "2"}
end
for _, param12 in ipairs{
"worklang",
"termlang",
"origlang",
"origworklang"
} do
add_with_2(param12, language_sublist)
end
-- Then the newversion params (which have FOO2 versions).
for _, param12 in ipairs{
-- author-like params; author params themselves are either list params (author=, last=, etc.) or single params
-- (2ndauthor=, 2ndlast=, etc.)
"coauthors",
"quotee",
"tlr",
"editor",
"editors",
"mainauthor",
"compiler",
"compilers",
"director",
"directors",
"lyricist",
"lyrics-translator",
"composer",
"role",
"actor",
"artist",
"feat",
-- author control params
"default-authorlabel",
"authorlabel",
-- title
"title",
"trans-title",
"series",
"seriesvolume",
"notitle",
-- entry
"entry",
"entryurl",
"trans-entry",
-- chapter
"chapter",
"chapterurl",
"chapter_number",
"chapter_plain",
"chapter_series",
"chapter_seriesvolume",
"trans-chapter",
"chapter_tlr",
-- section
"section",
"sectionurl",
"section_number",
"section_plain",
"section_series",
"section_seriesvolume",
"trans-section",
-- other video-game params
"system",
"scene",
"level",
-- URL
"url",
"urls",
"archiveurl",
-- edition
"edition",
"edition_plain",
-- ID params
"bibcode",
"doi",
"isbn",
"issn",
"jstor",
"lccn",
"oclc",
"ol",
"pmid",
"pmcid",
"ssrn",
"urn",
"id",
-- misc date params; most date params handled below
"archivedate",
"accessdate",
"nodate",
-- numeric params handled below
-- other params
"type",
"genre",
"format",
"medium",
"others",
"quoted_in",
"location",
"publisher",
"original",
"by",
"deriv",
"note",
"note_plain",
"other",
"source",
"platform",
} do
add_with_2(param12, true)
end
-- Then the aliases of newversion params (which have FOO2 versions).
for _, param12_aliased in ipairs{
{"role", "roles"},
{"role", "speaker"},
{"tlr", "tlrs"},
{"tlr", "translator"},
{"tlr", "translators"},
{"chapter_tlr", "chapter_tlrs"},
{"chapter_tlr", "chapter_translator"},
{"chapter_tlr", "chapter_translators"},
{"doi", "DOI"},
{"isbn", "ISBN"},
{"issn", "ISSN"},
{"jstor", "JSTOR"},
{"lccn", "LCCN"},
{"oclc", "OCLC"},
{"ol", "OL"},
{"pmid", "PMID"},
{"pmcid", "PMCID"},
{"ssrn", "SSRN"},
{"urn", "URN"},
} do
local canon, alias = unpack(param12_aliased)
alias_with_2(alias, canon)
end
-- Then the date params.
for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do
local pref, suf = unpack(datelike)
for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do
add_with_2(pref .. arg .. suf, true)
end
end
local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"}
-- Then the numeric params.
for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do
for _, suf in ipairs(numeric_param_suffixes) do
add_with_2(numeric .. suf, true)
end
end
-- And the aliases of numeric params.
for _, numeric_aliased in ipairs{{"volume", "vol"}} do
local canon, alias = unpack(numeric_aliased)
for _, suf in ipairs(numeric_param_suffixes) do
alias_with_2(alias .. suf, canon .. suf)
end
end
return process_params(cloned_args, params), alias_map, other_controls
end
local function get_origtext_params(args)
local origtext, origtextlang, origsc, orignormsc
if args.origtext then
-- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or
-- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology
-- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been
-- eliminated.)
origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$")
if not origtextlang then
-- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL.
origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$")
end
if not origtextlang then
error("origtext= should begin with a language code prefix")
end
origtextlang = get_lang(origtextlang, nil, "allow etym") or
error("origtext= should begin with a language code prefix")
origsc = args.origsc
orignormsc = args.orignormsc
else
for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do
if args[noparam] then
error(("Cannot specify %s= without origtext="):format(noparam))
end
end
end
return origtext, origtextlang, origsc, orignormsc
end
local function get_quote(args, is_cite)
local text = args.text
local gloss = args.t
local tr = args.tr
local ts = args.ts
local norm = args.norm
local sc = args.sc
local normsc = args.normsc
-- Fetch original-text parameters.
local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args)
-- If any quote-related args are present, display the actual quote; otherwise, display nothing.
if text or gloss or tr or ts or norm or args.origtext then
-- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages
-- in any case in source() if the language is omitted.
local lang = get_first_lang(args[1] or args.lang)
local termlang = args.termlang and get_first_lang(args.termlang) or lang
local usex_data = {
lang = lang,
termlang = termlang,
usex = text,
sc = sc,
translation = gloss,
normalization = norm,
normsc = normsc,
transliteration = tr,
transcription = ts,
brackets = args.brackets,
subst = args.subst,
lit = args.lit,
footer = args.footer,
qq = parse_and_format_labels(args.lb, lang),
quote = "quote-meta",
orig = origtext,
origlang = origtextlang,
origsc = origsc,
orignorm = args.orignorm,
orignormsc = orignormsc,
origtr = args.origtr,
origts = args.origts,
origsubst = args.origsubst,
origqq = parse_and_format_labels(args.origlb, lang),
noreq = args.noreq,
nocat = is_cite or args.nocat,
}
if args.inline then
-- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text
usex_data.footer = nil
usex_data.inline = 1
text = format_usex(usex_data)
if text then
text = " “" .. text .. "”"
else
text = ""
end
if args.footer then
text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>"
end
else
text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>"
end
elseif args.footer then
text = "<dl><dd>" .. args.footer .. "</dd></dl>"
end
return text
end
-- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary
-- interface for {{quote-*}} templates.
function export.quote_t(frame)
local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang")
if args.ascite then
return export.cite_t(frame)
end
return show_quote(args, alias_map, other_controls)
end
function show_quote(args, alias_map, other_controls)
local parts = {}
insert(parts, '<div class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, nil, other_controls))
insert(parts, "</span>")
insert(parts, get_quote(args))
insert(parts, "</div>")
local retval = concat(parts)
return deprecated and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
}) or retval
end
-- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary
-- interface for {{cite-*}} templates.
function export.cite_t(frame)
local parent_args = {}
for k, v in pairs(frame:getParent().args) do
parent_args[k] = v
end
-- use "und" as lang if none provided
if parent_args[1] == nil then
parent_args[1] = "und"
end
local args, alias_map, other_controls = get_args(frame.args, parent_args)
if args.asquote then
return show_quote(args, alias_map, other_controls)
end
return show_cite(args, alias_map, other_controls)
end
function show_cite(args, alias_map, other_controls)
local parts = {}
-- don't nag for translations
if args.text and not args.t then
args.noreq = 1
end
local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0
if len_visible == 0 then
if not args.t or args.t == "-" then
args.nocolon = true
end
elseif args.inline == nil then
args.inline = not (
args.block_text
or len_visible > 300
or (args.t and not args.t == "-" and len_visible < 80)
or string.match(args.text, "<br>")
)
end
insert(parts, '<span class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, "format_as_cite", other_controls))
insert(parts, "</span>")
insert(parts, get_quote(args, "is_cite"))
insert(parts, "</span>")
local retval = concat(parts)
return deprecated
and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
})
or retval
end
-- External interface, meant to be called from a template.
function export.call_quote_template(frame)
return export.call_template(frame)
end
-- External interface, for calling a template with overloaded parameters.
function export.overload(frame)
local iargs, overloaded_args = process_params(frame.args, {
[1] = {required = true}
}, true)
local parent_args = frame:getParent().args
for k, v in pairs(parent_args) do
overloaded_args[k] = v
end
return frame:expandTemplate{title = iargs[1], args = overloaded_args}
end
-- External interface, meant to be called from a template.
function export.call_template(frame)
local parameter_sublist = {type = "parameter", sublist = true}
local iargs, other_direct_args = process_params(frame.args, {
["template"] = true,
["textparam"] = parameter_sublist,
["pageparam"] = parameter_sublist,
["propagateparams"] = parameter_sublist,
["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently.
}, true)
local function fetch_param(source, params)
for _, param in ipairs(params) do
if source[param] then
return source[param]
end
end
return nil
end
local params = {
["text"] = true,
["passage"] = true,
["footer"] = true, -- always propagates, but gets special formatting
}
-- paramaters that can be used during template declaration or included in template calls
-- if the template is called with param=- it will set any declared value to nil
local always_propagate = {
["brackets"] = true,
["usenodot"] = true,
["nodot"] = true,
["ascite"] = true,
["asquote"] = true,
}
for k,v in pairs(always_propagate) do
params[k] = v
end
local textparam = iargs.textparam or {}
for _, param in ipairs(textparam) do
params[param] = true
end
local pageparam = iargs.pageparam or {}
local pageparam1 = pageparam[1]
if pageparam1 ~= nil then
params["page"], params["pages"] = true, true
for _, param in ipairs(pageparam) do
params[param] = true
end
end
local allowparams, allow_all, list = iargs.allowparams, false
if allowparams ~= nil then
for _, allow in ipairs(allowparams) do
local param = allow:match("^(.*):list$")
if param then
if list == nil then
list = {list = true}
end
params[scribunto_parameter_key(param)] = list
elseif allow == "*" then
track("no parameter checking")
allow_all = true
else
params[scribunto_parameter_key(allow)] = true
end
end
else
local parent = frame:getParent()
local template_name = parent:getTitle()
local template_title = new_title(template_name)
local content = template_title:getContent()
local allowed_params, seen = {}, {}
-- Detect all params used by the parent template. param:get_name() takes the
-- parent frame arg table as an argument so that preprocessing will take
-- them into account, since it will matter if the name contains another
-- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change
-- depending on the value for bar=). `seen` memoizes results based on the
-- raw parameter text (which is stored as a string in the parameter object),
-- which avoids unnecessary param:get_name() calls, which are non-trivial.
for param in find_parameters(content) do
local raw = param.raw
if not seen[raw] then
allow = param:get_name(template_args)
params[scribunto_parameter_key(allow)] = true
seen[raw] = true
end
end
end
local propagateparams = iargs.propagateparams or {}
for _, param in ipairs(propagateparams) do
params[param] = true
end
local parent_args = frame:getParent().args
local args = process_params(parent_args, params, allow_all)
parent_args = shallow_copy(parent_args)
if textparam[1] ~= "-" then
other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam)
end
if not (pageparam1 == nil or pageparam1 == "-") then
other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil
other_direct_args.pages = args.pages or other_direct_args.pages or nil
if other_direct_args.page == "-" then
other_direct_args.page = nil
end
if other_direct_args.pages == "-" then
other_direct_args.pages = nil
end
end
if args.footer then
other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}}
end
for param, _ in pairs(always_propagate) do
if args[param] == "-" then
other_direct_args[param] = nil
else
other_direct_args[param] = args[param] or other_direct_args[param] or nil
end
end
-- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to
-- the actual {{quote-*}} code.
if other_direct_args.authorlink == "-" then
other_direct_args.authorlink = nil
end
for _, param in ipairs(propagateparams) do
if args[param] then
other_direct_args[param] = args[param]
end
end
return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args}
end
local paramdoc_param_replacements = {
passage = {
param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}",
param_no_synonym = "{{para|text}} or {{para|passage}}",
text = [=[
* <<params>> – the passage to be quoted.]=],
},
page = {
param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}",
param_no_synonym = "{{para|page}} or {{para|pages}}",
text = [=[
* <<params>> – '''mandatory in some cases''': the page number(s) quoted from. When quoting a range of pages, note the following:
** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}.
** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to the online version of the work.]=],
},
page_with_roman_preface = {
param_with_synonym = {"inherit", "page"},
param_no_synonym = {"inherit", "page"},
text = [=[
* <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following:
** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}.
** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to the online version of the work.]=],
},
chapter = {
param_with_synonym = "<<synonym>> or {{para|chapter}}",
param_no_synonym = "{{para|chapter}}",
text = [=[
* <<params>> – the name of the chapter quoted from.]=],
},
roman_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in uppercase Roman numerals.]=],
},
arabic_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in Arabic numerals.]=],
},
trailing_params = {
text = [=[
* {{para|footer}} – a comment on the passage quoted.
* {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=],
},
}
function export.paramdoc(frame)
local parargs = frame:getParent().args
local args = process_params(parargs, {
[1] = true,
})
local text = args[1]
local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym)
local function sub_param(synonym)
local subbed_paramtext
if synonym then
subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}")
else
subbed_paramtext = paramtext_no_synonym
end
return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext))))
end
text = text:gsub("<<" .. pattern_escape(param) .. ">>", function()
return sub_param()
end)
text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param)
end
local function fetch_text(param_to_replace, key)
local spec = paramdoc_param_replacements[param_to_replace]
local val = spec[key]
if type(val) == "string" then
return val
end
if type(val) == "table" and val[1] == "inherit" then
return fetch_text(val[2], key)
end
error(
"Internal error: Unrecognized value for param '"
.. param_to_replace
.. "', key '"
.. key
.. "': "
.. mw.dumpObject(val)
)
end
for param_to_replace, spec in pairs(paramdoc_param_replacements) do
if not spec.param_no_synonym then
-- Text to substitute directly.
text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function()
return frame:preprocess(fetch_text(param_to_replace, "text"))
end)
else
do_param_with_optional_synonym(
param_to_replace,
fetch_text(param_to_replace, "text"),
fetch_text(param_to_replace, "param_with_synonym"),
fetch_text(param_to_replace, "param_no_synonym")
)
end
end
-- Remove final newline so template code can add a newline after invocation
text = text:gsub("\n$", "")
return text
end
return export
gxqy3csu5np5v5aw9y5skz751jyhobf
Module:gender and number/data
828
33791
178361
170504
2026-10-23T02:25:20Z
GinawaSaHapon
3989
178361
Scribunto
text/plain
local data = {}
-- A list of all possible "parts" that a specification can be made out of. For each part, we list the class it's in
-- (gender, animacy, etc.), the associated category (if any) and the display form. In a given gender/number spec, only
-- one part of each class is allowed. `display` is how the code is diplayed to the user and should normally be wrapped
-- in <abbr title="tooltip">...</abbr> with an explanatory tooltip. If not, it will automatically be wrapped in this
-- fashion. If `req` is true, a category "Requests for TYPE in LANG entries" will be generated, except for the code "?",
-- which is special-cased; TYPE is "gender" unless the POS is "verb", in which case it is "aspect".
--TLCHANGE the "POS" automatically has the pang-angkop in it, no need to add it here
data.codes = {
["?"] = {type = "other", req = true, display = '<abbr title="walang tinukoy na kasarian">?</abbr>'},
-- FIXME: The following should be either eliminated in favor of g! or converted to a general "gender/number unattested".
["?!"] = {type = "other", display = "di-kumpirmado ang kasarian"},
-- Genders
--TLCHANGE ["m"] = {type = "gender", cat = "masculine POS", display = '<abbr title="masculine gender">m</abbr>'},
["m"] = {type = "gender", cat = "na POS panlalaki", display = '<abbr title="panlalaki">l</abbr>'},
["l"] = {type = "gender", cat = "na POS panlalaki", display = '<abbr title="panlalaki">l</abbr>'}, --TLCHANGE
--TLCHANGE ["f"] = {type = "gender", cat = "feminine POS", display = '<abbr title="feminine gender">f</abbr>'},
["f"] = {type = "gender", cat = "na POS pambabae", display = '<abbr title="pambabae">b</abbr>'},
["b"] = {type = "gender", cat = "na POS pambabae", display = '<abbr title="pambabae">b</abbr>'}, --TLCHANGE
--TLCHANGE ["n"] = {type = "gender", cat = "neuter POS", display = '<abbr title="neuter gender">n</abbr>'},
["n"] = {type = "gender", cat = "na POS di-tiyak", display = '<abbr title="di-tiyak">dt</abbr>'},
["bl"] = {type = "gender", cat = "na POS di-tiyak", display = '<abbr title="di-tiyak">dt</abbr>'}, --TLCHANGE
--TLCHANGE ["c"] = {type = "gender", cat = "common-gender POS", display = '<abbr title="common gender">c</abbr>'},
["c"] = {type = "gender", cat = "na POS kasariang karaniwan", display = '<abbr title="karaniwan">k</abbr>'},
["k"] = {type = "gender", cat = "na POS kasariang karaniwan", display = '<abbr title="karaniwan">k</abbr>'}, --TLCHANGE
--TLCHANGE ["gneut"] = {type = "gender", cat = "gender-neutral POS", display = "gender-neutral"},
["gneut"] = {type = "gender", cat = "na POS anumang kasarian", display = "anuman"},
["kneut"] = {type = "gender", cat = "na POS anumang kasarian", display = "anuman"}, --TLCHANGE
["g!"] = {type = "gender", display = "di-kumpirmado ang kasarian"},
["g?"] = {type = "gender", req = true, display = "walang tinukoy na kasarian"},
-- Animacy
-- Animate = either animal or personal (for Russian, etc.)
["an"] = {type = "animacy", cat = "animate POS", display = '<abbr title="buhay">bhy</abbr>'},
["in"] = {type = "animacy", cat = "inanimate POS", display = '<abbr title="di-buhay">dbhy</abbr>'},
-- Animal (for Ukrainian, Belarusian, Polish, etc.)
["anml"] = {type = "animacy", cat = "animal POS", display = "panghayop"},
-- Personal (for Ukrainian, Belarusian, Polish, etc.)
["pr"] = {type = "animacy", cat = "personal POS", display = '<abbr title="pantao">tao</abbr>'},
["np"] = {type = "animacy", cat = "nonpersonal POS", display = '<abbr title="di-pantao">dtao</abbr>'},
["an!"] = {type = "animacy", display = "di-kumpirmado ang buhay"},
["an?"] = {type = "animacy", req = true, display = "walang tinukoy na buhay"},
-- Virility (for Polish)
["vr"] = {type = "virility", cat = "virile POS", display = '<abbr title="panlalaki (= taong lalaki)">tl</abbr>'},
["nv"] = {type = "virility", cat = "nonvirile POS", display = '<abbr title="di-panlalaki (= bukod sa taong lalaki)">dtl</abbr>'},
-- Numbers
["s"] = {type = "number", display = '<abbr title="isahan">isa</abbr>'},
["d"] = {type = "number", cat = "dualia tantum", display = '<abbr title="dalawahan">dalawa</abbr>'},
["p"] = {type = "number", cat = "pluralia tantum", display = '<abbr title="maramihan">marami</abbr>'},
["num!"] = {type = "number", display = "di-kumpirmado ang kailanan"},
["num?"] = {type = "number", req = true, display = "walang tinukoy na kailanan"},
-- Verb qualifiers
["impf"] = {type = "aspect", cat = "imperfective POS", display = '<abbr title="aspektong nagaganap">nggp</abbr>'},
["pf"] = {type = "aspect", cat = "perfective POS", display = '<abbr title="aspektong naganap">ngp</abbr>'},
["asp!"] = {type = "aspect", display = "di-kumpirmado ang aspekto"},
["asp?"] = {type = "aspect", req = true, display = "walang tinukoy na aspekto"},
}
-- Combined codes that are equivalent to giving multiple specs. `mf` is the same as specifying two separate specs,
-- one with `m` in it and the other with `f`. `mfbysense` is similar but is used for nouns that can be either masculine
-- or feminine according as to whether they refer to masculine or feminine beings.
data.combinations = {
["mf"] = {codes = {"m", "f"}},
["mfequiv"] = {codes = {"m", "f"}, display = '<abbr title="walang epekto sa kahulugan ang kasarian">parehong kahulugan</abbr>'},
["mfbysense"] = {codes = {"m", "f"}, cat = "masculine and feminine POS by sense",
display = '<abbr title="ayon sa kasarian ng tinutukoy">ayon sa kahulugan</abbr>'},
["biasp"] = {codes = {"impf", "pf"}},
}
-- Categories when multiple gender/number codes of a given type occur in different specs (two or more of the same type
-- cannot occur in a single spec).
data.multicode_cats = {
["gender"] = "POS with multiple genders",
["animacy"] = "POS with multiple animacies",
["aspect"] = "biaspectual POS",
}
return data
rmyshfwkbfyd8c2pt6axv1zq8m8ebhq
Module:interproject/style.css
828
34625
178365
167671
2026-10-23T05:43:44Z
GinawaSaHapon
3989
178365
sanitized-css
text/css
/* note: these styles are also used by some legacy templates that do not use the module. thus a full redesign should probably use a new class. */
.interproject-box {
font-size: 90%;
width: 250px;
padding: 5px;
text-align: left;
background: var(--wikt-palette-paleblue, #f9f9f9);
border: var(--border-color-base, #aaa) 1px solid;
display: flex;
flex-direction: row;
align-items: center;
}
.interproject-box-logo {
min-width: 44px;
display: flex;
align-items: center;
justify-content: center;
}
/* override inline styles */
.interproject-box > div:first-child {
float: none !important;
flex: none;
}
.interproject-box > div:nth-child(2) {
margin-left: 0.55em !important;
}
/* allow {{commonscat}} to be smaller in Vector skin */
body.skin-vector:not(.skin-vector-2022) .interproject-box .vector-hide {
display: none;
}
body.skin-vector:not(.skin-vector-2022) .interproject-box .vector-inline-block {
display: inline-block;
margin-left: 0 !important;
}
@media screen and (max-width: 719px) { /* >=720px is the crossover point for floats to work */
.interproject-box {
box-sizing: border-box;
line-height: 1.5;
width: 100%;
max-width: 100%;
padding: 6px;
}
}
m9k5xbng6wuwr54i1j6n3x45wmrntyz
Module:es-headword
828
34963
178357
177520
2026-10-23T00:59:15Z
GinawaSaHapon
3989
178357
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()
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 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] then
for key, val in pairs(pos_functions[poscat].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] and pos_functions[poscat].pos_category or poscat,
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] and pos_functions[poscat].redlink_pos or true,
}
if pagename:find("^%-") and poscat ~= "suffix forms" then
data.is_suffix = true
data.pos_category = "suffixes"
data.checkredlinks = true
local singular_poscat = m_en_utilities.singularize(poscat)
insert(data.categories, langname .. " " .. singular_poscat .. "-forming suffixes")
insert(data.inflections, {label = singular_poscat .. "-forming suffix"})
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 .. " terms spelled with " .. uupper(ch))
end
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data)
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 decorations 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)
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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
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 = "feminine-only"})
insert_inflection(feminine_plurals, "feminine plural", "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_decorations(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_decorations(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", "masculine singular before a noun")
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_decorations(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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
else
-- Make sure there are feminines given and not same as lemma.
if not fem_like_lemma then
insert_inflection(feminines, "feminine", "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, "plural", "p")
else
insert_inflection(masculine_plurals, "masculine and feminine plural", "p")
end
else
insert_inflection(masculine_plurals, "masculine plural", "m|p")
insert_inflection(feminine_plurals, "feminine plural", "f|p")
end
end
end
parse_and_insert_inflection(data, args, "comp", "comparative")
parse_and_insert_inflection(data, args, "sup", "superlative")
parse_and_insert_inflection(data, args, "dim", "diminutive")
parse_and_insert_inflection(data, args, "aug", "augmentative")
if args.irreg and is_superlative then
insert(data.categories, langname .. " irregular superlative " .. category_plpos)
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["adjectives"] = {
params = get_adjective_params("base"),
func = do_adjective,
}
pos_functions["past participles"] = {
params = get_adjective_params("part"),
func = do_adjective,
redlink_pos = "participles",
}
pos_functions["determiners"] = {
params = get_adjective_params("det"),
func = do_adjective,
}
pos_functions["pronouns"] = {
params = get_adjective_params("pron"),
func = do_adjective,
}
pos_functions["comparative adjectives"] = {
params = get_adjective_params("comp"),
func = do_adjective,
pos_category = "adjectives",
}
pos_functions["superlative adjectives"] = {
params = get_adjective_params("sup"),
func = function(args, data)
do_adjective(args, data, true)
end,
pos_category = "adjectives",
}
-----------------------------------------------------------------------------------------
-- Adverbs --
-----------------------------------------------------------------------------------------
pos_functions["adverbs"] = {
params = {
["sup"] = list_param, --superlative(s)
},
func = function(args, data)
parse_and_insert_inflection(data, args, "sup", "superlative")
end,
}
-----------------------------------------------------------------------------------------
-- Numerals --
-----------------------------------------------------------------------------------------
pos_functions["cardinal numbers"] = {
params = {
["f"] = list_param, --feminine(s)
["mapoc"] = list_param, --masculine apocopated form(s)
},
func = function(args, data)
insert(data.categories, 1, langname .. " cardinal numbers")
if args.f[1] then
insert(data.genders, "m")
parse_and_insert_inflection(data, args, "f", "feminine")
end
parse_and_insert_inflection(data, args, "mapoc", "masculine before a noun")
end,
pos_category = "numerals",
}
-----------------------------------------------------------------------------------------
-- 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)
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("plural only")})
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 m_headword_utilities.termobj_has_decorations(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, langname .. " uncountable " .. category_plpos)
-- If plural forms were given explicitly, then show "usually"
if plurals[1] then
insert(data.inflections, {label = "usually " .. glossary_link("uncountable")})
insert(data.categories, langname .. " countable " .. category_plpos)
else
insert(data.inflections, {label = glossary_link("uncountable")})
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("countable") .. " and " .. glossary_link("uncountable")})
insert(data.categories, langname .. " uncountable " .. category_plpos)
insert(data.categories, langname .. " countable " .. category_plpos)
elseif plurals[1] then
-- Countable nouns
insert(data.categories, langname .. " countable " .. category_plpos)
else
-- Uncountable nouns
insert(data.categories, langname .. " uncountable " .. category_plpos)
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 mfpls = 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(mfpls) do
local accel
if #mfpls == #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_decorations(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_decorations(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, "maramihan", "p")
insert_noun_inflection(feminines, "pambabae", "f")
insert_noun_inflection(feminine_plurals, "pambabae maramihan")
insert_noun_inflection(masculines, "panlalaki")
insert_noun_inflection(masculine_plurals, "panlalaki maramihan")
parse_and_insert_noun_inflection("dim", "pampaliit")
parse_and_insert_noun_inflection("aug", "pampalaki")
parse_and_insert_noun_inflection("pej", "mapanira")
parse_and_insert_noun_inflection("dem", "ngalang panlipi")
parse_and_insert_noun_inflection("fdem", "pambabaeng ngalang panlipi")
-- 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 .. " nouns with irregular gender")
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["nouns"] = {
params = get_noun_params(),
func = do_noun,
}
pos_functions["proper nouns"] = {
params = get_noun_params("is proper"),
func = function(args, data)
do_noun(args, data, "is proper")
end,
}
-----------------------------------------------------------------------------------------
-- Verbs --
-----------------------------------------------------------------------------------------
pos_functions["verbs"] = {
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 = ("first-person singular %s"):format(label_tense),
}
elseif has_3s then
return {
slot = slot_tense .. "_3s",
label = ("third-person singular %s"):format(label_tense),
}
else
return {
slot = slot_tense .. "_3p",
label = ("third-person plural %s"):format(label_tense),
}
end
end
preses = do_finite("pres", "present")
prets = do_finite("pret", "preterite")
parts = {
slot = "pp_ms",
label = "past participle",
}
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 = "no " .. 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 = "no first-person singular present"})
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("impersonal")})
elseif alternant_multiword_spec.only3sp then
insert(data.inflections, {label = "third-person only"})
elseif alternant_multiword_spec.only3p then
insert(data.inflections, {label = "third-person plural only"})
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["phrases"] = {
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", "masculine")
parse_and_insert_inflection(data, args, "f", "feminine")
end,
}
-----------------------------------------------------------------------------------------
-- Suffix forms --
-----------------------------------------------------------------------------------------
pos_functions["suffix forms"] = {
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 .. "-forming suffix")
end
insert(data.inflections, {label = "non-lemma form of " .. require("Module:table").serialCommaJoin(suffix_type, {conj = "or"})})
end,
}
return export
hm5ehyt7q1ljb9e54qfhixuqzh096iz
178358
178357
2026-10-23T01:02:03Z
GinawaSaHapon
3989
178358
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()
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 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] then
for key, val in pairs(pos_functions[poscat].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] and pos_functions[poscat].pos_category or poscat,
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] and pos_functions[poscat].redlink_pos or true,
}
if pagename:find("^%-") and poscat ~= "suffix forms" then
data.is_suffix = true
data.pos_category = "suffixes"
data.checkredlinks = true
local singular_poscat = m_en_utilities.singularize(poscat)
insert(data.categories, langname .. " " .. singular_poscat .. "-forming suffixes")
insert(data.inflections, {label = singular_poscat .. "-forming suffix"})
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 .. " terms spelled with " .. uupper(ch))
end
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data)
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 decorations 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)
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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
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 = "feminine-only"})
insert_inflection(feminine_plurals, "feminine plural", "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_decorations(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_decorations(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", "panlalaki isahan bago pangngalan")
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_decorations(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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
else
-- Make sure there are feminines given and not same as lemma.
if not fem_like_lemma then
insert_inflection(feminines, "feminine", "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, "plural", "p")
else
insert_inflection(masculine_plurals, "masculine and feminine plural", "p")
end
else
insert_inflection(masculine_plurals, "masculine plural", "m|p")
insert_inflection(feminine_plurals, "feminine plural", "f|p")
end
end
end
parse_and_insert_inflection(data, args, "comp", "pahambing")
parse_and_insert_inflection(data, args, "sup", "pasukdol")
parse_and_insert_inflection(data, args, "dim", "pampaliit")
parse_and_insert_inflection(data, args, "aug", "pampalaki")
if args.irreg and is_superlative then
insert(data.categories, langname .. " irregular superlative " .. category_plpos)
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["adjectives"] = {
params = get_adjective_params("base"),
func = do_adjective,
}
pos_functions["past participles"] = {
params = get_adjective_params("part"),
func = do_adjective,
redlink_pos = "participles",
}
pos_functions["determiners"] = {
params = get_adjective_params("det"),
func = do_adjective,
}
pos_functions["pronouns"] = {
params = get_adjective_params("pron"),
func = do_adjective,
}
pos_functions["comparative adjectives"] = {
params = get_adjective_params("comp"),
func = do_adjective,
pos_category = "adjectives",
}
pos_functions["superlative adjectives"] = {
params = get_adjective_params("sup"),
func = function(args, data)
do_adjective(args, data, true)
end,
pos_category = "adjectives",
}
-----------------------------------------------------------------------------------------
-- Adverbs --
-----------------------------------------------------------------------------------------
pos_functions["adverbs"] = {
params = {
["sup"] = list_param, --superlative(s)
},
func = function(args, data)
parse_and_insert_inflection(data, args, "sup", "pasukdol")
end,
}
-----------------------------------------------------------------------------------------
-- Numerals --
-----------------------------------------------------------------------------------------
pos_functions["cardinal numbers"] = {
params = {
["f"] = list_param, --feminine(s)
["mapoc"] = list_param, --masculine apocopated form(s)
},
func = function(args, data)
insert(data.categories, 1, langname .. " cardinal numbers")
if args.f[1] then
insert(data.genders, "m")
parse_and_insert_inflection(data, args, "f", "pambabae")
end
parse_and_insert_inflection(data, args, "mapoc", "panlalaki bago pangngalan")
end,
pos_category = "numerals",
}
-----------------------------------------------------------------------------------------
-- 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)
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("plural only")})
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 m_headword_utilities.termobj_has_decorations(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, langname .. " uncountable " .. category_plpos)
-- If plural forms were given explicitly, then show "usually"
if plurals[1] then
insert(data.inflections, {label = "usually " .. glossary_link("uncountable")})
insert(data.categories, langname .. " countable " .. category_plpos)
else
insert(data.inflections, {label = glossary_link("uncountable")})
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("countable") .. " and " .. glossary_link("uncountable")})
insert(data.categories, langname .. " uncountable " .. category_plpos)
insert(data.categories, langname .. " countable " .. category_plpos)
elseif plurals[1] then
-- Countable nouns
insert(data.categories, langname .. " countable " .. category_plpos)
else
-- Uncountable nouns
insert(data.categories, langname .. " uncountable " .. category_plpos)
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 mfpls = 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(mfpls) do
local accel
if #mfpls == #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_decorations(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_decorations(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, "maramihan", "p")
insert_noun_inflection(feminines, "pambabae", "f")
insert_noun_inflection(feminine_plurals, "pambabae maramihan")
insert_noun_inflection(masculines, "panlalaki")
insert_noun_inflection(masculine_plurals, "panlalaki maramihan")
parse_and_insert_noun_inflection("dim", "pampaliit")
parse_and_insert_noun_inflection("aug", "pampalaki")
parse_and_insert_noun_inflection("pej", "mapanira")
parse_and_insert_noun_inflection("dem", "ngalang panlipi")
parse_and_insert_noun_inflection("fdem", "pambabaeng ngalang panlipi")
-- 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 .. " nouns with irregular gender")
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["nouns"] = {
params = get_noun_params(),
func = do_noun,
}
pos_functions["proper nouns"] = {
params = get_noun_params("is proper"),
func = function(args, data)
do_noun(args, data, "is proper")
end,
}
-----------------------------------------------------------------------------------------
-- Verbs --
-----------------------------------------------------------------------------------------
pos_functions["verbs"] = {
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 = ("first-person singular %s"):format(label_tense),
}
elseif has_3s then
return {
slot = slot_tense .. "_3s",
label = ("third-person singular %s"):format(label_tense),
}
else
return {
slot = slot_tense .. "_3p",
label = ("third-person plural %s"):format(label_tense),
}
end
end
preses = do_finite("pres", "present")
prets = do_finite("pret", "preterite")
parts = {
slot = "pp_ms",
label = "past participle",
}
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 = "no " .. 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 = "no first-person singular present"})
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("impersonal")})
elseif alternant_multiword_spec.only3sp then
insert(data.inflections, {label = "third-person only"})
elseif alternant_multiword_spec.only3p then
insert(data.inflections, {label = "third-person plural only"})
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["phrases"] = {
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", "panlalaki")
parse_and_insert_inflection(data, args, "f", "pambabae")
end,
}
-----------------------------------------------------------------------------------------
-- Suffix forms --
-----------------------------------------------------------------------------------------
pos_functions["suffix forms"] = {
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 .. "-forming suffix")
end
insert(data.inflections, {label = "non-lemma form of " .. require("Module:table").serialCommaJoin(suffix_type, {conj = "or"})})
end,
}
return export
6tameglcg4blouxe8k0bq5egoxifuqu
178359
178358
2026-10-23T01:29:04Z
GinawaSaHapon
3989
178359
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()
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 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] then
for key, val in pairs(pos_functions[poscat].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] and pos_functions[poscat].pos_category or poscat,
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] and pos_functions[poscat].redlink_pos or true,
}
if pagename:find("^%-") and poscat ~= "suffix forms" then
data.is_suffix = true
data.pos_category = "suffixes"
data.checkredlinks = true
local singular_poscat = m_en_utilities.singularize(poscat)
insert(data.categories, langname .. " " .. singular_poscat .. "-forming suffixes")
insert(data.inflections, {label = "hulaping gumagawa ng " .. 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 .. " terms spelled with " .. uupper(ch))
end
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data)
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 decorations 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)
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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
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 = "pambabae lamang"})
insert_inflection(feminine_plurals, "pambabae maramihan", "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_decorations(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_decorations(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", "panlalaki isahan bago pangngalan")
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_decorations(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("invariable")})
insert(data.categories, langname .. " indeclinable " .. category_plpos)
else
-- Make sure there are feminines given and not same as lemma.
if not fem_like_lemma then
insert_inflection(feminines, "pambabae", "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, "maramihan", "p")
else
insert_inflection(masculine_plurals, "panlalaki at pambabae maramihan", "p")
end
else
insert_inflection(masculine_plurals, "panlalaki maramihan", "m|p")
insert_inflection(feminine_plurals, "pambabae maramihan", "f|p")
end
end
end
parse_and_insert_inflection(data, args, "comp", "pahambing")
parse_and_insert_inflection(data, args, "sup", "pasukdol")
parse_and_insert_inflection(data, args, "dim", "pampaliit")
parse_and_insert_inflection(data, args, "aug", "pampalaki")
if args.irreg and is_superlative then
insert(data.categories, langname .. " irregular superlative " .. category_plpos)
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["adjectives"] = {
params = get_adjective_params("base"),
func = do_adjective,
}
pos_functions["past participles"] = {
params = get_adjective_params("part"),
func = do_adjective,
redlink_pos = "participles",
}
pos_functions["determiners"] = {
params = get_adjective_params("det"),
func = do_adjective,
}
pos_functions["pronouns"] = {
params = get_adjective_params("pron"),
func = do_adjective,
}
pos_functions["comparative adjectives"] = {
params = get_adjective_params("comp"),
func = do_adjective,
pos_category = "adjectives",
}
pos_functions["superlative adjectives"] = {
params = get_adjective_params("sup"),
func = function(args, data)
do_adjective(args, data, true)
end,
pos_category = "adjectives",
}
-----------------------------------------------------------------------------------------
-- Adverbs --
-----------------------------------------------------------------------------------------
pos_functions["adverbs"] = {
params = {
["sup"] = list_param, --superlative(s)
},
func = function(args, data)
parse_and_insert_inflection(data, args, "sup", "pasukdol")
end,
}
-----------------------------------------------------------------------------------------
-- Numerals --
-----------------------------------------------------------------------------------------
pos_functions["cardinal numbers"] = {
params = {
["f"] = list_param, --feminine(s)
["mapoc"] = list_param, --masculine apocopated form(s)
},
func = function(args, data)
insert(data.categories, 1, langname .. " cardinal numbers")
if args.f[1] then
insert(data.genders, "m")
parse_and_insert_inflection(data, args, "f", "pambabae")
end
parse_and_insert_inflection(data, args, "mapoc", "panlalaki bago pangngalan")
end,
pos_category = "numerals",
}
-----------------------------------------------------------------------------------------
-- 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)
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("plural only")})
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 m_headword_utilities.termobj_has_decorations(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 = "di-kumpirmado ang maramihan"})
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, langname .. " uncountable " .. category_plpos)
-- If plural forms were given explicitly, then show "usually"
if plurals[1] then
insert(data.inflections, {label = "madalas " .. glossary_link("uncountable")})
insert(data.categories, langname .. " countable " .. category_plpos)
else
insert(data.inflections, {label = glossary_link("uncountable")})
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("countable") .. " and " .. glossary_link("uncountable")})
insert(data.categories, langname .. " uncountable " .. category_plpos)
insert(data.categories, langname .. " countable " .. category_plpos)
elseif plurals[1] then
-- Countable nouns
insert(data.categories, langname .. " countable " .. category_plpos)
else
-- Uncountable nouns
insert(data.categories, langname .. " uncountable " .. category_plpos)
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 mfpls = 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(mfpls) do
local accel
if #mfpls == #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_decorations(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_decorations(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, "maramihan", "p")
insert_noun_inflection(feminines, "pambabae", "f")
insert_noun_inflection(feminine_plurals, "pambabae maramihan")
insert_noun_inflection(masculines, "panlalaki")
insert_noun_inflection(masculine_plurals, "panlalaki maramihan")
parse_and_insert_noun_inflection("dim", "pampaliit")
parse_and_insert_noun_inflection("aug", "pampalaki")
parse_and_insert_noun_inflection("pej", "mapanira")
parse_and_insert_noun_inflection("dem", "ngalang panlipi")
parse_and_insert_noun_inflection("fdem", "pambabaeng ngalang panlipi")
-- 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 .. " nouns with irregular gender")
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["nouns"] = {
params = get_noun_params(),
func = do_noun,
}
pos_functions["proper nouns"] = {
params = get_noun_params("is proper"),
func = function(args, data)
do_noun(args, data, "is proper")
end,
}
-----------------------------------------------------------------------------------------
-- Verbs --
-----------------------------------------------------------------------------------------
pos_functions["verbs"] = {
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 = ("isahan sa unang panauhan %s"):format(label_tense),
}
elseif has_3s then
return {
slot = slot_tense .. "_3s",
label = ("isahan sa ikatlong panauhan %s"):format(label_tense),
}
else
return {
slot = slot_tense .. "_3p",
label = ("maramihan sa ikatlong panauhan %s"):format(label_tense),
}
end
end
preses = do_finite("pres", "pangkasalukuyan")
prets = do_finite("pret", "pangnakaraan")
parts = {
slot = "pp_ms",
label = "pandiwaring pangnakaraan",
}
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 = "no " .. 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 = " walang isahang pangkasalukuyan sa unang panauhan"})
insert(data.inflections, {label = "walang pasakaling pangkasalukuyan"})
end
if alternant_multiword_spec.no_pres_stressed then
insert(data.inflections, {label = "walang nakadiin na paturol o pasakali na pangkasalukuyan"})
skip_pres_if_empty = true
end
if alternant_multiword_spec.only3s then
insert(data.inflections, {label = glossary_link("impersonal")})
elseif alternant_multiword_spec.only3sp then
insert(data.inflections, {label = "ikatlong panauhan lamang"})
elseif alternant_multiword_spec.only3p then
insert(data.inflections, {label = "maramihan sa ikatlong panauhan lamang"})
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["phrases"] = {
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", "panlalaki")
parse_and_insert_inflection(data, args, "f", "pambabae")
end,
}
-----------------------------------------------------------------------------------------
-- Suffix forms --
-----------------------------------------------------------------------------------------
pos_functions["suffix forms"] = {
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, "hulaping gumagawa ng " .. typ)
end
insert(data.inflections, {label = "anyong di-kataga ng " .. require("Module:table").serialCommaJoin(suffix_type, {conj = "o"})})
end,
}
return export
p25mn0y7oso4cka024q2ehd2zs79rqx
Padron:es-verb form of
10
35720
178373
169996
2026-10-23T06:22:51Z
GinawaSaHapon
3989
Ipinapalit ang pahina ng may nilalamang '{{#invoke:es-inflections|verb_form_of}}<!-- --><noinclude>{{documentation}}</noinclude>'
178373
wikitext
text/x-wiki
{{#invoke:es-inflections|verb_form_of}}<!--
--><noinclude>{{documentation}}</noinclude>
4a1xg9lw7gg9uzyrggfsk2bgrkig5lm
Padron:R:es:DRAE
10
37020
178377
172966
2026-10-23T06:40:03Z
GinawaSaHapon
3989
178377
wikitext
text/x-wiki
{{#invoke:quote|call_quote_template
|template=cite-web
|es
|date=15-12-2025
|work=w:Diccionario de la lengua española<t:Dictionary of the Spanish Language>
|publisher=w:Royal Spanish Academy<f:es:Real Academia Española>
|edition_plain=bersyon online 23.8.1
|entry={{{1|{{{entry|{{pagename}}}}}}}}
|entryurl={{{url|https://dle.rae.es/{{urlencode:{{{1|{{{entry|{{pagename}}}}}}}}|PATH}}{{#if:{{{2|{{{id|}}}}}}|#{{{2|{{{id|}}}}}}}}}}}
|allowparams=1,2,entry,id,url
}}<noinclude>{{documentation}}</noinclude>
mu3pd55eknjjldhkgxar7a6hgru5h9k
Padron:topN
10
38946
178369
2026-10-23T05:53:06Z
GinawaSaHapon
3989
Nilikha ang pahina na may '{{#invoke:checkparams|error}}<!-- Validate template parameters --><includeonly><templatestyles src="Template:topN-collapsible/style.css" /><div class="list-switcher-wrapper">{{#if:{{{title|}}}|<div class="list-switcher-header">{{{title}}}</div>}}<div class="list-switcher" data-toggle-category="derived terms"><div class="columns-bg term-list ul-column-count" data-column-count="{{{1|2}}}"></includeonly><noinclude>{{documentation}}</noinclude>'
178369
wikitext
text/x-wiki
{{#invoke:checkparams|error}}<!-- Validate template parameters
--><includeonly><templatestyles src="Template:topN-collapsible/style.css" /><div class="list-switcher-wrapper">{{#if:{{{title|}}}|<div class="list-switcher-header">{{{title}}}</div>}}<div class="list-switcher" data-toggle-category="derived terms"><div class="columns-bg term-list ul-column-count" data-column-count="{{{1|2}}}"></includeonly><noinclude>{{documentation}}</noinclude>
sm7ucdsug2zh3hsx1gya2qjuqejn66x
Padron:topN-collapsible/style.css
10
38947
178370
2026-10-23T05:54:20Z
GinawaSaHapon
3989
Nilikha ang pahina na may '.list-switcher-header { background: var(--wikt-palette-grey-indigo-2); font-weight: bold; font-size: 95%; padding: 0.2em 0.4em 0.1em 0.6em; } .list-switcher-header + .list-switcher .term-list { padding-top: 0.1em; } .list-switcher-edit { margin-left: 1.5em; font-size: 87.75%; /* exactly match font size of [show more] button (in Chromium-based browsers at least) */ font-weight: normal; } .list-switcher-edit::before { content: "["; } .list-switcher...'
178370
sanitized-css
text/css
.list-switcher-header {
background: var(--wikt-palette-grey-indigo-2);
font-weight: bold;
font-size: 95%;
padding: 0.2em 0.4em 0.1em 0.6em;
}
.list-switcher-header + .list-switcher .term-list {
padding-top: 0.1em;
}
.list-switcher-edit {
margin-left: 1.5em;
font-size: 87.75%; /* exactly match font size of [show more] button (in Chromium-based browsers at least) */
font-weight: normal;
}
.list-switcher-edit::before {
content: "[";
}
.list-switcher-edit::after {
content: "]";
}
2jf2q6p32p4vg8hn59a1gv6gd5p9vja
Padron:bottomN
10
38948
178371
2026-10-23T06:08:10Z
GinawaSaHapon
3989
Nilikha ang pahina na may '<includeonly></div></div></div></includeonly><noinclude>{{documentation}}</noinclude>'
178371
wikitext
text/x-wiki
<includeonly></div></div></div></includeonly><noinclude>{{documentation}}</noinclude>
aw2gmnzc9saql6s25k8cbpi4tdxgdsp
Padron:R:es:DCECH
10
38949
178374
2026-10-23T06:32:17Z
GinawaSaHapon
3989
Nilikha ang pahina na may '{{#invoke:quote|call_template |template=cite-book |es |first = Joan|last=Coromines|authorlink=Joan Coromines |first2 = José Antonio|last2=Pascual|authorlink2=José Antonio Pascual |title = w:Diccionario crítico etimológico castellano e hispánico |location = Madrid |publisher = Gredos |year = {{#switch:{{{vol|{{{volume|{{{3|}}}}}}}}} |1|I|A-Ca|A–Ca = 1984 |2|II|Ce-F|Ce–F = 1984 |3|III|G-Ma|G–Ma = 1984 |4|I...'
178374
wikitext
text/x-wiki
{{#invoke:quote|call_template
|template=cite-book
|es
|first = Joan|last=Coromines|authorlink=Joan Coromines
|first2 = José Antonio|last2=Pascual|authorlink2=José Antonio Pascual
|title = w:Diccionario crítico etimológico castellano e hispánico
|location = Madrid
|publisher = Gredos
|year = {{#switch:{{{vol|{{{volume|{{{3|}}}}}}}}}
|1|I|A-Ca|A–Ca = 1984
|2|II|Ce-F|Ce–F = 1984
|3|III|G-Ma|G–Ma = 1984
|4|IV|Me-Re|Me–Re = 1985
|5|V|Ri-X|Ri–X = 1983
|6|VI|Y-Z|Y–Z = 1991
|#default = 1983–1991
}}
|url = {{#switch:{{{vol|{{{volume|{{{3|}}}}}}}}}
|1|I|A-Ca|A–Ca = https://archive.org/details/joanco-2/JOANCO~1/
|2|II|Ce-F|Ce–F = https://archive.org/details/joanco-2/JOANCO~2/
|3|III|G-Ma|G–Ma = https://archive.org/details/joanco-2/JOANCO~3/
|4|IV|Me-Re|Me–Re = https://archive.org/details/joanco-2/JOANCO~4/
|5|V|Ri-X|Ri–X = https://archive.org/details/joanco-2/JO1540~1
|6|VI|Y-Z|Y–Z = https://archive.org/details/joanco-2/Joan%20Corominas%2C%20Jos%C3%A9%20A.%20Pascual%20-%20Diccionario%20Cr%C3%ADtico%20Etimol%C3%B3gico%20Castellano%20e%20Hisp%C3%A1nico%20%28Y-Z%29.%206-Gredos
|#default = https://archive.org/details/joanco-2
}}
|entry = {{#if:{{{1|{{{entry|}}}}}}|{{{1|{{{entry|}}}}}}|{{pagename}}}}
|volume = {{#switch:{{{vol|{{{volume|{{{3|}}}}}}}}}
|1|I|A-Ca|A–Ca = !I (A–Ca)
|2|II|Ce-F|Ce–F = !II (Ce–F)
|3|III|G-Ma|G–Ma = !III (G–Ma)
|4|IV|Me-Re|Me–Re = !IV (Me–Re)
|5|V|Ri-X|Ri–X = !V (Ri–X)
|6|VI|Y-Z|Y–Z = !VI (Y–Z)
|#default =
}}
|pageparam = 2
|isbn = {{#switch:{{{vol|{{{volume|{{{3|}}}}}}}}}
|1|I|A-Ca|A–Ca = 84-249-1361-2
|2|II|Ce-F|Ce–F = 84-249-1363-9
|3|III|G-Ma|G–Ma = 84-249-1365-5
|4|IV|Me-Re|Me–Re = 84-249-0066-9
|5|V|Ri-X|Ri–X = 84-249-0879-1
|6|VI|Y-Z|Y–Z = 84-249-1456-2
|#default =
}}
|propagateparams=line,column,section
}}<noinclude>{{documentation}}</noinclude>
mpph76gzxqikwc0jqbingvnqx69shjf
Padron:=osp=
10
38950
178378
2026-10-23T06:45:13Z
GinawaSaHapon
3989
Nilikha ang pahina na may '{{#invoke:languages/templates|getByCode|osp|getCanonicalName}}<noinclude>{{#invoke:documentation|show|hr=above|from=Template:=aa=/documentation|osp}}</noinclude>'
178378
wikitext
text/x-wiki
{{#invoke:languages/templates|getByCode|osp|getCanonicalName}}<noinclude>{{#invoke:documentation|show|hr=above|from=Template:=aa=/documentation|osp}}</noinclude>
omhdpi0ge3xx8cyub5nzg75jgngfqdc
Padron:osp-noun
10
38951
178380
2026-10-23T06:57:48Z
GinawaSaHapon
3989
Nilikha ang pahina na may '{{head|osp|noun|head={{{head|}}}|sort={{{sort|}}}<!-- -->|g={{#switch:{{{1|{{{g|}}}}}}|m|f={{{1|{{{g}}}}}}|mp=m-p|fp=f-p|mf=m|mfp=m-p|#default=?}}<!-- -->|g2={{#switch:{{{1|{{{g|}}}}}}|mf=f|mfp=f-p}}<!-- -->}}<!-- -->{{#ifeq:{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}|?|[[Category:osp-noun needing attention]]| ({{#if:{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}|{{#switch:{{{p|{{{pl|{{{plural|{{{2}}}}}}}}}}}}|-=''madalas Appendix:Glossary#uncountable|di-mabibilang...'
178380
wikitext
text/x-wiki
{{head|osp|noun|head={{{head|}}}|sort={{{sort|}}}<!--
-->|g={{#switch:{{{1|{{{g|}}}}}}|m|f={{{1|{{{g}}}}}}|mp=m-p|fp=f-p|mf=m|mfp=m-p|#default=?}}<!--
-->|g2={{#switch:{{{1|{{{g|}}}}}}|mf=f|mfp=f-p}}<!--
-->}}<!--
-->{{#ifeq:{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}|?|[[Category:osp-noun needing attention]]| ({{#if:{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}|{{#switch:{{{p|{{{pl|{{{plural|{{{2}}}}}}}}}}}}|-=''madalas [[Appendix:Glossary#uncountable|di-mabibilang]]''|s=''maramihan'' '''{{l-self|osp|accel-form=p|{{pagename}}s}}'''|es=''maramihan'' '''{{l-self|osp|accel-form=p|{{pagename}}es}}'''|{{{p|{{{pl|{{{plural|{{{2}}}}}}}}}}}}=''maramihan'' '''{{l-self|osp|accel-form=p|{{{pl|{{{p|{{{plural|{{{2|{{pagename}}s}}}}}}}}}}}}}}'''}}|''maramihan'' '''{{l-self|osp|accel-form=p|{{pagename}}s}}'''}}{{#if:{{{pl2|}}}| o '''{{l-self|osp|accel-form=p|{{{pl2}}}}}'''}}<!--end of plural information
-->{{#if:{{{f|}}}|{{#ifeq:{{{1}}}|m|, ''pambabae isahan'' '''{{l-self|osp|{{{f}}}}}''', ''pambabae maramihan'' '''{{l-self|osp|{{{fpl|{{{f}}}s}}}}}'''}}}}<!--allow feminine forms only when gender is masculine
-->{{#if:{{{m|}}}|{{#ifeq:{{{1}}}|f|, ''panlalaki isahan'' '''{{l-self|osp|{{{m}}}}}''', ''panlalaki maramihan'' '''{{l-self|osp|{{{mpl|{{{m}}}s}}}}}'''}}}}<!--allow masculine forms only when gender is feminine-->)}}<!-- Now categories
-->{{#ifeq:{{NAMESPACE}}||<!--checks for validity of the plural, such as no square or curly bracket-->{{#ifeq:{{{2|}}}|-||{{#if:{{#ifeq:{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}|-||{{#invoke:ugly hacks|is_valid_page_name|{{{p|{{{pl|{{{plural|{{{2|}}}}}}}}}}}}}}}}||[[Category:osp-noun needing attention]]}}}}}}<noinclude>{{documentation}}</noinclude>
8wvlar0ichh6ew7yvrhklg57z7527i1
Padron:see desc
10
38952
178381
2026-10-23T06:59:14Z
GinawaSaHapon
3989
Nilikha ang pahina na may '(''tingnan doon para makita ang mga anak'')<!-- --><noinclude>{{documentation}}</noinclude>'
178381
wikitext
text/x-wiki
(''tingnan doon para makita ang mga anak'')<!--
--><noinclude>{{documentation}}</noinclude>
anh99gr4f9wawp40ew2xjhqmv2i9723
Module:la-IPA
828
38953
178386
2026-10-23T07:42:26Z
GinawaSaHapon
3989
Nilikha ang pahina na may 'local export = {} local m_a = require("Module:accent qualifier") local m_IPA = require("Module:IPA") local m_str_utils = require("Module:string utilities") local m_table = require("Module:table") local lang = require("Module:languages").getByCode("la") local concat = table.concat local deep_equals = m_table.deepEquals local gsplit = m_str_utils.gsplit local insert = table.insert local invert = m_table.invert local list_to_set = m_table.listToSet local remove =...'
178386
Scribunto
text/plain
local export = {}
local m_a = require("Module:accent qualifier")
local m_IPA = require("Module:IPA")
local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local lang = require("Module:languages").getByCode("la")
local concat = table.concat
local deep_equals = m_table.deepEquals
local gsplit = m_str_utils.gsplit
local insert = table.insert
local invert = m_table.invert
local list_to_set = m_table.listToSet
local remove = table.remove
local rfind = m_str_utils.find
local toNFC = mw.ustring.toNFC
local toNFD = mw.ustring.toNFD
local trim = m_str_utils.trim
local u = m_str_utils.char
local ugsub = m_str_utils.gsub
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local umatch = m_str_utils.match
local MACRON = u(0x304) -- ̄
local BREVE = u(0x306) -- ̆
local TREMA = u(0x308) -- ̈
local LENGTH = MACRON .. "?" .. BREVE .. "?" .. TREMA .. "?"
local UNDERTIE = u(0x35C) -- ͜
local OVERTIE = u(0x361) -- ͡
local VOWELS = "aeɛiɪoɔuʊyʏ"
local VOWEL = "[" .. VOWELS .. "]"
local TILDE = u(0x303) -- ̃
local HALF_LONG = "ˑ"
local LONG = "ː"
local letters_ipa = {
["ā"] = "aː", ["ē"] = "eː", ["ī"] = "iː", ["ō"] = "oː", ["ū"] = "uː", ["ȳ"] = "yː",
["ae"] = "ae̯", ["au"] = "au̯", ["ei"] = "ei̯", ["eu"] = "eu̯", ["oe"] = "oe̯", ["ou"] = "uː",
["c"] = "k", ["g"] = "ɡ", ["q"] = "k", ["v"] = "w", ["x"] = {"k", "s"},
["ph"] = "pʰ", ["th"] = "tʰ", ["ch"] = "kʰ", ["rh"] = "rʰ",
["qw"] = "kʷ", ["gw"] = "ɡʷ", ["sw"] = "sʷ", ["xw"] = {"k", "sʷ"},
["'"] = "ˈ",
}
-- Only includes changes from letters_ipa above.
local letters_ipa_eccl = require("Module:table/setParent")({
["y"] = "i", ["ȳ"] = "iː",
["ae"] = "eː", ["oe"] = "eː",
["c"] = "c", -- becomes /k/, /t͡ʃ/ or /ʃ/
["v"] = "v",
["ph"] = "f",
}, letters_ipa)
local lax_vowel = {
["e"] = "ɛ",
["i"] = "ɪ",
["o"] = "ɔ",
["u"] = "ʊ",
-- No evidence for this, and Greek did not have a near-close lax front-rounded vowel as far as we can tell
-- ["y"] = "ʏ",
}
local tense_vowel = invert(lax_vowel)
local voicing = {
["p"] = "b",
["t"] = "d",
["k"] = "ɡ",
}
local devoicing = invert(voicing)
local phonetic_rules = {
-- Bibliography included at the end
-- Assimilation of [g] to [ŋ] before a following /n/
{"ɡ([.ˈ]*)n", "ŋ%1n"},
-- Per Allen (1978: 23), although note the reservations expressed on the next page.
-- Assimilation of word-internal /n/ and /m/ to following consonants. Exception: /m/ does not assimilate to a following /n/.
{"[mn]([.ˈ]*)([kɡ])", "ŋ%1%2"},
{"m([.ˈ]*)([td])", "n%1%2"},
{"n([.ˈ]*)([mpb])", "m%1%2"},
-- Per George M. Lane: “Nasals changed their place of articulation to that of the following consonant. Thus, dental n before the labials p and b became the labial m... labial m before the gutturals c and g became guttural n...labial m before the dentals t, d, s became dental n...” (§164.3); “One nasal, n, is assimilated to another, m...but an m before n is never assimilated..." (§166.5). -- Per Lloyd (1987: 84): “The opposition between nasals was neutralized in syllable-final position, with the realization of the nasality being assimilated to the point of articulation of the following consonant, e.g., [m] is found only before labials, [n] only before dentals or alveolars, and [ŋ] only before velars and /n/."
-- Potential addition: assimilation of final /m/ and /n/ across word boundaries, per e.g. Allen (1987: 28, 31).
-- No additional labialization before high back vowels
{"ʷ%f[uʊ]", ""},
-- Tensing of short vowels before another vowel
{
"(" .. VOWEL .. ")([.ˈ]+[h]?)%f" .. VOWEL,
function (v, following)
return (tense_vowel[v] or v) .. following
end,
},
-- But not before consonantal glides
{"e([iu]̯)", "ɛ%1"},
-- Nasal vowels
{
"(" .. VOWEL .. ")(" .. LONG .. "?)m$",
function (v, long)
-- 2025-05-15: Change per [[Wiktionary:Beer_parlour/2025/May#Retiring_dual_phonemic-phonetic_transcriptions_for_Latin]]
if true then -- long == LONG then
return (tense_vowel[v] or v) .. TILDE .. LONG
end
return (lax_vowel[v] or v) .. TILDE .. HALF_LONG
end,
},
{
"(" .. VOWEL .. ")[nm]([.ˈ]*[fs])",
function (v, following)
return (tense_vowel[v] or v) .. TILDE .. LONG .. following
end,
},
-- Realization of /r/ as a tap
-- Pultrová (2013) argues for Latin /r/ being an alveolar tap.
-- Lloyd (1987: 81) agrees: “The /r/ was doubtlessly an alveolar flap."
-- Allen (1978: 33) expresses doubt: “By the classical period there is no reason to think that the sound had not strengthened to the trill described by later writers.”
-- Unconditional [r] transcription is preferable to unconditional [ɾ] per 18 September 2021 discussion at [[Module_talk:la-IPA#Transcription_of_Latin's_rhotic_consonant]]
-- No consensus yet on how to implement conditional allophony of [r] vs. [ɾ]
-- Voicing and loss of intervocalic /h/.
{"([^ˈ].)h", "%1(ɦ)"},
-- Per Allen (1978: 43–45).
-- Phonetic (as opposed to lexical/phonemic) assimilations
-- Place
-- First because this accounts for 'atque' seemingly escaping total assimilation (and 'adque' presumably not)
{"d([.ˈ]*s%f[" .. VOWELS .. "ptk])", "s%1"}, -- leave [t] out since etsi has [ts], not [sː]
{"s[^ː]([.ˈ]*)s%f[ptk]", "s(ː)%1"},
{"st([.ˈ]+)([^" .. VOWELS .. "])", "s(t)%1%2"},
{"d([.ˈ]+)([pkɡln])", "%2%1%2"}, --leave [r] out since dr does not assimilate, even when heterosyllabic (e.g. quadrans), except in prefixed words
{"b([.ˈ]+)([mf])", "%2%1%2"},
{"s([.ˈ]+)(f)", "%2%1%2"},
-- Regressive voicing assimilation in consonant clusters
{
"([bdɡ])([.ˈ]*)%f[fkpst]",
function (consonant, following)
return (devoicing[consonant] or consonant) .. following
end,
},
{
"([ptk])([.ˈ]*)%f[bdɡz]",
function (consonant, following)
return (voicing[consonant] or consonant) .. following
end,
},
-- 2025-05-15: Numerous changes per [[Wiktionary:Beer_parlour/2025/May#Retiring_dual_phonemic-phonetic_transcriptions_for_Latin]]:
-- (1) simplify l-pinguis vs. l-exilis to just [ɫ] (formerly [ɫ̪]) vs. [l] (formerly [lʲ] in some circumstances);
-- consider further simplifying further to use [l] before non-high-front vowels
-- (2) don't mark dental or alveolar notations on coronals
-- (3) don't mark centralized ä on [a]
-- Allophones of /l/
{"l", "ɫ"},
-- “Pinguis”. Dark/velarized.
-- Per Weiss (2009: 117): “... pinguis (velar). l is exīlis before i and when geminate, otherwise l is pinguis.”
-- Page 82: “... l is pinguis even before e, e.g. Herculēs < Hercolēs ... < Hercelēs ...”
-- Per Sihler (1995: 174): “l exilis was found before the vowels -i- and -ī-, and before another -l-; l pinguis occurred before any other vowel; before any consonant except l; and in word-final position [...] l pinguis actually had two degrees of avoirdupois, being fatter before a consonant than before a vowel...”
-- Page 41: “... velarized l (that is, ‘l pinguis’)...”
-- Sen (2015: §2) states that /l/ was velarized in word-final position or before consonants–other than another /l/–and that it had varying degrees of “dark resonance (velarization in articulatory terms)” (p. 23) before e, a, o, and u (p. 33).
-- Both Sen and Sihler indicate different degrees of velarization, depending on the environment. IPA lacks a way to represent these gradations, unfortunately.
{"ɫ([.ˈ]*)ɫ", "l%1l"},
{"ɫ([.ˈ]*[iɪyʏ])", "l%1"},
-- “Exīlis”. Not dark/velarized. Possibly palatalized.
-- Per Sen (2015: 29): It is plausible [...] that simple onset /l/ was palatalized before /i/, thus [lʲ] [...] it seems likely that geminate /ll/ was also palatalized, given the similar behaviour of the two...”
-- Per Weiss (2009: 82): “In Latin, l developed... a non-velar (possibly palatal) allophone called exīlis before i and when geminate...”
-- Per Sihler (1995: 174): “l exilis was found before the vowels -i- and -ī-, and before another -l-.”
-- Per Sihler (2000: §133.1): "It is less clear whether the 'thin' lateral [i.e. L exilis] was specifically palatal, or palatalized, or only neutral."
-- Giannini and Marotta apparently argue that it was not palatalized (https://i.imgur.com/ytM1QDn.png). I do not have access to the book in question.
-- Retracted /s/
-- {"s", "s̠"}, [already commented out sometime before 2025-05-15]
-- Lloyd (1987: 80–81) expresses some uncertainty about this, but appears to overall be in favour of it: “... the evidence that the apico-alveolar pronunciation was ancient in Latin and inherited from Indo-European is quite strong.”
-- Per Zampaulo (2019: 93), “... in many instances, Latin s was likely pronounced as an apical segment [s̺] (rather than laminal [s])."
-- Per Widdison (1987: 64), "In all, it would be fair to state that the apico-alveolar [ś] articulation represented the main allophonic variant of Latin and possibly IE /s/..."
-- dental Z
-- {"z", "z̪"}, [2025-05-15; see above]
-- Dental articulations
-- {"[td]", "%0̪"} ,[2025-05-15; see above]
-- {"n([.ˈ]*[td])", "n̪%1"}, --it's not as clear as for the stops [2025-05-15; see above]
--Allophones of A
-- {"a", "ä"}, [2025-05-15; see above]
-- Works cited
-- Allen, William Sidney. 1978. Vox Latina: A Guide to the pronunciation of Classical Latin.
-- Lane, George M. A Latin grammar for schools and colleges.
-- Lloyd, Paul M. 1987. From Latin to Spanish.
-- Pultrová, Lucie. 2013. On the phonetic nature of the Latin R.
-- Sen, Ranjan. 2015. Syllable and segment in Latin.
-- Sihler, Andrew L. 1995. New comparative grammar of Greek and Latin.
-- Sihler, Andrew L. 2000. Language history: An introduction.
-- Weiss, Michael. 2009. Outline of the historical and comparative grammar of Latin.
-- Widdison, Kirk A. 16th century Spanish sibilant reordering: Reasons for divergence.
-- Zampaulo, André. 2019. Palatal Sound Change in the Romance languages: Diachronic and Synchronic Perspectives.
}
local phonetic_rules_eccl = {
-- Specifically the Roman Ecclesiastical for singing from the Liber Usualis
{"([aɛeiɔou][ːˑ.ˈ]*)s([.ˈ]*)%f[aɛeiɔou]", "%1s̬%2"}, --partial voicing of s between vowels
{"s([.ˈ]*)%f[bdɡmnlv]", "z%1"}, --full voicing of s before voiced consonants
{"ek([.ˈ]*)s([aɛeiɔoubdɡmnlv])", "eɡ%1z%2"}, --voicing of the prefix ex-
{"kz", "ɡz"},
-- Tapped R intervocalically and in complex onset
-- ^ Citation needed for this being the case in Ecclesiastical pronunciation
-- {"([aɛeiɔou][ːˑ.ˈ]+)r([aɛeiɔou]?)", "%1ɾ%2"},
-- {"([fbdɡptk])r", "%1ɾ"},
--Partial assimilation of l and n before palatal affricates, as in Italian
{"([ln])([.ˈ]*t͡ʃ)", "%1̠ʲ%2"},
{"([ln])([.ˈ]*d͡ʒ)", "%1̠ʲ%2"},
{"([ln])([.ˈ]*ʃ)", "%1̠ʲ%2"},
-- other coda nasal assimilation, full and partial. Per Canepari, only applies to /n/ and not to /m/
{"n([.ˈ]*[kɡ])", "ŋ%1"},
{"n([.ˈ]*[fv])", "ɱ%1"},
}
local lengthen_vowel = {
["a"] = "aː", ["aː"] = "aː",
["ɛ"] = "ɛː", ["ɛː"] = "ɛː",
["e"] = "eː", ["eː"] = "eː",
["i"] = "iː", ["iː"] = "iː",
["ɔ"] = "ɔː", ["ɔː"] = "ɔː",
["o"] = "oː", ["oː"] = "oː",
["u"] = "uː", ["uː"] = "uː",
["au̯"] = "aːu̯",
["ɛu̯"] = "ɛːu̯",
["eu̯"] = "eːu̯",
}
local vowels = list_to_set{
"a", "ɛ", "e", "ɪ", "i", "ɔ", "o", "ʊ", "u", "y",
"aː", "ɛː", "eː", "iː", "ɔː", "oː", "uː", "yː",
"ae̯", "au̯", "ei̯", "eu̯", "oe̯", "ou̯",
}
local onsets = {
"p", "pʰ", "b",
"t", "tʰ", "d",
"k", "kʰ", "kʷ", "ɡ", "ɡʷ",
"s", "sʷ", "z", "f", "v", "h",
"t͡s", "d͡z", "t͡ʃ", "d͡ʒ", "ʃ",
"l", "r", "rʰ",
"m", "n", "ɲ",
"j", "w",
"pl", "pʰl", "bl",
"kl", "kʰl", "ɡl",
"fl",
"pr", "pʰr", "br",
"tr", "tʰr", "dr",
"kr", "kʰr", "ɡr",
"fr",
}
for i = 1, #onsets do
local v = onsets[i]
if umatch(v, "^[ptk][ʰʷ]*[lr]?$") then
insert(onsets, "s" .. v)
end
end
onsets = list_to_set(onsets)
local codas = list_to_set{
"p", "pʰ", "b",
"t", "tʰ", "d",
"k", "kʰ", "ɡ",
"s", "z", "f",
"ʃ",
"l", "r",
"m", "n", "ɲ",
"j",
"ps", "ts", "ks",
"sp", "st", "sk",
"spʰ", "stʰ", "skʰ",
"lp", "lpʰ", "lb", "lps",
"lt", "ltʰ", "ld",
"lk", "lkʰ", "lɡ", "lks",
"ls",
"lm", "ln", "lms", "lns",
"rp", "rpʰ", "rb", "rps",
"rt", "rtʰ", "rd",
"rk", "rkʰ", "rɡ", "rks",
"rs",
"rl", "rls",
"rm", "rn", "rms", "rns",
"mp", "mpʰ", "mb", "mps",
"nt", "ntʰ", "nd",
"nk", "nkʰ", "nɡ", "nks",
"ns",
}
-- Prefixes that end in a consonant; can be patterns. Occurrences of such
-- prefixes + i + vowel cause the i to convert to j (to suppress this, add a
-- dot, i.e. syllable boundary, after the i).
local cons_ending_prefixes = {
"a[bd]", "circum", "con", "dis", "ex", "inter", "in", "ob", "per",
"subter", "sub", "super", "tr[aā]ns"
}
local macrons_to_breves = {
["ā"] = "ă",
["ē"] = "ĕ",
["ī"] = "ĭ",
["ō"] = "ŏ",
["ū"] = "ŭ",
-- Unicode doesn't have breve-y
["ȳ"] = "y" .. BREVE,
}
local function normalize_ligatures(ligature, diacritic)
return (ligature == "æ" and "a" or "o") .. diacritic .. "e"
end
-- NOTE: Everything is lowercased very early on, so we don't have to worry
-- about capitalized letters.
-- FIXME: handle ǟë̄ï̄ȫǖÿ̄ etc.
local short_vowels_string = "aeiouyăĕĭŏŭäëïöüÿ" -- no breve-y in Unicode
local long_vowels_string = "āēīōūȳ"
local vowels_string = short_vowels_string .. long_vowels_string
local vowels_c = "[" .. vowels_string .. "]"
local non_vowels_c = "[^" .. vowels_string .. "]"
local function track(page)
require("Module:debug/track")("la-IPA/" .. page)
return true
end
local function remove_diacritic(word, ch)
return toNFC((ugsub(toNFD(word), ch, "")))
end
local function match_phoneme(ch, pattern)
return ch and umatch(ch, pattern) and true or false
end
local function letters_to_ipa(word, phonetic, eccl)
local ph = {}
local dictionary = eccl and letters_ipa_eccl or letters_ipa
while ulen(word) > 0 do
local longestmatch = ""
for letter in pairs(dictionary) do
local letter_len = ulen(letter)
if letter_len > ulen(longestmatch) and usub(word, 1, letter_len) == letter then
longestmatch = letter
end
end
if ulen(longestmatch) > 0 then
local ipa = dictionary[longestmatch]
if type(ipa) == "table" then
for _, phoneme in ipairs(ipa) do
insert(ph, phoneme)
end
else
insert(ph, ipa)
end
word = usub(word, ulen(longestmatch) + 1)
else
insert(ph, usub(word, 1, 1))
word = usub(word, 2)
end
end
if eccl then
local front_vowel = "^[eɛiɪ]"
local i, n = 1, #ph
while i <= n do
local cur = ph[i]
if cur == "c" then -- c, but not k/q/x
ph[i] = "k" -- default
local nxt = ph[i + 1]
if nxt == "c" then -- cc{e|i}: t.t͡ʃ
if match_phoneme(ph[i + 2], front_vowel) then
ph[i], ph[i + 1] = "t", "t͡ʃ"
i = i + 2
end
elseif match_phoneme(nxt, front_vowel) then -- c{e|i}: t͡ʃ
ph[i] = "t͡ʃ"
i = i + 1
end
elseif cur == "ɡ" then
local nxt = ph[i + 1]
if nxt == "ɡ" then -- gg{e|i}: d.d͡ʒ
if match_phoneme(ph[i + 2], front_vowel) then
ph[i], ph[i + 1] = "d", "d͡ʒ"
i = i + 2
end
elseif nxt == "n" then -- gn: ɲ.ɲ
ph[i], ph[i + 1] = "ɲ", "ɲ"
i = i + 1
elseif match_phoneme(nxt, front_vowel) then -- g{e|i}: d͡ʒ
ph[i] = "d͡ʒ"
end
elseif cur == "h" then
ph[i] = ""
elseif cur == "m" then -- mihī̆ = michī̆
if ph[i + 1] == "i" and ph[i + 2] == "h" and match_phoneme(ph[i + 3], "^[iɪ]ː?$") then
ph[i + 2] = letters_ipa_eccl["ch"]
i = i + 3
end
elseif cur == "n" then -- nihil = nichil
if ph[i + 1] == "i" and ph[i + 2] == "h" and ph[i + 3] == "i" and ph[i + 4] == "l" then
ph[i + 2] = letters_ipa_eccl["ch"]
i = i + 4
end
elseif cur == "s" then -- sc{e|i}: ʃ.ʃ
if ph[i + 1] == "c" and match_phoneme(ph[i + 2], front_vowel) then
ph[i], ph[i + 1] = "ʃ", "ʃ"
i = i + 2
end
elseif cur == "t" then -- ti{V}: t͡si
if match_phoneme(ph[i + 1], "^[iɪ]") and not match_phoneme(ph[i - 1], "[dstz]ʰ?$") and vowels[ph[i + 2]] then
ph[i] = "t͡s"
i = i + 2
end
elseif cur == "z" then
if ph[i + 1] == "z" then -- zz: d.d͡z
ph[i], ph[i + 1] = "d", "d͡z"
i = i + 1
else -- z: d͡z
ph[i] = "d͡z"
end
end
i = i + 1
end
end
return ph
end
local function get_onset(syll)
local consonants = {}
for i = 1, #syll do
if vowels[syll[i]] then
break
end
if syll[i] ~= "ˈ" then
insert(consonants, syll[i])
end
end
return concat(consonants)
end
local function get_coda(syll)
local consonants = {}
for i = #syll, 1, -1 do
if vowels[syll[i]] then
break
end
insert(consonants, 1, syll[i])
end
return concat(consonants)
end
local function get_vowel(syll)
for i = 1,#syll do
if vowels[syll[i]] then return syll[i] end
end
end
-- Split the word into syllables of CV shape
local function split_syllables(remainder)
local syllables, syll = {}, {}
for _, phoneme in ipairs(remainder) do
if phoneme == "." then
if #syll > 0 then
insert(syllables, syll)
syll = {}
end
-- Insert a special syllable consisting only of a period.
-- We remove it later but it forces no movement of consonants across
-- the period.
insert(syllables, {"."})
elseif phoneme == "ˈ" then
if #syll > 0 then
insert(syllables,syll)
end
syll = {"ˈ"}
elseif vowels[phoneme] then
insert(syll, phoneme)
insert(syllables, syll)
syll = {}
else
insert(syll, phoneme)
end
end
-- If there are phonemes left, then the word ends in a consonant.
-- Add another syllable for them, which will get joined the preceding
-- syllable down below.
if #syll > 0 then
insert(syllables, syll)
end
-- Split consonant clusters between syllables
for i, current in ipairs(syllables) do
if #current == 1 and current[1] == "." then
-- If the current syllable is just a period (explicit syllable
-- break), remove it. The loop will then skip the next syllable,
-- which will prevent movement of consonants across the syllable
-- break (since movement of consonants happens from the current
-- syllable to the previous one).
remove(syllables, i)
elseif i > 1 then
local previous = syllables[i - 1]
local onset = get_onset(current)
-- Shift over consonants until the syllable onset is valid
while not (onset == "" or onsets[onset]) do
insert(previous, remove(current, 1))
onset = get_onset(current)
end
-- If the preceding syllable still ends with a vowel,
-- and the current one begins with s + another consonant, then shift it over.
if get_coda(previous) == "" and (current[1] == "s" and not vowels[current[2]]) then
insert(previous, remove(current, 1))
end
-- Check if there is no vowel at all in this syllable. That
-- generally happens either (1) with an explicit syllable division
-- specified, like 'cap.ra', which will get divided into the syllables
-- [ca], [p], [.], [ra]; or (2) at the end of a word that ends with
-- one or more consonants. We move the consonants onto the preceding
-- syllable, then remove the resulting empty syllable. If the
-- new current syllable is [.], remove it, too. The loop will then
-- skip the next syllable, which will prevent movement of consonants
-- across the syllable break (since movement of consonants happens
-- from the current syllable to the previous one).
if not get_vowel(current) then
for _ = 1, #current do
insert(previous, remove(current, 1))
end
remove(syllables, i)
if syllables[i] and #syllables[i] == 1 and syllables[i][1] == "." then
remove(syllables, i)
end
end
end
end
for _, syll in ipairs(syllables) do
local onset = get_onset(syll)
local coda = get_coda(syll)
if not (onset == "" or onsets[onset]) then
track("bad onset")
--error("onset error:[" .. onset .. "]")
end
if not (coda == "" or codas[coda]) then
track("bad coda")
--error("coda error:[" .. coda .. "]")
end
end
return syllables
end
local function phoneme_is_short_vowel(phoneme)
return rfind(phoneme, "^[aɛeiɔouy]$")
end
local function detect_accent(syllables, is_prefix, is_suffix)
-- Manual override
for i=1,#syllables do
for j=1,#syllables[i] do
if syllables[i][j] == "ˈ" then
remove(syllables[i],j)
return i
end
end
end
-- Prefixes have no accent.
if is_prefix then
return -1
end
-- Suffixes have an accent only if the stress would be on the suffix when the
-- suffix is part of a word. Don't get tripped up by the first syllable being
-- nonsyllabic (e.g. in -rnus).
if is_suffix then
local syllables_with_vowel = #syllables - (get_vowel(syllables[1]) and 0 or 1)
if syllables_with_vowel < 2 then
return -1
end
if syllables_with_vowel == 2 then
local penult = syllables[#syllables - 1]
if phoneme_is_short_vowel(penult[#penult]) then
return -1
end
end
end
-- Detect accent placement
if #syllables > 2 then
-- Does the penultimate syllable end in a single vowel?
local penult = syllables[#syllables - 1]
if phoneme_is_short_vowel(penult[#penult]) then
return #syllables - 2
else
return #syllables - 1
end
elseif #syllables == 2 then
return #syllables - 1
elseif #syllables == 1 then
return #syllables --mark stress on monosyllables so that stress-conditioned sound rules work correctly. Then, delete it prior to display
end
end
local function clean_syllable_breaks(word)
return (ugsub(word, "[%.ˈ][%.ˈ]+", function(m)
return m:find("ˈ") and "ˈ" or "."
end))
end
local function convert_word(word, phonetic, eccl)
-- Some contracted words end in apostrophes, which shouldn't be mistaken for stress placement.
word = word:gsub("'$", "")
-- Normalize i/j/u/v; do this before removing breves, so we keep the
-- ŭ in langŭī (perfect of languēscō) as a vowel.
word = ugsub(word, "(" .. vowels_c .. ")[vw](" .. non_vowels_c .. ")", "%1u%2")
word = ugsub(word, "qu(" .. vowels_c .. ")", "qw%1")
word = word:gsub("%f[^%z.'][ck]w", "qw")
word = ugsub(word, "%f[^%z.'n]gu(" .. vowels_c .. ")", "gw%1") -- nguV or initial guV
word = ugsub(word, "^i(" .. vowels_c .. ")", "j%1")
word = ugsub(word, "^u(" .. vowels_c .. ")", "v%1")
-- Per the August 31 2019 recommendation by [[User:Brutal Russian]] in
-- [[Module talk:la-IPA]], we convert i/j between vowels to jj if the
-- preceding vowel is short but to single j if the preceding vowel is long.
word = ugsub(word, "(" .. vowels_c .. ")('?)([iju])()", function (vowel, stress, cons, pos)
if vowels_string:find(usub(word, pos, pos)) then
if cons == "u" then
cons = stress .. "v"
-- FIXME: this should also catch diphthongs.
elseif eccl or long_vowels_string:find(vowel) then
cons = stress .. "j"
else
cons = "j" .. stress .. "j"
end
return vowel .. cons
end
end)
--Convert v/w to u syllable-finally
word = word:gsub("[vw]%f[%z.']", "u")
-- Convert i to j before vowel and after any prefix that ends in a consonant,
-- per the August 23 2019 discussion in [[Module talk:la-IPA]].
for _, pref in ipairs(cons_ending_prefixes) do
word = ugsub(word, "^(" .. pref .. ")i(" .. vowels_c .. ")", "%1j%2")
end
-- Convert z to zz between vowels so that the syllable weight and stress assignment will be correct.
word = ugsub(word, "(" .. vowels_c .. ")z(" .. vowels_c .. ")", "%1zz%2")
if eccl then
word = ugsub(word, "(" .. vowels_c .. ")ti(" .. vowels_c .. ")", "%1tt͡si%2")
end
-- Now remove breves.
word = remove_diacritic(word, BREVE)
-- Normalize syllabic vowels like aë, oë; do this after removing breves but
-- before any other normalizations.
word = ugsub(word, "(" .. vowels_c .. ")([äëïöüÿ])", "%1.%2")
word = remove_diacritic(word, TREMA)
-- Assume the u in a final -us or -um is not part of a diphthong
word = word:gsub("([aeo])(u[ms])$", "%1.%2")
word = word:gsub("[aeou]%f[i]", "%0.")
word = word:gsub("_", "")
-- Vowel length before nasal + fricative is allophonic
word = toNFC(toNFD(word):gsub("([aeiouy])" .. MACRON .. "([mn][.']*[fs])", "%1%2"))
if eccl then
word = toNFC(word:gsub("[aeiouy]%f[j]", "%0" .. MACRON))
end
-- Per May 10 2019 discussion in [[Module talk:la-IPA]], we syllabify
-- prefixes ab-, ad-, ob-, sub- separately from following l or r.
word = word:gsub("^a([bd])([lr])", "a%1.%2")
word = word:gsub("^ob([lr])", "ob.%1")
word = word:gsub("^sub([lr])", "sub.%1")
-- Remove hyphens indicating prefixes or suffixes; do this after the above,
-- some of which are sensitive to beginning or end of word and shouldn't
-- apply to end of prefix or beginning of suffix.
local is_prefix, is_suffix
word = word:gsub("^(%-?)(.-)(%-?)$", function(m1, m2, m3)
is_prefix, is_suffix = m1 == "-", m3 == "-"
return m2
end)
-- Convert word to IPA
local phonemes = letters_to_ipa(word, phonetic, eccl)
-- Split into syllables
local syllables = split_syllables(phonemes)
-- Add accent
local accent = detect_accent(syllables, is_prefix, is_suffix)
for _, syll in ipairs(syllables) do
for j in ipairs(syll) do
if eccl then
syll[j] = syll[j]:gsub("ː", "")
elseif phonetic then
syll[j] = lax_vowel[syll[j]] or syll[j]
end
end
end
for i, syll in ipairs(syllables) do
if eccl and i == accent and phonetic and vowels[syll[#syll]] then
syll[#syll] = lengthen_vowel[syll[#syll]] or syll[#syll]
end
for j = 1, #syll - 1 do
if syll[j] == syll[j + 1] then
syll[j + 1] = ""
end
end
end
for i, syll in ipairs(syllables) do
syll = concat(syll)
-- Atonic /ɔ/ and /ɛ/ merge with /o/ and /e/ respectively
if eccl and phonetic and i == accent then
syll = syll:gsub("o", "ɔ")
syll = syll:gsub("e", "ɛ")
-- Syllable-initial /ɡn/ becomes /n/ (e.g. "gnōscō")
elseif not eccl then
syll = syll:gsub("^ɡn", "n")
end
syllables[i] = (i == accent and "ˈ" or "") .. syll
end
word = clean_syllable_breaks(concat(syllables, "."))
-- poetic meter shows that a consonant before "h" was syllabified as an onset, not as a coda.
-- Based on outcome of talk page discussion, this will be indicated by the omission of /h/ [h] in this context.
word = ugsub(word, "([^" .. VOWELS .. "ptk.ˈːˑ])([.ˈːˑ]*)h", "%2%1")
if eccl then
-- Replace ʃ.ʃ or ʃˈʃ with .ʃ or ˈʃ after any consonant.
word = ugsub(word, "([^" .. VOWELS .. "])ʃ([.ˈ]*)ʃ", "%1%2ʃ")
word = word:gsub("ʰ", "")
else
-- [2025-05-15: don't do this, per [[Wiktionary:Beer_parlour/2025/May#Retiring_dual_phonemic-phonetic_transcriptions_for_Latin]]
-- word = word:gsub("j", "i̯") -- normalize glide spelling
-- word = word:gsub("w", "u̯")
end
if phonetic then
local rules = eccl and phonetic_rules_eccl or phonetic_rules
for _, rule in ipairs(rules) do
word = ugsub(word, rule[1], rule[2])
end
-- [2025-05-15: now that we've disabled the phonemic notation, we should put the syllable breaks in the
-- phonetic notation, as otherwise they don't display at all]
-- word = word:gsub("%.+", "") -- remove the dots
end
if phonetic then
word = ugsub(word, "(%a([̠̯]?))%1", "%1" .. LONG) -- convert double consonants into long ones
word = ugsub(word, "[ːˑ][ːˑ]+", "ː") -- maximum of one full length mark
end
return clean_syllable_breaks(word)
end
function export.convert_words(text, phonetic, eccl)
local disallowed = ugsub(text, "[a-zA-ZæœāǣēīōūȳăĕĭŏŭäëïöüÿĀǢĒĪŌŪȲĂĔĬŎŬÄËÏÖÜŸ%-,.?!:;()'\"_ " .. MACRON .. BREVE .. TREMA .. UNDERTIE .. OVERTIE .. "]", "")
local n = ulen(disallowed)
if n > 0 then
local msg = ("The character%%s %s %%s not allowed."):format(mw.dumpObject(disallowed))
if n == 1 then
error(msg:format("", "is"))
else
error(msg:format("s", "are"))
end
end
text = toNFD(text)
-- Call ulower() even though it's also called in phoneticize,
-- in case convert_words() is called externally.
text = ulower(text):gsub("[,?!:;()\"]", "")
text = ugsub(text, "([æœ])(" .. LENGTH .. ")", normalize_ligatures)
-- Treat a tie as "_".
text = ugsub(text, "[" .. UNDERTIE .. OVERTIE .. "]", "_"):gsub("__+", "_")
local result = {}
-- Split on spaces and hyphens, but hyphens preceded/followed by a space
-- are included in the word (e.g. prefixes and suffixes).
for chunk in gsplit(text, " +") do
for word in gsplit(chunk, "%f[%z-]%-+%f[^%z-]") do
if word:match("[^-]") then
insert(result, convert_word(toNFC(word), phonetic, eccl))
end
end
end
return trim(concat(result, " "))
end
-- Phoneticize Latin TEXT. Return a list of one or more phoneticizations,
-- each of which is a two-element list {PHONEMIC, PHONETIC}. If ECCL, use
-- Ecclesiastical pronunciation. Otherwise, use Classical pronunciation.
function export.phoneticize(text, eccl)
local function do_phoneticize(text, eccl)
return {
export.convert_words(text, false, eccl),
export.convert_words(text, true, eccl),
}
end
text = ulower(text)
-- If we have a macron-breve sequence, generate two pronunciations, one for
-- the long vowel and one for the short.
if rfind(text, "[āēīōūȳ]" .. BREVE) then
local longvar = ugsub(text, "([āēīōūȳ])" .. BREVE, "%1")
local shortvar = ugsub(text, "([āēīōūȳ])" .. BREVE, macrons_to_breves)
local longipa = do_phoneticize(longvar, eccl)
local shortipa = do_phoneticize(shortvar, eccl)
-- Make sure long and short variants are actually different (they won't
-- be in Ecclesiastical pronunciation).
if not deep_equals(longipa, shortipa) then
return {longipa, shortipa}
else
return {longipa}
end
elseif rfind(text, ";") then
local tautosyllabicvar = text:gsub(";", "")
local heterosyllabicvar = text:gsub(";", ".")
local tautosyllabicipa = do_phoneticize(tautosyllabicvar, eccl)
local heterosyllabicipa = do_phoneticize(heterosyllabicvar, eccl)
if not deep_equals(tautosyllabicipa, heterosyllabicipa) then
return {tautosyllabicipa, heterosyllabicipa}
else
return {tautosyllabicipa}
end
else
return {do_phoneticize(text, eccl)}
end
end
local function make_row(phoneticizations, dials, include_phonemic)
local IPA_items = {}
for _, phoneticization in ipairs(phoneticizations) do
local phonemic = phoneticization[1]
local phonetic = phoneticization[2]
local IPA_arg
local phonetic_brackets = "[" .. phonetic .. "]"
if include_phonemic then
IPA_arg = {pron = "/" .. phonemic .. "/ " .. phonetic_brackets}
else
IPA_arg = {pron = phonetic_brackets}
end
insert(IPA_items, IPA_arg)
end
return m_a.format_qualifiers(lang, dials) .. " " .. m_IPA.format_IPA_full { lang = lang, items = IPA_items }
end
function export.show_full(frame)
local boolean_default_true = {type = "boolean", default = true}
local args = require("Module:parameters").process(frame:getParent().args, {
[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "īnspīrāre" or mw.loadData("Module:headword/data").pagename},
classical = boolean_default_true,
cl = {alias_of = "classical"},
ecclesiastical = boolean_default_true,
eccl = {alias_of = "ecclesiastical"},
vul = {type = "boolean"}, -- To be removed.
-- 2025-05-15: Add include_phonemic (not by default) per [[Wiktionary:Beer_parlour/2025/May#Retiring_dual_phonemic-phonetic_transcriptions_for_Latin]]
include_phonemic = {type = "boolean"},
ann = true,
accent = {list = true},
indent = true
})
-- Track down any remaining uses of |vul=
if args.vul ~= nil then
track("vul")
end
local text = args[1]
local categories = {}
local accent = args.accent
local text_to_sub = text:gsub("[.'_]", "")
local anntext = (
args.ann == "1" and "''" .. text_to_sub .. "'':" or
args.ann and "''" .. args.ann:gsub("%+", m_str_utils.replacement_escape(text_to_sub)) .. "'':" or
"")
local below_ann_indent = ""
local both_lines = args.classical and args.ecclesiastical
if anntext ~= "" then
if both_lines then
anntext = anntext .. "\n"
below_ann_indent = "*"
else
anntext = anntext .. " "
end
end
local text = args[1]
local categories = {}
local accent = args.accent
local first_line_indent = (args.indent or "") .. " "
local later_line_indent
if both_lines then
later_line_indent = (args.indent or "*") .. below_ann_indent .. " "
end
local function make_classical()
return make_row(export.phoneticize(text, false), #accent > 0 and accent or {"Klasiko"})
end
local function make_ecclesiastical()
return make_row(export.phoneticize(text, true), #accent > 0 and accent or {'Pangsimbahan'})
end
if both_lines then
out = first_line_indent .. anntext .. (anntext == "" and "" or later_line_indent) .. make_classical() .. "\n" ..
later_line_indent .. make_ecclesiastical()
elseif args.classical then
out = first_line_indent .. anntext .. make_classical()
else
out = first_line_indent .. anntext .. make_ecclesiastical()
insert(categories, lang:getCanonicalName() .. " terms with Ecclesiastical IPA pronunciation only")
end
return out .. require("Module:utilities").format_categories(categories)
end
return export
32txuwrug0118g2v5w17tsrb3j18hyy
Module:la-adj/data
828
38954
178387
2026-10-23T07:53:21Z
GinawaSaHapon
3989
Nilikha ang pahina na may 'local decl = {} local en_utilities_module = "Module:en-utilities" local la_utilities_module = "Module:la-utilities" local string_char_module = "Module:string/char" local table_deep_copy_module = "Module:table/deepCopy" local table_empty_module = "Module:table/empty" local table_insert_if_not_module = "Module:table/insertIfNot" local toNFD = mw.ustring.toNFD local u = require(string_char_module) local umatch = mw.ustring.match local usub = mw.ustring.sub local...'
178387
Scribunto
text/plain
local decl = {}
local en_utilities_module = "Module:en-utilities"
local la_utilities_module = "Module:la-utilities"
local string_char_module = "Module:string/char"
local table_deep_copy_module = "Module:table/deepCopy"
local table_empty_module = "Module:table/empty"
local table_insert_if_not_module = "Module:table/insertIfNot"
local toNFD = mw.ustring.toNFD
local u = require(string_char_module)
local umatch = mw.ustring.match
local usub = mw.ustring.sub
local MACRON = u(0x304)
local BREVE = u(0x306)
local DIAER = u(0x308)
local accent = "[" .. MACRON .. BREVE .. DIAER .. "]*"
local function add_form(...)
add_form = require(la_utilities_module).add_form
return add_form(...)
end
local function deep_copy(...)
deep_copy = require(table_deep_copy_module)
return deep_copy(...)
end
local function empty_table(...)
empty_table = require(table_empty_module)
return empty_table(...)
end
local function insert_if_not(...)
insert_if_not = require(table_insert_if_not_module)
return insert_if_not(...)
end
local function remove_forms(...)
remove_forms = require(la_utilities_module).remove_forms
return remove_forms(...)
end
local function singularize(...)
singularize = require(en_utilities_module).singularize
return singularize(...)
end
local function glossary_link(anchor, text)
text = text or anchor
return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]"
end
local function decl_link(english_declension, decl_text)
decl_text = decl_text or english_declension .. "-declension"
return "[[Appendix:Latin " .. english_declension .. " declension|" .. decl_text .. "]]"
end
local function preprocess(...)
local frame = mw.getCurrentFrame()
function preprocess(text)
return frame:preprocess(text)
end
return preprocess(...)
end
decl["0+"] = function(data, args)
local forms, categories = data.forms, data.categories
local stem = args[1]
forms["nom_sg_m"] = stem
forms["nom_pl_m"] = stem
forms["gen_sg_m"] = stem
forms["gen_pl_m"] = stem
forms["dat_sg_m"] = stem
forms["dat_pl_m"] = stem
forms["acc_sg_m"] = stem
forms["acc_pl_m"] = stem
forms["abl_sg_m"] = stem
forms["abl_pl_m"] = stem
forms["voc_sg_m"] = stem
forms["voc_pl_m"] = stem
forms["loc_sg_m"] = stem
forms["loc_pl_m"] = stem
insert_if_not(categories, "Latin indeclinable " .. data.pos)
end
decl["1&2+"] = function(data, args)
local forms, types, pos, subtitles, categories = data.forms, data.types, data.pos, data.subtitles, data.categories
local stem = args[1]
local singpos, gender = singularize(pos), data.gender
if gender == "F" then
data.title = decl_link("first") .. " " .. singpos
elseif gender then
data.title = decl_link("second") .. " " .. singpos
else
data.title = decl_link("first", "first") .. "/" .. decl_link("second") .. " " .. singpos
end
local original
if types.er then
local final2 = stem:sub(-2)
if final2 == "er" then
insert_if_not(subtitles, "nominative masculine singular in ''-er''")
insert_if_not(categories, "Latin first and second declension "
.. pos .. " with nominative masculine singular in -er")
elseif final2 == "ur" then
insert_if_not(subtitles, "nominative masculine singular in ''-ur''")
insert_if_not(categories, "Latin first and second declension "
.. pos .. " with nominative masculine singular in -ur")
else
error("Unrecognized ''-r'' stem (doesn't end in ''-er'' or ''-ur''): " .. stem)
end
stem, original = args[2], stem
end
local us = "us"
local a_sf = "a"
local um = "um"
local ae_gsf = "ae"
local am = "am"
local a_macron = "ā"
local i_pl = stem .. "ī"
if types.greekA or types.greekE then
insert_if_not(subtitles, "Greek-type")
insert_if_not(categories, "Latin first and second declension " .. pos .. " with Greek declension")
if types.greekA then
us = "os"
um = "on"
am = "ān"
else
us = "os"
a_sf = "ē"
um = "on"
ae_gsf = "ēs"
am = "ēn"
a_macron = "ē"
end
i_pl = {i_pl, stem .. "oe"} -- FIXME: add .oe spec.
end
forms["nom_sg_m"] = original or (stem .. us)
forms["nom_sg_f"] = stem .. a_sf
forms["nom_sg_n"] = stem .. um
forms["nom_pl_m"] = i_pl
forms["nom_pl_f"] = stem .. "ae"
forms["nom_pl_n"] = stem .. "a"
forms["gen_sg_m"] = stem .. "ī"
forms["gen_sg_f"] = stem .. ae_gsf
forms["gen_sg_n"] = stem .. "ī"
forms["gen_pl_m"] = stem .. "ōrum"
forms["gen_pl_f"] = stem .. "ārum"
forms["gen_pl_n"] = stem .. "ōrum"
forms["dat_sg_m"] = stem .. "ō"
forms["dat_sg_f"] = stem .. "ae"
forms["dat_sg_n"] = stem .. "ō"
forms["dat_pl_m"] = stem .. "īs"
forms["dat_pl_f"] = stem .. "īs"
forms["dat_pl_n"] = stem .. "īs"
forms["acc_sg_m"] = stem .. um
forms["acc_sg_f"] = stem .. am
forms["acc_sg_n"] = stem .. um
forms["acc_pl_m"] = stem .. "ōs"
forms["acc_pl_f"] = stem .. "ās"
forms["acc_pl_n"] = stem .. "a"
forms["abl_sg_m"] = stem .. "ō"
forms["abl_sg_f"] = stem .. a_macron
forms["abl_sg_n"] = stem .. "ō"
forms["abl_pl_m"] = stem .. "īs"
forms["abl_pl_f"] = stem .. "īs"
forms["abl_pl_n"] = stem .. "īs"
forms["voc_sg_m"] = original or (stem .. "e")
forms["voc_sg_f"] = stem .. a_sf
forms["voc_sg_n"] = stem .. um
forms["voc_pl_m"] = i_pl
forms["voc_pl_f"] = stem .. "ae"
forms["voc_pl_n"] = stem .. "a"
if types.ius then
insert_if_not(subtitles, "pronominal declension")
--insert_if_not(subtitles, "with genitive singular in ''-ī̆us'' and dative singular in ''-ī''")
insert_if_not(categories, "Latin first and second declension " .. pos .. " with genitive singular in -ī̆us")
forms["gen_sg_m"] = stem .. "ī̆us"
forms["gen_sg_f"] = stem .. "ī̆us"
forms["gen_sg_n"] = stem .. "ī̆us"
forms["dat_sg_m"] = stem .. "ī"
forms["dat_sg_f"] = stem .. "ī"
forms["dat_sg_n"] = stem .. "ī"
elseif types.not_ius then
insert_if_not(subtitles, "non-pronominal declension")
--insert_if_not(subtitles, "with normal genitive and dative singular")
end
if stem == "me" then
forms["voc_sg_m"] = "mī"
end
if types.ic then
insert_if_not(subtitles, "''hic''-type")
--insert_if_not(subtitles, "with genitive singular ending in ''-ius'' and dative singular ending in ''-ic''")
local oc = "oc"
local oc_macron = "ōc"
if stem == "ill" then
oc = "uc"
oc_macron = "ūc"
end
forms["nom_sg_m"] = stem .. "ic"
forms["nom_sg_f"] = stem .. "aec"
forms["nom_sg_n"] = stem .. oc
forms["nom_pl_n"] = stem .. "aec"
forms["gen_sg_m"] = stem .. "uius"
forms["gen_sg_f"] = stem .. "uius"
forms["gen_sg_n"] = stem .. "uius"
forms["dat_sg_m"] = stem .. "uic"
forms["dat_sg_f"] = stem .. "uic"
forms["dat_sg_n"] = stem .. "uic"
forms["acc_sg_m"] = stem .. "unc"
forms["acc_sg_f"] = stem .. "anc"
forms["acc_sg_n"] = stem .. oc
forms["acc_pl_n"] = stem .. "aec"
forms["abl_sg_m"] = stem .. "ōc"
forms["abl_sg_f"] = stem .. "āc"
forms["abl_sg_n"] = stem .. oc_macron
forms["voc_sg_m"] = "-"
forms["voc_sg_f"] = "-"
forms["voc_sg_n"] = "-"
forms["voc_pl_m"] = "-"
forms["voc_pl_f"] = "-"
forms["voc_pl_n"] = "-"
end
if types.distr then
if stem:sub(-1) == "n" then
insert_if_not(subtitles, "distributive, normally plural-only; short genitive plurals in ''-num'' preferred")
forms["gen_pl_m"] = {stem .. "um", stem .. "ōrum"}
forms["gen_pl_f"] = {stem .. "um", stem .. "ārum"}
forms["gen_pl_n"] = {stem .. "um", stem .. "ōrum"}
else
error("Unrecognized distributive numeral stem (doesn't end in ''n''): " .. stem)
end
original = stem
stem = args[2]
end
forms["loc_sg_m"] = deep_copy(forms["gen_sg_m"])
forms["loc_sg_f"] = deep_copy(forms["gen_sg_f"])
forms["loc_sg_n"] = deep_copy(forms["gen_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_f"] = deep_copy(forms["abl_pl_f"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin first and second declension " .. pos)
end
decl["1-1+"] = function(data, args)
local forms, pos, subtitles, categories = data.forms, data.pos, data.subtitles, data.categories
local stem = args[1]
data.title = decl_link("first") .. " one-termination " .. singularize(pos)
forms["nom_sg_m"] = stem .. "a"
forms["nom_pl_m"] = stem .. "ae"
forms["nom_pl_n"] = stem .. "a"
forms["gen_sg_m"] = stem .. "ae"
forms["gen_pl_m"] = stem .. "ārum"
forms["dat_sg_m"] = stem .. "ae"
forms["dat_pl_m"] = stem .. "īs"
forms["acc_sg_m"] = stem .. "am"
forms["acc_sg_n"] = stem .. "a"
forms["acc_pl_m"] = stem .. "ās"
forms["acc_pl_n"] = stem .. "a"
forms["abl_sg_m"] = stem .. "ā"
forms["abl_pl_m"] = stem .. "īs"
forms["voc_sg_m"] = stem .. "a"
forms["voc_pl_m"] = stem .. "ae"
forms["voc_pl_n"] = stem .. "a"
forms["loc_sg_m"] = deep_copy(forms["gen_sg_m"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
insert_if_not(categories, "Latin first declension " .. data.pos)
end
decl["2-2+"] = function(data, args)
local forms, types, pos, subtitles, categories = data.forms, data.types, data.pos, data.subtitles, data.categories
local stem = args[1]
data.title = decl_link("second") .. " two-termination " .. singularize(pos)
local us = "us"
local um = "um"
local i_pl = stem .. "ī"
if types.greek then
insert_if_not(subtitles, "Greek-type")
insert_if_not(categories, "Latin second declension " .. pos .. " with Greek declension")
us = "os"
um = "on"
i_pl = {i_pl, stem .. "oe"} -- FIXME: add .oe spec.
end
forms["nom_sg_m"] = stem .. us
forms["nom_sg_n"] = stem .. um
forms["nom_pl_m"] = i_pl
forms["nom_pl_n"] = stem .. "a"
forms["gen_sg_m"] = stem .. "ī"
forms["gen_sg_n"] = stem .. "ī"
forms["gen_pl_m"] = stem .. "ōrum"
forms["gen_pl_n"] = stem .. "ōrum"
forms["dat_sg_m"] = stem .. "ō"
forms["dat_sg_n"] = stem .. "ō"
forms["dat_pl_m"] = stem .. "īs"
forms["dat_pl_n"] = stem .. "īs"
forms["acc_sg_m"] = stem .. um
forms["acc_sg_n"] = stem .. um
forms["acc_pl_m"] = stem .. "ōs"
forms["acc_pl_n"] = stem .. "a"
forms["abl_sg_m"] = stem .. "ō"
forms["abl_sg_n"] = stem .. "ō"
forms["abl_pl_m"] = stem .. "īs"
forms["abl_pl_n"] = stem .. "īs"
forms["voc_sg_m"] = stem .. "e"
forms["voc_sg_n"] = stem .. um
forms["voc_pl_m"] = i_pl
forms["voc_pl_n"] = stem .. "a"
forms["loc_sg_m"] = deep_copy(forms["gen_sg_m"])
forms["loc_sg_n"] = deep_copy(forms["gen_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin second declension " .. pos)
end
local function abl_i_e(...)
local function update_slot(forms, slot, f, do_copy)
if not forms[slot] then
return do_copy
elseif do_copy then
f = deep_copy(f)
end
forms[slot] = f
return true
end
function abl_i_e(stem, forms, types)
local f, do_copy
if types["abl_e_i"] then
f = {stem .. "e", stem .. "ī"}
elseif types["abl_i_e"] then
f = {stem .. "ī", stem .. "e"}
else
return
end
do_copy = update_slot(forms, "abl_sg_m", f, do_copy)
do_copy = update_slot(forms, "abl_sg_f", f, do_copy)
-- Neuter doesn't take -e with i-stems.
if not types.I then
update_slot(forms, "abl_sg_n", f, do_copy)
end
end
return abl_i_e(...)
end
decl["3-1+"] = function(data, args)
local forms, types, pos, subtitles, notes, categories = data.forms, data.types, data.pos, data.subtitles, data.notes, data.categories
local stem1, stem2 = args[1], args[2]
local singpos = singularize(pos)
if data.gender then
data.title = decl_link("third") .. " " .. singpos
else
data.title = decl_link("third") .. " one-termination " .. singpos
end
forms["nom_sg_m"] = stem1
forms["nom_sg_n"] = stem1
forms["nom_pl_m"] = stem2 .. "ēs"
forms["nom_pl_n"] = stem2 .. "ia"
forms["gen_sg_m"] = stem2 .. "is"
forms["gen_sg_n"] = stem2 .. "is"
forms["gen_pl_m"] = stem2 .. "ium"
forms["gen_pl_n"] = stem2 .. "ium"
forms["dat_sg_m"] = stem2 .. "ī"
forms["dat_sg_n"] = stem2 .. "ī"
forms["dat_pl_m"] = stem2 .. "ibus"
forms["dat_pl_n"] = stem2 .. "ibus"
forms["acc_sg_m"] = stem2 .. "em"
forms["acc_sg_n"] = stem1
forms["acc_pl_m"] = {stem2 .. "īs", stem2 .. "ēs"}
forms["acc_pl_n"] = stem2 .. "ia"
forms["abl_sg_m"] = {stem2 .. "ī", stem2 .. "e"}
forms["abl_sg_n"] = {stem2 .. "ī", stem2 .. "e"}
forms["abl_pl_m"] = stem2 .. "ibus"
forms["abl_pl_n"] = stem2 .. "ibus"
forms["voc_sg_m"] = stem1
forms["voc_sg_n"] = stem1
forms["voc_pl_m"] = stem2 .. "ēs"
forms["voc_pl_n"] = stem2 .. "ia"
if types.par then
insert_if_not(subtitles, "non-i-stem")
forms["abl_sg_m"] = stem2 .. "e"
forms["abl_sg_n"] = stem2 .. "e"
forms["nom_pl_n"] = stem2 .. "a"
forms["gen_pl_m"] = stem2 .. "um"
forms["gen_pl_n"] = stem2 .. "um"
forms["acc_pl_m"] = stem2 .. "ēs"
forms["acc_pl_n"] = stem2 .. "a"
forms["voc_pl_n"] = stem2 .. "a"
elseif types.not_par then
insert_if_not(subtitles, "i-stem")
end
local es_base = stem1:match("^(.-)ēs$")
if es_base and es_base == stem2 then
if types.greek then
local note1 = "It is unknown whether adjectives of this type would use i-stem or consonant-stem endings in Classical Latin: the relevant forms are not attested. Depending on the word, either ending or both may be attested in New Latin."
forms["nom_sg_n"] = stem2 .. "es"
forms["acc_sg_n"] = stem2 .. "es"
forms["voc_sg_n"] = stem2 .. "es"
forms["nom_pl_n"] = {stem2 .. "a", stem2 .. "ia"}
notes["nom_pl_n2"] = note1
forms["acc_pl_n"] = {stem2 .. "a", stem2 .. "ia"}
notes["acc_pl_n2"] = note1
forms["voc_pl_n"] = {stem2 .. "a", stem2 .. "ia"}
notes["voc_pl_n2"] = note1
forms["abl_sg_m"] = {stem2 .. "e", stem2 .. "ī"}
notes["abl_sg_m2"] = note1
forms["abl_sg_n"] = {stem2 .. "e", stem2 .. "ī"}
notes["abl_sg_n2"] = note1
notes["loc_sg_m2"] = note1 -- same as abl_sg_m2
notes["loc_sg_n2"] = note1 -- same as abl_sg_n2
forms["gen_pl_m"] = {stem2 .. "um", stem2 .. "ium"}
notes["gen_pl_m2"] = note1
forms["gen_pl_n"] = {stem2 .. "um", stem2 .. "ium"}
notes["gen_pl_n2"] = note1
insert_if_not(subtitles, "Greek-type")
elseif types.not_greek then
insert_if_not(subtitles, "non-Greek-type")
end
end
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
insert_if_not(categories, "Latin third declension " .. pos .. " of one termination")
end
decl["3-def+"] = function(data, args)
local forms, types, pos, subtitles, notes, categories = data.forms, data.types, data.pos, data.subtitles, data.notes, data.categories
local stem1, stem2 = args[1], args[2]
local singpos = singularize(pos)
if data.gender then
data.title = decl_link("third") .. " " .. singpos
else
data.title = decl_link("third") .. " defective " .. singpos
end
forms["nom_sg_m"] = stem1
forms["nom_sg_n"] = stem1
forms["nom_pl_m"] = stem2 .. "ēs"
forms["nom_pl_n"] = stem2 .. "ia"
forms["gen_sg_m"] = stem2 .. "is"
forms["gen_sg_n"] = stem2 .. "is"
forms["gen_pl_m"] = stem2 .. "ium"
forms["gen_pl_n"] = stem2 .. "ium"
forms["dat_sg_m"] = stem2 .. "ī"
forms["dat_sg_n"] = stem2 .. "ī"
forms["dat_pl_m"] = stem2 .. "ibus"
forms["dat_pl_n"] = stem2 .. "ibus"
forms["acc_sg_m"] = stem2 .. "em"
forms["acc_sg_n"] = stem1
forms["acc_pl_m"] = stem2 .. "ēs"
forms["acc_pl_n"] = stem2 .. "ia"
forms["abl_sg_m"] = stem2 .. "ī"
forms["abl_sg_n"] = stem2 .. "ī"
forms["abl_pl_m"] = stem2 .. "ibus"
forms["abl_pl_n"] = stem2 .. "ibus"
forms["voc_sg_m"] = stem1
forms["voc_sg_n"] = stem1
forms["voc_pl_m"] = stem2 .. "ēs"
forms["voc_pl_n"] = stem2 .. "ia"
if types.tor then
data.title = decl_link("third") .. " masculine-only " .. singpos
insert_if_not(subtitles, "non-i-stem")
remove_forms(forms, {"_f$", "_n$"})
forms["nom_sg_m"] = stem1
forms["gen_sg_m"] = stem2 .. "is"
forms["dat_sg_m"] = stem2 .. "ī"
forms["acc_sg_m"] = stem2 .. "em"
forms["abl_sg_m"] = stem2 .. "e"
forms["voc_sg_m"] = stem1
forms["nom_pl_m"] = stem2 .. "ēs"
forms["gen_pl_m"] = stem2 .. "um"
forms["dat_pl_m"] = stem2 .. "ibus"
forms["acc_pl_m"] = stem2 .. "ēs"
forms["abl_pl_m"] = stem2 .. "ibus"
forms["voc_pl_m"] = stem2 .. "ēs"
insert_if_not(categories, "Latin third declension masculine-only adjectives")
end
if types.trix then
insert_if_not(subtitles, "feminine-only when singular, feminine or neuter when plural")
remove_forms(forms, {"_m$", "sg_n$"})
forms["nom_sg_f"] = stem1
forms["gen_sg_f"] = stem2 .. "is"
forms["dat_sg_f"] = stem2 .. "ī"
forms["acc_sg_f"] = stem2 .. "em"
forms["abl_sg_f"] = {stem2 .. "e", stem2 .. "ī"}
forms["voc_sg_f"] = stem1
forms["nom_pl_f"] = stem2 .. "ēs"
forms["gen_pl_f"] = stem2 .. "ium"
forms["dat_pl_f"] = stem2 .. "ibus"
forms["acc_pl_f"] = stem2 .. "ēs"
forms["abl_pl_f"] = stem2 .. "ibus"
forms["voc_pl_f"] = stem2 .. "ēs"
insert_if_not(categories, "Latin third declension feminine- and neuter-only adjectives")
end
if types.trixf then
data.title = decl_link("third") .. " feminine-only " .. singpos
remove_forms(forms, {"_m$", "_n$"})
forms["nom_sg_f"] = stem1
forms["gen_sg_f"] = stem2 .. "is"
forms["dat_sg_f"] = stem2 .. "ī"
forms["acc_sg_f"] = stem2 .. "em"
forms["abl_sg_f"] = {stem2 .. "e", stem2 .. "ī"}
forms["voc_sg_f"] = stem1
forms["nom_pl_f"] = stem2 .. "ēs"
forms["gen_pl_f"] = stem2 .. "ium"
forms["dat_pl_f"] = stem2 .. "ibus"
forms["acc_pl_f"] = stem2 .. "ēs"
forms["abl_pl_f"] = stem2 .. "ibus"
forms["voc_pl_f"] = stem2 .. "ēs"
insert_if_not(categories, "Latin third declension feminine-only adjectives")
end
if types.idis then
data.title = decl_link("third") .. " feminine-only " .. singpos
insert_if_not(subtitles, "non-Greek-type or Greek-type")
insert_if_not(subtitles, "non-i-stem")
remove_forms(forms, {"_m$", "_n$"})
forms["nom_sg_f"] = stem1
forms["gen_sg_f"] = {stem2 .. "is", stem2 .. "os"}
forms["dat_sg_f"] = stem2 .. "ī"
forms["acc_sg_f"] = {stem2 .. "em", stem2 .. "a"}
forms["abl_sg_f"] = stem2 .. "e"
forms["voc_sg_f"] = stem1
forms["nom_pl_f"] = stem2 .. "ē̆s"
forms["gen_pl_f"] = stem2 .. "um"
forms["dat_pl_f"] = stem2 .. "ibus"
forms["acc_pl_f"] = {stem2 .. "ēs", stem2 .. "as"}
forms["abl_pl_f"] = stem2 .. "ibus"
forms["voc_pl_f"] = stem2 .. "ē̆s"
if umatch(toNFD(stem1), "[iyIY]" .. accent .. "s$") then
-- Per Hiley, words in -is and -ys have a poetic vocative
-- without the -s, but otherwise the vocative is the same
-- as the nominative.
forms["voc_sg_f"] = {stem1, (stem1:gsub("s$", ""))}
notes["voc_sg_f2"] = "In poetry."
end
insert_if_not(categories, "Latin third declension feminine-only adjectives")
end
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_sg_f"] = deep_copy(forms["abl_sg_f"])
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_f"] = deep_copy(forms["abl_pl_f"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
end
decl["3-C+"] = function(data, args)
local forms, types, pos, categories = data.forms, data.types, data.pos, data.categories
local stem1 = args[1]
local stem2 = stem1 .. "ōr"
data.title = decl_link("third") .. " comparative " .. singularize(pos)
forms["nom_sg_m"] = stem1 .. "or"
forms["nom_sg_n"] = stem1 .. "us"
forms["nom_pl_m"] = stem2 .. "ēs"
forms["nom_pl_n"] = stem2 .. "a"
forms["gen_sg_m"] = stem2 .. "is"
forms["gen_sg_n"] = stem2 .. "is"
forms["gen_pl_m"] = stem2 .. "um"
forms["gen_pl_n"] = stem2 .. "um"
forms["dat_sg_m"] = stem2 .. "ī"
forms["dat_sg_n"] = stem2 .. "ī"
forms["dat_pl_m"] = stem2 .. "ibus"
forms["dat_pl_n"] = stem2 .. "ibus"
forms["acc_sg_m"] = stem2 .. "em"
forms["acc_sg_n"] = stem1 .. "us"
forms["acc_pl_m"] = {stem2 .. "ēs", stem2 .. "īs"}
forms["acc_pl_n"] = stem2 .. "a"
forms["abl_sg_m"] = stem2 .. "ī"
forms["abl_sg_n"] = stem2 .. "ī"
forms["abl_pl_m"] = stem2 .. "ibus"
forms["abl_pl_n"] = stem2 .. "ibus"
abl_i_e(stem2, forms, types)
forms["voc_sg_m"] = stem1 .. "or"
forms["voc_sg_n"] = stem1 .. "us"
forms["voc_pl_m"] = stem2 .. "ēs"
forms["voc_pl_n"] = stem2 .. "a"
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
insert_if_not(categories, "Latin comparative adjectives")
end
decl["3-P+"] = function(data, args)
local forms, notes = data.forms, data.notes
local stem2 = args[2]
decl["3-1+"](data, args)
data.title = decl_link("third") .. " participle"
local note1 = "When used purely as an adjective."
forms["abl_sg_m"] = {stem2 .. "e", stem2 .. "ī"}
notes["abl_sg_m2"] = note1
forms["abl_sg_n"] = {stem2 .. "e", stem2 .. "ī"}
notes["abl_sg_n2"] = note1
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
notes["loc_sg_m2"] = note1 -- same as abl_sg_m2
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
notes["loc_sg_n2"] = note1 -- same as abl_sg_n2
forms["acc_pl_m"] = {stem2 .. "ēs", stem2 .. "īs"}
end
decl["3-2+"] = function(data, args)
local forms, types, pos, categories = data.forms, data.types, data.pos, data.categories
local stem = args[1]
local singpos = singularize(pos)
if data.gender then
data.title = decl_link("third") .. " " .. singpos
else
data.title = decl_link("third") .. " two-termination " .. singpos
end
forms["nom_sg_m"] = stem .. "is"
forms["nom_sg_n"] = stem .. "e"
forms["nom_pl_m"] = stem .. "ēs"
forms["nom_pl_n"] = stem .. "ia"
forms["gen_sg_m"] = stem .. "is"
forms["gen_sg_n"] = stem .. "is"
forms["gen_pl_m"] = stem .. "ium"
forms["gen_pl_n"] = stem .. "ium"
forms["dat_sg_m"] = stem .. "ī"
forms["dat_sg_n"] = stem .. "ī"
forms["dat_pl_m"] = stem .. "ibus"
forms["dat_pl_n"] = stem .. "ibus"
forms["acc_sg_m"] = stem .. "em"
forms["acc_sg_n"] = stem .. "e"
forms["acc_pl_m"] = {stem .. "īs", stem .. "ēs"}
forms["acc_pl_n"] = stem .. "ia"
forms["abl_sg_m"] = stem .. "ī"
forms["abl_sg_n"] = stem .. "ī"
forms["abl_pl_m"] = stem .. "ibus"
forms["abl_pl_n"] = stem .. "ibus"
-- abl_i_e(stem, forms, types) -- enable once [[Module:la-nominal]] has ben updated
forms["voc_sg_m"] = stem .. "is"
forms["voc_sg_n"] = stem .. "e"
forms["voc_pl_m"] = stem .. "ēs"
forms["voc_pl_n"] = stem .. "ia"
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
insert_if_not(categories, "Latin third declension " .. pos .. " of two terminations")
end
decl["3-3+"] = function(data, args)
local forms, types, pos, categories = data.forms, data.types, data.pos, data.categories
local stem1, stem2 = args[1], args[2]
local singpos = singularize(pos)
if data.gender then
data.title = decl_link("third") .. " " .. singpos
else
data.title = decl_link("third") .. " three-termination " .. singpos
end
forms["nom_sg_m"] = stem1
forms["nom_sg_f"] = stem2 .. "is"
forms["nom_sg_n"] = stem2 .. "e"
forms["nom_pl_m"] = stem2 .. "ēs"
forms["nom_pl_f"] = stem2 .. "ēs"
forms["nom_pl_n"] = stem2 .. "ia"
forms["gen_sg_m"] = stem2 .. "is"
forms["gen_sg_f"] = stem2 .. "is"
forms["gen_sg_n"] = stem2 .. "is"
forms["gen_pl_m"] = stem2 .. "ium"
forms["gen_pl_f"] = stem2 .. "ium"
forms["gen_pl_n"] = stem2 .. "ium"
forms["dat_sg_m"] = stem2 .. "ī"
forms["dat_sg_f"] = stem2 .. "ī"
forms["dat_sg_n"] = stem2 .. "ī"
forms["dat_pl_m"] = stem2 .. "ibus"
forms["dat_pl_f"] = stem2 .. "ibus"
forms["dat_pl_n"] = stem2 .. "ibus"
forms["acc_sg_m"] = stem2 .. "em"
forms["acc_sg_f"] = stem2 .. "em"
forms["acc_sg_n"] = stem2 .. "e"
forms["acc_pl_m"] = {stem2 .. "īs", stem2 .. "ēs"}
forms["acc_pl_f"] = {stem2 .. "īs", stem2 .. "ēs"}
forms["acc_pl_n"] = stem2 .. "ia"
forms["abl_sg_m"] = stem2 .. "ī"
forms["abl_sg_f"] = stem2 .. "ī"
forms["abl_sg_n"] = stem2 .. "ī"
forms["abl_pl_m"] = stem2 .. "ibus"
forms["abl_pl_f"] = stem2 .. "ibus"
forms["abl_pl_n"] = stem2 .. "ibus"
-- abl_i_e(stem2, forms, types) -- enable once [[Module:la-nominal]] has ben updated
forms["voc_sg_m"] = stem1
forms["voc_sg_f"] = stem2 .. "is"
forms["voc_sg_n"] = stem2 .. "e"
forms["voc_pl_m"] = stem2 .. "ēs"
forms["voc_pl_f"] = stem2 .. "ēs"
forms["voc_pl_n"] = stem2 .. "ia"
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_sg_f"] = deep_copy(forms["abl_sg_f"])
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_f"] = deep_copy(forms["abl_pl_f"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
insert_if_not(categories, "Latin third declension " .. pos .. " of three terminations")
end
decl["indecl+"] = function(data, args)
local forms, subtitles, categories = data.forms, data.subtitles, data.categories
local stem = args[1]
insert_if_not(subtitles, "used only in the nominative and accusative")
forms["nom_sg_m"] = stem
forms["nom_pl_m"] = "-"
forms["gen_sg_m"] = "-"
forms["gen_pl_m"] = "-"
forms["dat_sg_m"] = "-"
forms["dat_pl_m"] = "-"
forms["acc_sg_m"] = stem
forms["acc_pl_m"] = "-"
forms["abl_sg_m"] = "-"
forms["abl_pl_m"] = "-"
forms["voc_sg_m"] = "-"
forms["voc_pl_m"] = "-"
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
insert_if_not(categories, "Latin indeclinable " .. data.pos)
end
decl["irreg+"] = function(data, args)
local forms, types, pos, notes, categories = data.forms, data.types, data.pos, data.notes, data.categories
local arg1 = args[1]
if arg1 == "duo" or arg1 == "ambō" then
local stem = usub(arg1, 1, -2)
data.title = stem == "amb" and glossary_link("irregular") .. " adjective" or "numeral"
data.num = "pl"
local stem_with_o = stem .. (stem == "amb" and "ō" or "o")
local note1 = preprocess("Genitive plural {{m|la|duum}} is sometimes spelled {{m|la|duûm}} in New Latin texts. Its ending {{m|la|-um|id=genitive plural}} is the regular outcome of the original second-declension genitive plural ending (compare Greek {{m|grc|-ων}}, {{m|grc|-ῶν}}) not a contraction of {{m|la||-ōrum}} (a newer innovation). The corresponding Old Latin form {{m|la|duom}} is used by Plautus and mentioned by Cicero; it was potentially pronounced as {{m|la|duōm}} in Archaic Latin, but some linguists believe vowels were shortened before final {{m|la||-m}} already in Proto-Italic.")
forms["nom_pl_m"] = stem_with_o
forms["nom_pl_f"] = stem .. "ae"
forms["nom_pl_n"] = stem_with_o
forms["gen_pl_m"] = stem .. "ōrum"
forms["gen_pl_f"] = stem .. "ārum"
forms["gen_pl_n"] = stem .. "ōrum"
forms["dat_pl_m"] = stem .. "ōbus"
forms["dat_pl_f"] = stem .. "ābus"
forms["dat_pl_n"] = stem .. "ōbus"
forms["acc_pl_m"] = {stem .. "ōs", stem_with_o}
forms["acc_pl_f"] = stem .. "ās"
forms["acc_pl_n"] = stem_with_o
forms["abl_pl_m"] = stem .. "ōbus"
forms["abl_pl_f"] = stem .. "ābus"
forms["abl_pl_n"] = stem .. "ōbus"
forms["voc_pl_m"] = stem_with_o
forms["voc_pl_f"] = stem .. "ae"
forms["voc_pl_n"] = stem_with_o
if stem == "du" then
forms["gen_pl_m"] = {forms["gen_pl_m"], "duum"}
notes["gen_pl_m2"] = note1
forms["gen_pl_n"] = {forms["gen_pl_n"], "duum"}
notes["gen_pl_n2"] = note1
end
elseif arg1:sub(-6) == "mīlle" then
data.title = "semi-" .. glossary_link("indeclinable") .. " numeral"
local stem = arg1:sub(1, -3)
forms["nom_sg_m"] = stem .. "le"
forms["nom_pl_m"] = {stem .. "ia", stem .. "lia"}
forms["gen_sg_m"] = stem .. "le"
forms["gen_pl_m"] = {stem .. "ium", stem .. "lium"}
forms["dat_sg_m"] = stem .. "le"
forms["dat_pl_m"] = {stem .. "ibus", stem .. "libus"}
forms["acc_sg_m"] = stem .. "le"
forms["acc_pl_m"] = {stem .. "ia", stem .. "lia"}
forms["abl_sg_m"] = stem .. "le"
forms["abl_pl_m"] = {stem .. "ibus", stem .. "libus"}
forms["voc_sg_m"] = stem .. "le"
forms["voc_pl_m"] = {stem .. "ia", stem .. "lia"}
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
elseif arg1 == "ille" or arg1 == "iste" or arg1 == "ipse" or arg1 == "olle" then
local stem = arg1:sub(1, -2)
types.ius = true
decl["1&2+"](data, {stem})
data.title = glossary_link("demonstrative") .. " " .. singularize(data.pos)
forms["nom_sg_m"] = arg1
if arg1 == "ipse" then
local note1 = "Medieval Latin."
add_form(forms, "nom_sg_n", stem, "ud")
notes["nom_sg_n2"] = note1
add_form(forms, "acc_sg_n", stem, "ud")
notes["acc_sg_n2"] = note1
else
forms["nom_sg_n"] = stem .. "ud"
forms["acc_sg_n"] = stem .. "ud"
end
forms["voc_sg_m"] = "-"
forms["voc_sg_f"] = "-"
forms["voc_sg_n"] = "-"
forms["voc_pl_m"] = "-"
forms["voc_pl_f"] = "-"
forms["voc_pl_n"] = "-"
empty_table(categories)
elseif arg1 == "illic" or arg1 == "istic" or arg1 == "isthic" then
data.title = glossary_link("demonstrative") .. " " .. singularize(data.pos)
local stem, unattested = arg1:sub(1, -3), data.unattested
forms["nom_sg_m"] = stem .. "ic"
forms["nom_sg_f"] = stem .. "aec"
forms["nom_sg_n"] = {stem .. "uc", stem .. "ucce", stem .. "oc"}
forms["gen_sg_m"] = stem .. "ī̆usce"
forms["gen_sg_f"] = stem .. "ī̆usce"
forms["gen_sg_n"] = stem .. "ī̆usce"
forms["dat_sg_m"] = stem .. "īc"
forms["dat_sg_f"] = stem .. "īc"
forms["dat_sg_n"] = stem .. "īc"
forms["acc_sg_m"] = stem .. "unc"
forms["acc_sg_f"] = stem .. "anc"
forms["acc_sg_n"] = {stem .. "uc", stem .. "ucce", stem .. "oc"}
forms["abl_sg_m"] = stem .. "ōc"
forms["abl_sg_f"] = stem .. "āc"
forms["abl_sg_n"] = stem .. "ōc"
forms["loc_sg_m"] = deep_copy(forms["gen_sg_m"])
forms["loc_sg_f"] = deep_copy(forms["gen_sg_f"])
forms["loc_sg_n"] = deep_copy(forms["gen_sg_n"])
forms["nom_pl_m"] = stem .. "īsce"
forms["nom_pl_f"] = stem .. "aec"
forms["nom_pl_n"] = stem .. "aec"
forms["gen_pl_m"] = stem .. "ōrunc"
unattested["gen_pl_m"] = true
forms["gen_pl_f"] = stem .. "ārunc"
unattested["gen_pl_f"] = true
forms["gen_ok_n"] = stem .. "ōrunc"
unattested["gen_pl_n"] = true
forms["dat_pl_m"] = stem .. "īsce"
forms["dat_pl_f"] = stem .. "īsce"
forms["dat_pl_n"] = stem .. "īsce"
forms["acc_pl_m"] = stem .. "ōsce"
forms["acc_pl_f"] = stem .. "āsce"
forms["acc_pl_n"] = stem .. "aec"
forms["abl_pl_m"] = stem .. "īsce"
forms["abl_pl_f"] = stem .. "īsce"
forms["abl_pl_n"] = stem .. "īsce"
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_f"] = deep_copy(forms["abl_pl_f"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
elseif arg1 == "hice" then
data.title = glossary_link("demonstrative") .. " pronoun"
forms["nom_sg_m"] = "hice"
forms["nom_sg_f"] = "haece"
forms["nom_sg_n"] = "hoce"
forms["nom_pl_m"] = "hīce"
forms["nom_pl_f"] = "haece"
forms["nom_pl_n"] = "haece"
forms["gen_sg_m"] = "huiusce"
forms["gen_sg_f"] = "huiusce"
forms["gen_sg_n"] = "huiusce"
forms["gen_pl_m"] = {"hōrunce", "hōrumce"}
forms["gen_pl_f"] = {"hārunce", "hārumce"}
forms["gen_pl_n"] = {"hōrunce", "hōrumce"}
forms["dat_sg_m"] = "huīce"
forms["dat_sg_f"] = "huīce"
forms["dat_sg_n"] = "huīce"
forms["dat_pl_m"] = "hīsce"
forms["dat_pl_f"] = "hīsce"
forms["dat_pl_n"] = "hīsce"
forms["acc_sg_m"] = "hunce"
forms["acc_sg_f"] = "hance"
forms["acc_sg_n"] = "hoce"
forms["acc_pl_m"] = "hōsce"
forms["acc_pl_f"] = "hāsce"
forms["acc_pl_n"] = "haece"
forms["abl_sg_m"] = "hōce"
forms["abl_sg_f"] = "hāce"
forms["abl_sg_n"] = "hōce"
forms["abl_pl_m"] = "hīsce"
forms["abl_pl_f"] = "hīsce"
forms["abl_pl_n"] = "hīsce"
forms["loc_sg_m"] = deep_copy(forms["gen_sg_m"])
forms["loc_sg_f"] = deep_copy(forms["gen_sg_f"])
forms["loc_sg_n"] = deep_copy(forms["gen_sg_n"])
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_f"] = deep_copy(forms["abl_pl_f"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
elseif arg1 == "plūs" then
data.title = glossary_link("irregular") .. " " .. decl_link("third") .. " comparative " .. singularize(pos) .. ", plural-only in Classical Latin"
local note1 = "None of the singular forms are used as adjectives in Classical Latin."
forms["nom_sg_n"] = "plūs"
notes["nom_sg_n1"] = note1
forms["nom_pl_m"] = "plūrēs"
forms["nom_pl_n"] = "plūra"
forms["gen_sg_m"] = "plūris"
notes["gen_sg_m1"] = note1
forms["gen_sg_n"] = "plūris"
notes["gen_sg_n1"] = note1
forms["gen_pl_m"] = "plūrium"
forms["gen_pl_n"] = "plūrium"
forms["dat_sg_m"] = "plūrī"
notes["dat_sg_m1"] = note1
forms["dat_sg_n"] = "plūrī"
notes["dat_sg_n1"] = note1
forms["dat_pl_m"] = "plūribus"
forms["dat_pl_n"] = "plūribus"
forms["acc_sg_m"] = "plūrem"
notes["acc_sg_m1"] = note1
forms["acc_sg_f"] = "plūrem"
notes["acc_sg_f1"] = note1
forms["acc_sg_n"] = "plūs"
notes["acc_sg_n1"] = note1
forms["acc_pl_m"] = {"plūrēs", "plūrīs"}
forms["acc_pl_n"] = "plūra"
forms["abl_sg_m"] = {"plūrī", "plūre"}
notes["abl_sg_m1"] = note1
notes["abl_sg_m2"] = note1
forms["abl_sg_f"] = {"plūrī", "plūre"}
notes["abl_sg_f1"] = note1
notes["abl_sg_f2"] = note1
forms["abl_sg_n"] = {"plūrī", "plūre"}
notes["abl_sg_n1"] = note1
notes["abl_sg_n2"] = note1
forms["abl_pl_m"] = "plūribus"
forms["abl_pl_n"] = "plūribus"
forms["voc_sg_n"] = "plūs"
notes["voc_sg_n1"] = note1
forms["voc_pl_m"] = "plūrēs"
forms["voc_pl_n"] = "plūra"
forms["loc_sg_m"] = deep_copy(forms["abl_sg_m"])
notes["loc_sg_m1"] = note1
notes["loc_sg_m2"] = note1
forms["loc_sg_f"] = deep_copy(forms["abl_sg_f"])
notes["loc_sg_f1"] = note1
notes["loc_sg_f2"] = note1
forms["loc_sg_n"] = deep_copy(forms["abl_sg_n"])
notes["loc_sg_n1"] = note1
notes["loc_sg_n2"] = note1
forms["loc_pl_m"] = deep_copy(forms["abl_pl_m"])
forms["loc_pl_n"] = deep_copy(forms["abl_pl_n"])
insert_if_not(categories, "Latin third declension " .. pos)
insert_if_not(categories, "Latin third declension " .. pos .. " of one termination")
elseif umatch(arg1, "^egō̆?$") or arg1 == "nōs" then
data.title = glossary_link("personal") .. " pronoun"
forms["nom_sg_m"] = arg1
forms["nom_pl_m"] = "nōs"
forms["gen_sg_m"] = "meī"
forms["gen_pl_m"] = {"nostrī", "nostrum"}
forms["dat_sg_m"] = "mihī̆"
forms["dat_pl_m"] = "nōbīs"
forms["acc_sg_m"] = {"mē", "mēmē"}
forms["acc_pl_m"] = "nōs"
forms["abl_sg_m"] = {"mē", "mēmē"}
forms["abl_pl_m"] = "nōbīs"
forms["voc_sg_m"] = arg1
forms["voc_pl_m"] = "nōs"
elseif arg1 == "tū" or arg1 == "vōs" then
data.title = glossary_link("personal") .. " pronoun"
forms["nom_sg_m"] = arg1
forms["nom_pl_m"] = "vōs"
forms["gen_sg_m"] = "tuī"
forms["gen_pl_m"] = {"vestrī", "vestrum"}
forms["dat_sg_m"] = "tibī̆"
forms["dat_pl_m"] = "vōbīs"
forms["acc_sg_m"] = {"tē", "tētē"}
forms["acc_pl_m"] = "vōs"
forms["abl_sg_m"] = {"tē", "tētē"}
forms["abl_pl_m"] = "vōbīs"
forms["voc_sg_m"] = arg1
forms["voc_pl_m"] = "vōs"
elseif arg1 == "suī" then
data.title = glossary_link("reflexive") .. " pronoun"
forms["nom_sg_m"] = "-"
forms["nom_pl_m"] = "-"
forms["gen_sg_m"] = arg1
forms["gen_pl_m"] = forms["gen_sg_m"]
forms["dat_sg_m"] = "sibī̆"
forms["dat_pl_m"] = forms["dat_sg_m"]
forms["acc_sg_m"] = {"sē", "sēsē"}
forms["acc_pl_m"] = {"sē", "sēsē"}
forms["abl_sg_m"] = {"sē", "sēsē"}
forms["abl_pl_m"] = {"sē", "sēsē"}
forms["voc_sg_m"] = "-"
forms["voc_pl_m"] = "-"
elseif arg1 == "is" or arg1 == "īdem" then
data.title = glossary_link("demonstrative") .. " pronoun"
local note1 = preprocess("The dative singular is found spelled {{orth|{{sma|{{lang|la|EIEI}}}}}} (here represented as {{m|la||-ēī}}), and scanned as two longs in {{w|Plautus}}, but also as a monosyllable; the latter is its normal scansion in Classical. Other spellings include {{orth|{{sma|{{lang|la|EEI}}}}}}{{,}} and {{orth|{{sma|{{lang|la|IEI}}}}}}.")
local note2 = preprocess("The nominative/dative/ablative plural forms regularly developed into a monosyllable {{IPAchar|/iː(s)/}}, with later remodelling; compare the etymology of {{m|la|deus}}. This {{IPAchar|/iː/}} was normally spelled as {{orth|{{sma|{{lang|la|EI}}}}}} during and as {{orth|{{sma|{{lang|la|II}}}}}} after the Republic; a disyllabic {{m|la||-iī}}, spelled {{orth|{{sma|{{lang|la|II}}}}}}, {{orth|{{sma|{{lang|la|I}}}}}}, appears in Silver Age poetry, while disyllabic {{m|la||-eīs}} is only post-Classical. Other spellings include {{orth|{{sma|{{lang|la|EEI(S)}}}}}}, {{orth|{{sma|{{lang|la|EIEI(S)}}}}}}{{,}} and {{orth|{{sma|{{lang|la|IEI(S)}}}}}}.")
forms["nom_sg_m"] = "is"
forms["nom_sg_f"] = "ea"
forms["nom_sg_n"] = "id"
forms["nom_pl_m"] = {"iī", "eī", "ī"}
notes["nom_pl_m1"] = note2
forms["nom_pl_f"] = "eae"
forms["nom_pl_n"] = "ea"
forms["gen_sg_m"] = {"eius", "ejus"}
forms["gen_sg_f"] = {"eius", "ejus"}
forms["gen_sg_n"] = {"eius", "ejus"}
forms["gen_pl_m"] = {"eōrum", "eum"}
forms["gen_pl_f"] = "eārum"
forms["gen_pl_n"] = {"eōrum", "eum"}
forms["dat_sg_m"] = {"eī", "e͡i", "ēī"}
notes["dat_sg_m1"] = note1
forms["dat_sg_f"] = {"eī", "e͡i", "ēī", "eae"}
notes["dat_sg_f1"] = note1
forms["dat_sg_n"] = {"eī", "e͡i", "ēī"}
notes["dat_sg_n1"] = note1
forms["dat_pl_m"] = {"iīs", "eīs", "īs", "ībus"}
notes["dat_pl_m1"] = note2
forms["dat_pl_f"] = {"iīs", "eīs", "īs", "eābus"}
notes["dat_pl_f1"] = note2
forms["dat_pl_n"] = {"iīs", "eīs", "īs"}
notes["dat_pl_n1"] = note2
forms["acc_sg_m"] = "eum"
forms["acc_sg_f"] = "eam"
forms["acc_sg_n"] = "id"
forms["acc_pl_m"] = "eōs"
forms["acc_pl_f"] = "eās"
forms["acc_pl_n"] = "ea"
forms["abl_sg_m"] = "eō"
forms["abl_sg_f"] = "eā"
forms["abl_sg_n"] = "eō"
forms["abl_pl_m"] = {"iīs", "eīs", "īs"}
notes["abl_pl_m1"] = note2
forms["abl_pl_f"] = {"iīs", "eīs", "īs"}
notes["abl_pl_f1"] = note2
forms["abl_pl_n"] = {"iīs", "eīs", "īs"}
notes["abl_pl_n1"] = note2
if arg1 == "īdem" then
forms["nom_sg_m"] = "ī"
forms["nom_sg_n"] = "i"
forms["acc_sg_n"] = "i"
end
elseif arg1 == "quis" or arg1 == "quī" then
local note1 = preprocess("{{m|la|qua|Qua|ng=with short {{m|la||ă}}}} occurs only as an indefinite pronoun or determiner, placed immediately after {{m|la|sī}}, {{m|la|nē}}{{,}} or {{m|la|num}}. The combinations {{m|la|sīqua}}, {{m|la|nēqua}}, and {{m|la|numqua}} are sometimes written without spacing (as also are the masculines {{m|la|sīquis}}, {{m|la|nēquis}}{{,}} and {{m|la|numquis}}). Compare {{m|la|aliquis}}, {{m|la|aliqua}}, {{m|la|aliquid}}. {{m|la|quae|Quae}} can also be used instead of {{m|la||quă}}, and {{m|la||quă}} is never used as an interrogative pronoun/determiner, relative pronoun/determiner{{,}} or feminine nominative plural.")
local note2 = "Republican Latin."
local note3 = preprocess("{{m|la|quī|Quī}} is occasionally used as an ablative singular, whence {{m|la|quīcum|t=with whom}}; it was originally preferred in instrumental meanings.")
if arg1 == "quī" then
if pos == "pronouns" then
data.title = glossary_link("relative") .. " pronoun"
forms["nom_sg_m"] = {"quī", "quei"}
notes["nom_sg_m2"] = note2
forms["nom_sg_f"] = {"quae", "quai"}
notes["nom_sg_f2"] = note2
forms["nom_pl_n"] = "quae"
forms["acc_pl_n"] = "quae"
else
data.title = glossary_link("relative") .. "/" .. glossary_link("interrogative") .. " determiner"
forms["nom_sg_m"] = {"quī", "quei", "quis"}
notes["nom_sg_m2"] = note2
notes["nom_sg_m3"] = note2
forms["nom_sg_f"] = {"quae", "quai", "qua"}
notes["nom_sg_f2"] = note2
notes["nom_sg_f3"] = note1
forms["nom_pl_n"] = {"quae", "qua"}
notes["nom_pl_n2"] = note1
forms["acc_pl_n"] = {"quae", "qua"}
notes["acc_pl_n2"] = note1
end
forms["nom_sg_n"] = "quod"
forms["nom_pl_m"] = {"quī", "quei"}
notes["nom_pl_m2"] = note2
forms["nom_pl_f"] = "quae"
forms["gen_pl_m"] = "quōrum"
forms["gen_pl_f"] = "quārum"
forms["gen_pl_n"] = "quōrum"
forms["acc_sg_f"] = "quam"
forms["acc_sg_n"] = "quod"
forms["acc_pl_m"] = "quōs"
forms["acc_pl_f"] = "quās"
else
data.title = glossary_link("interrogative") .. "/" .. glossary_link("indefinite") .. " pronoun"
forms["nom_sg_m"] = {"quis", "quī", "quei"}
notes["nom_sg_m3"] = note2
forms["nom_sg_f"] = {"quae", "quis", "qua"}
notes["nom_sg_f2"] = note2
notes["nom_sg_f3"] = note1
forms["nom_sg_n"] = "quid"
forms["nom_pl_m"] = {"quī", "quei", "quēs"}
notes["nom_pl_m2"] = note2
notes["nom_pl_m3"] = note2
forms["nom_pl_f"] = {"quae", "quēs"}
notes["nom_pl_f2"] = note2
forms["nom_pl_n"] = {"quae", "qua"}
notes["nom_pl_n2"] = note1
forms["gen_pl_m"] = {"quōrum", "quium"}
forms["gen_pl_f"] = {"quārum", "quium"}
forms["gen_pl_n"] = {"quōrum", "quium"}
notes["gen_pl_m2"] = note2
notes["gen_pl_f2"] = note2
notes["gen_pl_n2"] = note2
forms["acc_sg_f"] = {"quam", "quem"}
notes["acc_sg_f2"] = note2
forms["acc_sg_n"] = "quid"
forms["acc_pl_m"] = {"quōs", "quēs"}
notes["acc_pl_m2"] = note2
forms["acc_pl_f"] = {"quās", "quēs"}
notes["acc_pl_f2"] = note2
forms["acc_pl_n"] = {"quae", "qua"}
notes["acc_pl_n2"] = note1
end
forms["gen_sg_m"] = {"cuius", "quoius"}
forms["gen_sg_f"] = {"cuius", "quoius"}
forms["gen_sg_n"] = {"cuius", "quoius"}
notes["gen_sg_m2"] = note2
notes["gen_sg_f2"] = note2
notes["gen_sg_n2"] = note2
forms["dat_sg_m"] = {"cui", "quoi", "[[quoī]] / [[quoei]]", "[[quoiī]] / [[quoiei]]"}
forms["dat_sg_f"] = {"cui", "quoi", "[[quoī]] / [[quoei]]", "[[quoiī]] / [[quoiei]]"}
forms["dat_sg_n"] = {"cui", "quoi", "[[quoī]] / [[quoei]]", "[[quoiī]] / [[quoiei]]"}
notes["dat_sg_m2"] = note2
notes["dat_sg_m3"] = note2
notes["dat_sg_m4"] = note2
notes["dat_sg_f2"] = note2
notes["dat_sg_f3"] = note2
notes["dat_sg_f4"] = note2
notes["dat_sg_n2"] = note2
notes["dat_sg_n3"] = note2
notes["dat_sg_n4"] = note2
forms["dat_pl_m"] = {"quibus", "quīs", "queis"}
forms["dat_pl_f"] = {"quibus", "quīs", "queis"}
forms["dat_pl_n"] = {"quibus", "quīs", "queis"}
notes["dat_pl_m3"] = note2
notes["dat_pl_f3"] = note2
notes["dat_pl_n3"] = note2
forms["acc_sg_m"] = "quem"
forms["abl_sg_m"] = {"quō", "quī"}
forms["abl_sg_f"] = {"quā", "quī"}
forms["abl_sg_n"] = {"quō", "quī"}
notes["abl_sg_m2"] = note3
notes["abl_sg_f2"] = note3
notes["abl_sg_n2"] = note3
forms["abl_pl_m"] = {"quibus", "quīs", "queis"}
forms["abl_pl_f"] = {"quibus", "quīs", "queis"}
forms["abl_pl_n"] = {"quibus", "quīs", "queis"}
notes["abl_pl_m3"] = note2
notes["abl_pl_f3"] = note2
notes["abl_pl_n3"] = note2
elseif arg1 == "aliquī" then
data.title = glossary_link("indefinite") .. " " .. glossary_link("determiner")
local note1 = "Normatively, [[aliqui#Latin|aliquī]] is a determiner (used adjectivally) and [[aliquis#Latin|aliquis]] is a pronoun (used substantively), but the opposite usages can be found, even among the best Classical writers."
local note2 = "The feminine nominative singular form is usually ''aliqua'', but there are a handful of possible examples of ''aliquae'' as a feminine nominative singular form; see [[Citations:aliquae]]. The feminine nominative plural can only be ''aliquae'', and there are perhaps no solid examples of the neuter nominative/accusative plural taking any form other than ''aliqua''."
local note3 = "Alternative spelling [[aliquoius]] (used in Republican Latin or earlier)."
local note4 = "Alternative spelling [[aliqueis]] (used in Republican Latin or earlier)."
local note5 = "Alternative spelling [[aliquoi]] (used in Republican Latin or earlier)."
forms["nom_sg_m"] = {"aliquī", "aliquis"}
notes["nom_sg_m2"] = note1
forms["nom_sg_f"] = "aliqua"
notes["nom_sg_f1"] = note2
forms["nom_sg_n"] = "aliquod"
forms["nom_pl_m"] = "aliquī"
forms["nom_pl_f"] = "aliquae"
notes["nom_pl_f1"] = note2
forms["nom_pl_n"] = "aliqua"
notes["nom_pl_n1"] = note2
forms["gen_sg_m"] = "alicuius"
notes["gen_sg_m1"] = note3
forms["gen_sg_f"] = "alicuius"
notes["gen_sg_f1"] = note3
forms["gen_sg_n"] = "alicuius"
notes["gen_sg_n1"] = note3
forms["gen_pl_m"] = "aliquōrum"
forms["gen_pl_f"] = "aliquārum"
forms["gen_pl_n"] = "aliquōrum"
forms["dat_sg_m"] = "alicui"
notes["dat_sg_m1"] = note5
forms["dat_sg_f"] = "alicui"
notes["dat_sg_f1"] = note5
forms["dat_sg_n"] = "alicui"
notes["dat_sg_n1"] = note5
forms["dat_pl_m"] = {"aliquīs", "aliquibus"}
notes["dat_pl_m1"] = note4
forms["dat_pl_f"] = {"aliquīs", "aliquibus"}
notes["dat_pl_f1"] = note4
forms["dat_pl_n"] = {"aliquīs", "aliquibus"}
notes["dat_pl_n1"] = note4
forms["acc_sg_m"] = "aliquem"
forms["acc_sg_f"] = "aliquam"
forms["acc_sg_n"] = "aliquod"
forms["acc_pl_m"] = "aliquōs"
forms["acc_pl_f"] = "aliquās"
forms["acc_pl_n"] = "aliqua"
notes["acc_pl_n1"] = note2
forms["abl_sg_m"] = "aliquō"
forms["abl_sg_f"] = "aliquā"
forms["abl_sg_n"] = "aliquō"
forms["abl_pl_m"] = {"aliquīs", "aliquibus"}
notes["abl_pl_m1"] = note4
forms["abl_pl_f"] = {"aliquīs", "aliquibus"}
notes["abl_pl_f1"] = note4
forms["abl_pl_n"] = {"aliquīs", "aliquibus"}
notes["abl_pl_n1"] = note4
elseif arg1 == "aliquis" then
data.title = glossary_link("indefinite") .. " " .. glossary_link("pronoun")
local note1 = preprocess("{{m|la|aliquī|g=m|qq=nom. sg.}} is relatively rare (but classically attested) as a pronoun, although frequent as a determiner.")
local note2 = preprocess("{{m|la|aliqua|g=f|qq=nom. sg.}} is very rare as a pronoun, although frequent as a determiner.")
local note3 = preprocess("{{m|la|alicuius|qq=gen. sg.}} and {{m|la|alicui|qq=dat. sg.}} have alternative spellings {{m|la|aliquoius}}, {{m|la|aliquoi}} (used in Republican Latin or earlier).")
local note4 = "Alternative spelling [[aliqueis]] (used in Republican Latin or earlier)."
local note4 = preprocess("{{m|la|aliquīs|qq=abl. pl.}} has the alternative spelling {{m|la|aliqueis}} (used in Republican Latin or earlier).")
local note5 = preprocess("{{m|la|aliquī|qq=abl. sg.}} is a rare Old Latin form, attested in Plautus in place of {{m|la|aliquō}} as a masculine and neuter pronoun.")
local note6 = preprocess("{{m|la|aliquī|qq=nom. pl.}} had an alternative Old Latin form {{m|la|aliquēs}} according to the Late Latin grammarian Charisius.")
forms["nom_sg_m"] = {"aliquis", "aliquī"}
notes["nom_sg_m2"] = note1
forms["nom_sg_f"] = "aliqua"
notes["nom_sg_f1"] = note2
forms["nom_sg_n"] = "aliquid"
forms["nom_pl_m"] = "aliquī"
notes["nom_pl_m1"] = note6
forms["nom_pl_f"] = "aliquae"
forms["nom_pl_n"] = "aliqua"
forms["gen_sg_m"] = "alicuius"
notes["gen_sg_m1"] = note3
forms["gen_sg_f"] = "alicuius"
notes["gen_sg_f1"] = note3
forms["gen_sg_n"] = "alicuius"
notes["gen_sg_n1"] = note3
forms["gen_pl_m"] = "aliquōrum"
forms["gen_pl_f"] = "aliquārum"
forms["gen_pl_n"] = "aliquōrum"
forms["dat_sg_m"] = "alicui"
notes["dat_sg_m1"] = note3
forms["dat_sg_f"] = "alicui"
notes["dat_sg_f1"] = note3
forms["dat_sg_n"] = "alicui"
notes["dat_sg_n1"] = note3
forms["dat_pl_m"] = {"aliquīs", "aliquibus"}
notes["dat_pl_m1"] = note4
forms["dat_pl_f"] = {"aliquīs", "aliquibus"}
notes["dat_pl_f1"] = note4
forms["dat_pl_n"] = {"aliquīs", "aliquibus"}
notes["dat_pl_n1"] = note4
forms["acc_sg_m"] = "aliquem"
forms["acc_sg_f"] = "aliquam"
forms["acc_sg_n"] = "aliquid"
forms["acc_pl_m"] = "aliquōs"
forms["acc_pl_f"] = "aliquās"
forms["acc_pl_n"] = "aliqua"
forms["abl_sg_m"] = {"aliquō", "aliquī"}
notes["abl_sg_m2"] = note5
forms["abl_sg_f"] = {"aliquā", "aliquī"}
notes["abl_sg_f2"] = note5
forms["abl_sg_n"] = {"aliquō", "aliquī"}
notes["abl_sg_n2"] = note5
forms["abl_pl_m"] = {"aliquīs", "aliquibus"}
notes["abl_pl_m1"] = note4
forms["abl_pl_f"] = {"aliquīs", "aliquibus"}
notes["abl_pl_f1"] = note4
forms["abl_pl_n"] = {"aliquīs", "aliquibus"}
notes["abl_pl_n1"] = note4
elseif arg1 == "quisquam" then
if pos == "pronouns" then
local note1 = "Republican Latin."
local note2 = "Used in the feminine only in Old Latin."
data.title = glossary_link("negative polarity item", "negative polarity") .. " " .. glossary_link("indefinite") .. " " .. glossary_link("pronoun")
forms["nom_sg_m"] = "quisquam"
notes["nom_sg_m1"] = note2
forms["nom_sg_n"] = {"quicquam", "quidquam"}
forms["gen_sg_m"] = {"cuiusquam", "quoiusquam"}
forms["gen_sg_f"] = {"cuiusquam", "quoiusquam"}
forms["gen_sg_n"] = {"cuiusquam", "quoiusquam"}
notes["gen_sg_m2"] = note1
notes["gen_sg_f2"] = note1
notes["gen_sg_n2"] = note1
forms["dat_sg_m"] = {"cuiquam", "quoiquam"}
forms["dat_sg_f"] = {"cuiquam", "quoiquam"}
forms["dat_sg_n"] = {"cuiquam", "quoiquam"}
notes["dat_sg_m2"] = note1
notes["dat_sg_f2"] = note1
notes["dat_sg_n2"] = note1
forms["acc_sg_m"] = "quemquam"
notes["acc_sg_m1"] = note2
forms["acc_sg_n"] = {"quicquam", "quidquam"}
forms["abl_sg_m"] = {"quōquam", "quīquam"}
forms["abl_sg_n"] = {"quōquam", "quīquam"}
elseif pos == "determiners" then
local note1 = "Only attested in postclassical Latin. In Classical Latin, forms of [[ullus#Latin|ūllus]] were used instead."
local note2 = "Only attested as a feminine form in the preclassical Latin of authors like Plautus."
local note3 = "Attested only once in Classical Latin. Usually [[ullus#Latin|ūllam]] was used instead."
local note4 = "Attested, but rare in Classical Latin. Usually [[ullus#Latin|ūllō]] was used instead."
data.title = glossary_link("negative polarity item", "negative polarity") .. " " .. glossary_link("indefinite") .. " " .. glossary_link("determiner")
forms["nom_sg_m"] = "quisquam"
forms["nom_sg_f"] = {"quaequam", "quisquam"}
notes["nom_sg_f1"] = note1
notes["nom_sg_f2"] = note2
forms["nom_sg_n"] = "quodquam"
notes["nom_sg_n1"] = note1
forms["nom_pl_m"] = "quīquam"
notes["nom_pl_m1"] = note1
forms["nom_pl_f"] = "quaequam"
notes["nom_pl_f1"] = note1
forms["nom_pl_n"] = "quaequam"
notes["nom_pl_n1"] = note1
forms["gen_sg_m"] = "cuiusquam"
forms["gen_sg_f"] = "cuiusquam"
forms["gen_sg_n"] = "cuiusquam"
forms["gen_pl_m"] = "quōrumquam"
notes["gen_pl_m1"] = note1
forms["gen_pl_f"] = "quārumquam"
notes["gen_pl_f1"] = note1
forms["gen_pl_n"] = "quōrumquam"
notes["gen_pl_n1"] = note1
forms["dat_sg_m"] = "cuiquam"
forms["dat_sg_f"] = "cuiquam"
forms["dat_sg_n"] = "cuiquam"
forms["dat_pl_m"] = "quibusquam"
notes["dat_pl_m1"] = note1
forms["dat_pl_f"] = "quibusquam"
notes["dat_pl_f1"] = note1
forms["dat_pl_n"] = "quibusquam"
notes["dat_pl_n1"] = note1
forms["acc_sg_m"] = "quemquam"
forms["acc_sg_f"] = {"quamquam", "quemquam"}
notes["acc_sg_f1"] = note3
notes["acc_sg_f2"] = note2
forms["acc_sg_n"] = "quodquam"
notes["acc_sg_n1"] = note1
forms["acc_pl_m"] = "quōsquam"
notes["acc_pl_m1"] = note1
forms["acc_pl_f"] = "quāsquam"
notes["acc_pl_f1"] = note1
forms["acc_pl_n"] = "quaequam"
notes["acc_pl_n1"] = note1
forms["abl_sg_m"] = {"quōquam", "quīquam"}
notes["abl_sg_m1"] = note4
notes["abl_sg_m2"] = note2
forms["abl_sg_f"] = "quāquam"
notes["abl_sg_f1"] = note1
forms["abl_sg_n"] = "quōquam"
notes["abl_sg_n1"] = note4
forms["abl_pl_m"] = "quibusquam"
notes["abl_pl_m1"] = note1
forms["abl_pl_f"] = "quibusquam"
notes["abl_pl_f1"] = note1
forms["abl_pl_n"] = "quibusquam"
notes["abl_pl_n1"] = note1
forms["voc_sg_m"] = "quisquam"
notes["voc_sg_m1"] = note1
forms["voc_sg_f"] = "quaequam"
notes["voc_sg_f1"] = note1
forms["voc_sg_n"] = "quodquam"
notes["voc_sg_n1"] = note1
forms["voc_pl_m"] = "quīquam"
notes["voc_pl_m1"] = note1
forms["voc_pl_f"] = "quaequam"
notes["voc_pl_f1"] = note1
forms["voc_pl_n"] = "quaequam"
notes["voc_pl_n1"] = note1
end
elseif arg1 == "quisquis" then
data.title = glossary_link("relative") .. "/" .. glossary_link("interrogative") .. " pronoun"
forms["nom_sg_m"] = "quisquis"
forms["nom_sg_f"] = "quisquis"
forms["nom_sg_n"] = {"quidquid", "quicquid"}
forms["nom_pl_m"] = "quīquī"
forms["nom_pl_f"] = "quaequae"
forms["nom_pl_n"] = "quaequae"
forms["gen_sg_m"] = "cuiuscuius"
forms["gen_sg_f"] = "cuiuscuius"
forms["gen_sg_n"] = "cuiuscuius"
forms["gen_pl_m"] = "quōrumquōrum"
forms["gen_pl_f"] = "quārumquārum"
forms["gen_pl_n"] = "quōrumquōrum"
forms["dat_sg_m"] = "cuicui"
forms["dat_sg_f"] = "cuicui"
forms["dat_sg_n"] = "cuicui"
forms["dat_pl_m"] = {"quibusquibus", "quīsquīs"}
forms["dat_pl_f"] = {"quibusquibus", "quīsquīs"}
forms["dat_pl_n"] = {"quibusquibus", "quīsquīs"}
forms["acc_sg_m"] = "quemquem"
forms["acc_sg_f"] = "quamquam"
forms["acc_sg_n"] = {"quidquid", "quicquid"}
forms["acc_pl_m"] = "quōsquōs"
forms["acc_pl_f"] = "quāsquās"
forms["acc_pl_n"] = "quaequae"
forms["abl_sg_m"] = "quōquō"
forms["abl_sg_f"] = "quāquā"
forms["abl_sg_n"] = "quōquō"
forms["abl_pl_m"] = {"quibusquibus", "quīsquīs"}
forms["abl_pl_f"] = {"quibusquibus", "quīsquīs"}
forms["abl_pl_n"] = {"quibusquibus", "quīsquīs"}
forms["voc_sg_m"] = "quisquis"
forms["voc_sg_f"] = "quisquis"
forms["voc_sg_n"] = {"quidquid", "quicquid"}
forms["voc_pl_m"] = "quīquī"
forms["voc_pl_f"] = "quaequae"
forms["voc_pl_n"] = "quaequae"
elseif arg1 == "ecquis" then
local note1 = "Unattested in classical Latin."
local note2 = "Attested only twice in Classical Latin."
data.title = glossary_link("interrogative") .. " pronoun"
forms["nom_sg_m"] = {"ecquis", "ecquī"}
forms["nom_sg_f"] = {"ecqua", "ecquae"}
forms["nom_sg_n"] = "ecquid"
forms["nom_pl_m"] = "ecquī"
forms["nom_pl_f"] = "ecquae"
forms["nom_pl_n"] = {"ecqua", "ecquae"}
forms["gen_sg_m"] = "eccuius"
forms["gen_sg_f"] = "eccuius"
forms["gen_sg_n"] = "eccuius"
notes["gen_sg_m1"] = note1
notes["gen_sg_f1"] = note1
notes["gen_sg_n1"] = note1
forms["dat_sg_m"] = "eccui"
forms["dat_sg_f"] = "eccui"
forms["dat_sg_n"] = "eccui"
notes["dat_sg_m1"] = note2
notes["dat_sg_f1"] = note2
notes["dat_sg_n1"] = note2
forms["acc_sg_m"] = "ecquem"
forms["acc_sg_f"] = "ecquam"
forms["acc_sg_n"] = "ecquod"
forms["acc_pl_m"] = "ecquōs"
forms["acc_pl_f"] = "ecquās"
forms["acc_pl_n"] = {"ecqua", "ecquae"}
forms["abl_sg_m"] = {"ecquō", "ecquī"}
forms["abl_sg_f"] = {"ecquā", "ecquī"}
forms["abl_sg_n"] = {"ecquō", "ecquī"}
elseif arg1 == "quīdam" then
local note1 = "The genitive singular was spelled [[quoiusdam#Latin|''quoiusdam'']] before the Augustan period."
local note2 = "The dative singular was spelled [[quoidam#Latin|''quoidam'']] before the Augustan period."
local note3 = "An alternative masculine nominative/accusative plural form [[quesdam#Latin|''quēsdam'']] occurs in Accius."
local note4 = "The dative/ablative plural has a rare alternative form [[quisdam#Latin|''quīsdam'']]/[[queisdam#Latin|''queisdam'']]."
data.title = glossary_link("indefinite") .. " pronoun"
forms["nom_sg_m"] = "quīdam"
forms["nom_sg_f"] = "quaedam"
forms["nom_sg_n"] = "quiddam"
forms["nom_pl_m"] = "quīdam"
notes["nom_pl_m1"] = note3
forms["nom_pl_f"] = "quaedam"
forms["nom_pl_n"] = "quaedam"
forms["gen_sg_m"] = "cuiusdam"
forms["gen_sg_f"] = "cuiusdam"
forms["gen_sg_n"] = "cuiusdam"
notes["gen_sg_m1"] = note1
notes["gen_sg_f1"] = note1
notes["gen_sg_n1"] = note1
forms["gen_pl_m"] = {"quōrundam", "quōrumdam"}
forms["gen_pl_f"] = {"quārundam", "quārumdam"}
forms["gen_pl_n"] = {"quōrundam", "quōrumdam"}
forms["dat_sg_m"] = "cuidam"
forms["dat_sg_f"] = "cuidam"
forms["dat_sg_n"] = "cuidam"
notes["dat_sg_m1"] = note2
notes["dat_sg_f1"] = note2
notes["dat_sg_n1"] = note2
forms["dat_pl_m"] = "quibusdam"
forms["dat_pl_f"] = "quibusdam"
forms["dat_pl_n"] = "quibusdam"
notes["dat_pl_m1"] = note4
notes["dat_pl_f1"] = note4
notes["dat_pl_n1"] = note4
forms["acc_sg_m"] = {"quendam", "quemdam"}
forms["acc_sg_f"] = {"quandam", "quamdam"}
forms["acc_sg_n"] = "quiddam"
forms["acc_pl_m"] = "quōsdam"
notes["acc_pl_m1"] = note3
forms["acc_pl_f"] = "quāsdam"
forms["acc_pl_n"] = "quaedam"
forms["abl_sg_m"] = "quōdam"
forms["abl_sg_f"] = "quādam"
forms["abl_sg_n"] = "quōdam"
forms["abl_pl_m"] = "quibusdam"
forms["abl_pl_f"] = "quibusdam"
forms["abl_pl_n"] = "quibusdam"
notes["abl_pl_m1"] = note4
notes["abl_pl_f1"] = note4
notes["abl_pl_n1"] = note4
elseif arg1 == "nēmō" then
local note1 = "The genitive [[neminis|''nēminis'']] is not used in Classical Latin, and is generally also avoided by later authors."
local note2 = "The ablative [[nemine|''nēmine'']] is not used in Classical Latin, but can be seen in authors from the Imperial period onwards."
data.title = "Negative pronoun and " .. glossary_link("determiner")
forms["nom_sg_m"] = "nēmō"
forms["nom_sg_f"] = "nēmō"
forms["gen_sg_m"] = {"nūllī̆us", "nēminis"}
forms["gen_sg_f"] = {"nūllī̆us", "nēminis"}
notes["gen_sg_m2"] = note1
notes["gen_sg_f2"] = note1
forms["dat_sg_m"] = "nēminī"
forms["dat_sg_f"] = "nēminī"
forms["acc_sg_m"] = "nēminem"
forms["acc_sg_f"] = "nēminem"
forms["abl_sg_m"] = {"nūllō", "nēmine"}
forms["abl_sg_f"] = {"nūllā", "nēmine"}
notes["abl_sg_m2"] = note2
notes["abl_sg_f2"] = note2
else
error('adjective ' .. arg1 .. ' not recognized')
end
end
return decl
-- For Vim, so we get 4-space tabs
-- vim: set ts=4 sw=4 noet:
qqkd2u6wskn6upy3stzht0ozdjkv768
Padron:la-adj
10
38955
178388
2026-10-23T08:10:09Z
GinawaSaHapon
3989
Nilikha ang pahina na may '{{#invoke:la-headword|show|adjectives}}<noinclude>{{documentation}}</noinclude>'
178388
wikitext
text/x-wiki
{{#invoke:la-headword|show|adjectives}}<noinclude>{{documentation}}</noinclude>
d8e3m90eq1mbi9l47xe5jl87m3ajba6