Wiktionary siwiktionary https://si.wiktionary.org/wiki/%E0%B7%80%E0%B7%92%E0%B6%9A%E0%B7%8A%E0%B7%82%E0%B6%B1%E0%B6%BB%E0%B7%92:%E0%B6%B8%E0%B7%94%E0%B6%BD%E0%B7%8A_%E0%B6%B4%E0%B7%92%E0%B6%A7%E0%B7%94%E0%B7%80 MediaWiki 1.47.0-wmf.19 case-sensitive මාධ්‍යය විශේෂ සාකච්ඡාව පරිශීලක පරිශීලක සාකච්ඡාව වික්ෂනරි වික්ෂනරි සාකච්ඡාව ගොනුව ගොනුව සාකච්ඡාව මාධ්‍යවිකි මාධ්‍යවිකි සාකච්ඡාව සැකිල්ල සැකිලි සාකච්ඡාව උදවු උදවු සාකච්ඡාව ප්‍රවර්ගය ප්‍රවර්ග සාකච්ඡාව TimedText TimedText talk Module Module talk Event Event talk Module:category tree/lang/en 828 6601 237279 235126 2026-07-05T23:37:49Z en>Brainulator9 0 undoing sort keys based on what's seen on other categories (although this means most of [[:Category:English terms by phonemic property]] is under "T"...) 237279 Scribunto text/plain local labels = {} labels["translation hubs"] = { description = "{{{langname}}} terms that do not mean more than the sum of their parts but are retained for the benefit of translation, per {{section link|Wiktionary:Criteria for inclusion#Translation hubs}}.", additional = "See also {{tl|translation only}}.", parents = {"entry maintenance"}, } -- Add irregular plural categories. local irregular_plurals = require("Module:form of/lang-data/en/functions").irregular_plurals labels["irregular plurals"] = { description = "{{{langname}}} irregular noun plurals.", additional = "The criteria for inclusion and singular forms can be found in [[:Category:English nouns with irregular plurals]].", parents = {{name = "noun forms", sort = "*"}}, } labels["miscellaneous irregular plurals"] = { description = "{{{langname}}} irregular noun plurals that do not fall into one of the most common irregular plural categories (e.g. [[:Category:English plurals in -ae with singular in -a|Category:English plurals in ''-ae'' with singular in ''-a'']] or [[:Category:English plurals in -men with singular in -man|Category:English plurals in ''-men'' with singular in ''-man'']]).", additional = "This mostly includes nouns whose plurals originate from a language other than Greek, Latin, Italian or French, or native irregular plurals such as {{m|en|dice}} (plural of {{m|en|die}}).", parents = "irregular plurals", } local function replace_angle_brackets(text) return (text:gsub("<<(.-)>>", "{{m|en||%1}}")) end local function replace_angle_brackets_plain(text) return (text:gsub("<<(.-)>>", "%1")) end for _, irreg_plural in ipairs(irregular_plurals) do local cat, description = irreg_plural.cat, irreg_plural.description if not description then description = cat local desc_suffix = irreg_plural.desc_suffix if desc_suffix then description = description .. desc_suffix end description = "English " .. description .. "." end local breadcrumb = irreg_plural.breadcrumb if not breadcrumb then breadcrumb = cat:match("^plurals in (.*)") or cat:match("^plurals with (.*)") or cat end local additional = irreg_plural.additional labels[replace_angle_brackets_plain(cat)] = { description = replace_angle_brackets(description), additional = additional and replace_angle_brackets(additional), displaytitle = replace_angle_brackets("English " .. cat), breadcrumb = replace_angle_brackets(breadcrumb), parents = {{name = "irregular plurals", sort = irreg_plural.sort_key or replace_angle_brackets_plain(breadcrumb):gsub("^%-", "")}}, } end labels["auxiliary verb forms"] = { description = "{{{langname}}} auxiliary verbs that are inflected to display grammatical relations other than the main form.", parents = {"verb forms", "auxiliary verbs"}, } labels["terms with early reduction of Middle English /iu̯r(ə)/"] = { description = "In Modern English, {{IPAchar|/jə(ɹ)/}} ({{IPAchar|/t͡ʃə(ɹ)/|/d͡ʒə(ɹ)/|/ʃə(ɹ)/|/ʒə(ɹ)/}} after historic {{IPAchar|/t/|/d/|/s/|/z/}}) is the usual reflex of unstressed Middle English {{IPAchar|/iu̯r(ə)/}}. However, in the late Middle English vernacular, there was a tendency to reduce this sound to {{IPAchar|/ir/|/ur/}}, which regularly developed to modern {{IPAchar|/ə(ɹ)/}} instead of {{IPAchar|/jə(ɹ)/}}, While forms reflecting this tendency were adopted in the standard language for some words (e.g. {{m|en|fritter}}), in others such forms were eventually relegated to nonstandard speech before becoming extinct (e.g. {{m|en|nater}} for {{m|en|nature}}).", displaytitle = "{{{langname}}} terms with early reduction of Middle English {{IPAchar|/iu̯r(ə)/}}", parents = {"terms by phonemic property"}, } labels["terms with /ɛ/ for Old English /y/"] = { description = "In [[w:Old English dialects|Kentish]] Old English, historic {{IPAchar|/y/}} became {{IPAchar|/e/}}, which regularly developed to modern {{IPAchar|/ɛ/}}. Even in Kent, these forms have been mostly replaced by those showing the usual [[w:Old English dialects|Anglian]] development to modern {{IPAchar|/ɪ/}}, but a few survive, whether in the standard language or dialectally. Note that before {{IPAchar|/ɹ/}} then a consonant, this sound has developed further to {{IPAchar|/ɜː(ɹ)/}}. Additionally, terms which never had {{IPAchar|/y/}} in the variety of Old English they come from should not be included in this category (an example is {{m|en|elder|t=senior}}, which comes from Anglian {{m|ang|eldra}}, not West Saxon {{m|ang|ieldra}}, {{m|ang|yldra}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/ɛ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /ʌ~ʊ/ for Old English /y/"] = { description = "Especially in the southern West Midlands and the Southwest of England, Old English {{IPAchar|/y/}} often became Middle English {{IPAchar|/u/}} in the vicinity of a following {{IPAchar|/r/}}, labial consonant, or postalveolar consonant. Southern influence has resulted in such forms being reasonably common in the modern standard, where this {{IPAchar|/u/}} is regularly reflected as {{IPAchar|/ʌ/}}, {{IPAchar|/ʊ/}}, or before (historic) preconsonantal {{IPAchar|/ɹ/}}, {{IPAchar|/ɜ(ː)/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/ʌ~ʊ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /i/ for expected final /ə/"] = { description = "In [[rhotic]] dialects of English, final {{IPAchar|/ə/}} generally does not appear in native vocabulary; as a result, some rhotic or historically-rhotic dialects tended to use word-final {{IPAchar|/i/}} where {{IPAchar|/ə/}} occurs in the standard language. Due to the influence of the standard language and other dialects, this feature is nearly extinct, though it has been adopted in the stanard language in {{m|en|nary}} (from {{m|en|ne'er}} {{m|en|a}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/i/}} for expected final {{IPAchar|/ə/}}", parents = {"terms by phonemic property"}, } labels["terms with assimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be assimilated before coronal consonants, especially {{IPAchar|/s/}}; this is distinct from later non-[[rhoticity]]. While forms reflecting this tendency have been adopted for some words in the standard language (such as {{m|en|bass|id=fish|t=fish}} ← {{m+|ang|bærs}}), others survive only dialectally or informally (e.g. {{m|en|hoss}}, {{m|en|passel}}).", displaytitle = "{{{langname}}} terms with assimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with dissimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be lost in words when another {{IPAchar|/ɹ/}} occured. While forms reflecting this tendency have been adopted for some words in the standard language, others survive only dialectally or informally (e.g. {{m|en|catridge}}).", displaytitle = "{{{langname}}} terms with dissimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with unetymological /ɹ/"] = { description = "Many English words have acquired an unetymological {{IPAchar|/ɹ/}}, either due to either purely phonetic processes or various kinds of {{glossary|hypercorrection}} (of non-rhoticity, the [[:Category:English terms with assimilation of historic /ɹ/|assimilation of {{IPAchar|/ɹ/}} before coronals]], or [[:Category:English terms with dissimilation of historic /ɹ/|dissimilation of {{IPAchar|/ɹ/}}]]). While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|parsnip}}), others survive only dialectally or informally (e.g. {{m|en|warsh}}).", displaytitle = "{{{langname}}} terms with unetymological {{IPAchar|/ɹ/}}", parents = {"hypercorrections"}, } labels["terms with unexpected final devoicing"] = { description = "In prehistoric Old English, final fricatives were {{w|final-obstruent devoicing|devoiced}}; compare {{m+|ang|līf}} to {{m+|goh|līb|t=life}}. In standard English, this process did not affect {{glossary|plosive|plosives}} (e.g. {{m|en|road}}) or secondary word-final fricatives (e.g. {{m|en|love}}), but some dialects devoiced these consonants, especially when unstressed (this was particularly common in Middle English). No modern variety universally has this devoicing, but some devoiced forms survive dialectally (e.g. {{m|en|anythink}}) or have been adopted in the standard language (most notably in the past tense of some irregular verbs, such as {{m|en|sent}}, aided by analogy with e.g. {{m|en|kept}}).", parents = {"terms by phonemic property"}, } labels["terms with Middle English front rounded vowel spellings"] = { description = "In Southern and southern West Midland Middle English, Old English ''y̆ ȳ'' {{IPAchar|/y/|/yː/}} retained their rounding, while ''ĕo ēo'' {{IPAchar|/eo̯/|/eːo̯/}} developed into the mid front rounded vowels {{IPAchar|/œ/|/øː/}}. While these vowels were eventually unrounded to {{IPAchar|/i/|/iː/}} and {{IPAchar|/ɛ/|/eː/}} respectively in Late Middle English in a recapitulation of the development that other dialects underwent earlier, the associated spellings ''u, ui, uy'' (especially for {{IPAchar|/y/|/yː/}}) and ''eo, eu, oe, ue'' (especially for {{IPAchar|/œ/|/øː/}}) are occasionally retained in Modern English due to these dialects’ influence, especially in placenames.", parents = {"terms by orthographic property"}, } labels["terms with Middle English initial fricative voicing"] = { description = "In Kentish, Southern, and Southwest Midland Middle English, the fricatives {{IPAchar|/f θ s ʃ/}} were voiced to {{IPAchar|/v ð z ʒ/}} at the beginning of a word or morpheme. This change has gradually been reversed due to the influence of the East Midland standard, but this was recent enough to leave traces in dialect literature in many regions, while relic items persist even today, whether dialectally or in the standard language. Terms where historically voiceless initial fricatives have come to be voiced due to other processes, such as borrowings from other Germanic languages with analogous sound changes, should not be included in this category.", parents = {"terms by phonemic property"}, } labels["terms with unraised Middle English /ɛː/"] = { description = "Middle English and Early Modern English {{IPAchar|/ɛː/}} regularly becomes {{IPAchar|/iː/}} ({{IPAchar|/ɪə/}}/{{IPAchar|/ɪ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) in the modern standard, but in some lexical items it has exceptionally developed to {{IPAchar|/eɪ/}} ({{IPAchar|/ɛː/}}/{{IPAchar|/ɛ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) due to dialectal influence. This category also includes dialectal forms where {{IPAchar|[eɪ]}} or something like it (commonly {{IPAchar|[eː]}}) is a more typical development, such as {{m|en|Jaysus}}, {{m|en|tay}}.", displaytitle = "{{{langname}}} terms with unraised Middle English {{IPAchar|/ɛː/}}", parents = {"terms by phonemic property"}, } labels["terms with Middle English prothetic /j w/"] = { description = "In Late Middle English, long vowels tended to develop a prothetic semivowel when word-initial or following {{IPAchar|/h/}}; {{IPAchar|/j/}} when preceding a front vowel, while {{IPAchar|/w/}} when preceding a back vowel. While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|one}}, {{m|en|yew}}), others survive only dialectally or informally (e.g. {{m|en|wold|t=old}}). in some dialects, this process has been extended to post-consonantal position (e.g. {{m|en|tyebble}}); this category does not include such forms.", displaytitle = "{{{langname}}} terms with Middle English prothetic {{IPAchar|/j w/}}", parents = {"terms by phonemic property"}, } labels["terms with open-syllable lengthening of Middle English /i u/"] = { description = "In Northern Middle English, Old English {{IPAchar|/i/|/u/}} often lengthened to {{IPAchar|/eː/|/oː/}} in stressed open syllables of multisyllabic words. Though the majority of forms with this development have been replaced with those displaying the reflex of unlengthened vowels in modern Northern English dialects and Scots, some have either remained dialectally (e.g. {{m|en|aboon}}) or entered the standard language (e.g. {{m|en|week}}) due to the southward dissemination of lengthened forms in later Middle English.", displaytitle = "{{{langname}}} terms with open-syllable lengthening of Middle English {{IPAchar|/i u/}}", parents = {"terms by phonemic property"}, } labels["terms with unexpected syllabic -ed"] = { description = "English words with ⟨-ed⟩ pronounced {{IPAchar|/əd/}} or {{IPAchar|/ɪd/}} after a vowel or after a consonant other than {{IPAchar|/d/}} or {{IPAchar|/t/}}.", parents = {"terms by phonemic property"}, } labels["terms with initial /t͡s/"] = { description = "The [[w:voiceless alveolar affricate|voiceless alveolar affricate]] ({{IPAchar|/t͡s/}}) does not occur at the beginning of native English words, but words containing it have been borrowed into English from a number of other languages, including German, Greek, Hebrew, Japanese, Russian, Tswana, and Yiddish and can usually be identified by the prefix ''ts-'' or ''tz-'' (more rarely ''cz-'' or ''z-''). In less formal speech, the sound may be substituted by {{IPAchar|/s/}}, {{IPAchar|/z/}} or rarely {{IPAchar|/t/}}.", displaytitle = "{{{langname}}} terms with initial {{IPAchar|/t͡s/}}", parents = {"terms by phonemic property"}, } labels["terms with /x/"] = { description = "The [[w:voiceless velar fricative|voiceless velar fricative]] ({{IPAchar|/x/}}) fell out of use in most English dialects, but survived in Scottish English and has subsequently been reborrowed into other dialects. In addition, some words borrowed from other languages such as German and Hebrew also include this sound. Speakers who struggle to produce {{IPAchar|/x/}} usually substitute {{IPAchar|/k/}}, or in cases where the sound occurs at the beginning of a word, {{IPAchar|/h/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/x/}}", parents = {"terms by phonemic property"}, } labels["productive prefixes"] = { description = "{{{langname}}} prefixes that have been used recently to form new words.", parents = {"prefixes"}, } labels["productive suffixes"] = { description = "{{{langname}}} suffixes that have been used recently to form new words.", parents = {"suffixes"}, } labels["unproductive prefixes"] = { description = "{{{langname}}} prefixes that are no longer used to form new words.", parents = {"prefixes"}, } labels["unproductive suffixes"] = { description = "{{{langname}}} suffixes that are no longer used to form new words.", parents = {"suffixes"}, } return {LABELS = labels} cwp0gbmrpci8kkoo97633qpdmdjetsg 237280 237279 2026-09-11T11:29:42Z Lee 19 [[:en:Module:category_tree/lang/en]] වෙතින් එක් සංශෝධනයක් 237279 Scribunto text/plain local labels = {} labels["translation hubs"] = { description = "{{{langname}}} terms that do not mean more than the sum of their parts but are retained for the benefit of translation, per {{section link|Wiktionary:Criteria for inclusion#Translation hubs}}.", additional = "See also {{tl|translation only}}.", parents = {"entry maintenance"}, } -- Add irregular plural categories. local irregular_plurals = require("Module:form of/lang-data/en/functions").irregular_plurals labels["irregular plurals"] = { description = "{{{langname}}} irregular noun plurals.", additional = "The criteria for inclusion and singular forms can be found in [[:Category:English nouns with irregular plurals]].", parents = {{name = "noun forms", sort = "*"}}, } labels["miscellaneous irregular plurals"] = { description = "{{{langname}}} irregular noun plurals that do not fall into one of the most common irregular plural categories (e.g. [[:Category:English plurals in -ae with singular in -a|Category:English plurals in ''-ae'' with singular in ''-a'']] or [[:Category:English plurals in -men with singular in -man|Category:English plurals in ''-men'' with singular in ''-man'']]).", additional = "This mostly includes nouns whose plurals originate from a language other than Greek, Latin, Italian or French, or native irregular plurals such as {{m|en|dice}} (plural of {{m|en|die}}).", parents = "irregular plurals", } local function replace_angle_brackets(text) return (text:gsub("<<(.-)>>", "{{m|en||%1}}")) end local function replace_angle_brackets_plain(text) return (text:gsub("<<(.-)>>", "%1")) end for _, irreg_plural in ipairs(irregular_plurals) do local cat, description = irreg_plural.cat, irreg_plural.description if not description then description = cat local desc_suffix = irreg_plural.desc_suffix if desc_suffix then description = description .. desc_suffix end description = "English " .. description .. "." end local breadcrumb = irreg_plural.breadcrumb if not breadcrumb then breadcrumb = cat:match("^plurals in (.*)") or cat:match("^plurals with (.*)") or cat end local additional = irreg_plural.additional labels[replace_angle_brackets_plain(cat)] = { description = replace_angle_brackets(description), additional = additional and replace_angle_brackets(additional), displaytitle = replace_angle_brackets("English " .. cat), breadcrumb = replace_angle_brackets(breadcrumb), parents = {{name = "irregular plurals", sort = irreg_plural.sort_key or replace_angle_brackets_plain(breadcrumb):gsub("^%-", "")}}, } end labels["auxiliary verb forms"] = { description = "{{{langname}}} auxiliary verbs that are inflected to display grammatical relations other than the main form.", parents = {"verb forms", "auxiliary verbs"}, } labels["terms with early reduction of Middle English /iu̯r(ə)/"] = { description = "In Modern English, {{IPAchar|/jə(ɹ)/}} ({{IPAchar|/t͡ʃə(ɹ)/|/d͡ʒə(ɹ)/|/ʃə(ɹ)/|/ʒə(ɹ)/}} after historic {{IPAchar|/t/|/d/|/s/|/z/}}) is the usual reflex of unstressed Middle English {{IPAchar|/iu̯r(ə)/}}. However, in the late Middle English vernacular, there was a tendency to reduce this sound to {{IPAchar|/ir/|/ur/}}, which regularly developed to modern {{IPAchar|/ə(ɹ)/}} instead of {{IPAchar|/jə(ɹ)/}}, While forms reflecting this tendency were adopted in the standard language for some words (e.g. {{m|en|fritter}}), in others such forms were eventually relegated to nonstandard speech before becoming extinct (e.g. {{m|en|nater}} for {{m|en|nature}}).", displaytitle = "{{{langname}}} terms with early reduction of Middle English {{IPAchar|/iu̯r(ə)/}}", parents = {"terms by phonemic property"}, } labels["terms with /ɛ/ for Old English /y/"] = { description = "In [[w:Old English dialects|Kentish]] Old English, historic {{IPAchar|/y/}} became {{IPAchar|/e/}}, which regularly developed to modern {{IPAchar|/ɛ/}}. Even in Kent, these forms have been mostly replaced by those showing the usual [[w:Old English dialects|Anglian]] development to modern {{IPAchar|/ɪ/}}, but a few survive, whether in the standard language or dialectally. Note that before {{IPAchar|/ɹ/}} then a consonant, this sound has developed further to {{IPAchar|/ɜː(ɹ)/}}. Additionally, terms which never had {{IPAchar|/y/}} in the variety of Old English they come from should not be included in this category (an example is {{m|en|elder|t=senior}}, which comes from Anglian {{m|ang|eldra}}, not West Saxon {{m|ang|ieldra}}, {{m|ang|yldra}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/ɛ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /ʌ~ʊ/ for Old English /y/"] = { description = "Especially in the southern West Midlands and the Southwest of England, Old English {{IPAchar|/y/}} often became Middle English {{IPAchar|/u/}} in the vicinity of a following {{IPAchar|/r/}}, labial consonant, or postalveolar consonant. Southern influence has resulted in such forms being reasonably common in the modern standard, where this {{IPAchar|/u/}} is regularly reflected as {{IPAchar|/ʌ/}}, {{IPAchar|/ʊ/}}, or before (historic) preconsonantal {{IPAchar|/ɹ/}}, {{IPAchar|/ɜ(ː)/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/ʌ~ʊ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /i/ for expected final /ə/"] = { description = "In [[rhotic]] dialects of English, final {{IPAchar|/ə/}} generally does not appear in native vocabulary; as a result, some rhotic or historically-rhotic dialects tended to use word-final {{IPAchar|/i/}} where {{IPAchar|/ə/}} occurs in the standard language. Due to the influence of the standard language and other dialects, this feature is nearly extinct, though it has been adopted in the stanard language in {{m|en|nary}} (from {{m|en|ne'er}} {{m|en|a}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/i/}} for expected final {{IPAchar|/ə/}}", parents = {"terms by phonemic property"}, } labels["terms with assimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be assimilated before coronal consonants, especially {{IPAchar|/s/}}; this is distinct from later non-[[rhoticity]]. While forms reflecting this tendency have been adopted for some words in the standard language (such as {{m|en|bass|id=fish|t=fish}} ← {{m+|ang|bærs}}), others survive only dialectally or informally (e.g. {{m|en|hoss}}, {{m|en|passel}}).", displaytitle = "{{{langname}}} terms with assimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with dissimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be lost in words when another {{IPAchar|/ɹ/}} occured. While forms reflecting this tendency have been adopted for some words in the standard language, others survive only dialectally or informally (e.g. {{m|en|catridge}}).", displaytitle = "{{{langname}}} terms with dissimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with unetymological /ɹ/"] = { description = "Many English words have acquired an unetymological {{IPAchar|/ɹ/}}, either due to either purely phonetic processes or various kinds of {{glossary|hypercorrection}} (of non-rhoticity, the [[:Category:English terms with assimilation of historic /ɹ/|assimilation of {{IPAchar|/ɹ/}} before coronals]], or [[:Category:English terms with dissimilation of historic /ɹ/|dissimilation of {{IPAchar|/ɹ/}}]]). While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|parsnip}}), others survive only dialectally or informally (e.g. {{m|en|warsh}}).", displaytitle = "{{{langname}}} terms with unetymological {{IPAchar|/ɹ/}}", parents = {"hypercorrections"}, } labels["terms with unexpected final devoicing"] = { description = "In prehistoric Old English, final fricatives were {{w|final-obstruent devoicing|devoiced}}; compare {{m+|ang|līf}} to {{m+|goh|līb|t=life}}. In standard English, this process did not affect {{glossary|plosive|plosives}} (e.g. {{m|en|road}}) or secondary word-final fricatives (e.g. {{m|en|love}}), but some dialects devoiced these consonants, especially when unstressed (this was particularly common in Middle English). No modern variety universally has this devoicing, but some devoiced forms survive dialectally (e.g. {{m|en|anythink}}) or have been adopted in the standard language (most notably in the past tense of some irregular verbs, such as {{m|en|sent}}, aided by analogy with e.g. {{m|en|kept}}).", parents = {"terms by phonemic property"}, } labels["terms with Middle English front rounded vowel spellings"] = { description = "In Southern and southern West Midland Middle English, Old English ''y̆ ȳ'' {{IPAchar|/y/|/yː/}} retained their rounding, while ''ĕo ēo'' {{IPAchar|/eo̯/|/eːo̯/}} developed into the mid front rounded vowels {{IPAchar|/œ/|/øː/}}. While these vowels were eventually unrounded to {{IPAchar|/i/|/iː/}} and {{IPAchar|/ɛ/|/eː/}} respectively in Late Middle English in a recapitulation of the development that other dialects underwent earlier, the associated spellings ''u, ui, uy'' (especially for {{IPAchar|/y/|/yː/}}) and ''eo, eu, oe, ue'' (especially for {{IPAchar|/œ/|/øː/}}) are occasionally retained in Modern English due to these dialects’ influence, especially in placenames.", parents = {"terms by orthographic property"}, } labels["terms with Middle English initial fricative voicing"] = { description = "In Kentish, Southern, and Southwest Midland Middle English, the fricatives {{IPAchar|/f θ s ʃ/}} were voiced to {{IPAchar|/v ð z ʒ/}} at the beginning of a word or morpheme. This change has gradually been reversed due to the influence of the East Midland standard, but this was recent enough to leave traces in dialect literature in many regions, while relic items persist even today, whether dialectally or in the standard language. Terms where historically voiceless initial fricatives have come to be voiced due to other processes, such as borrowings from other Germanic languages with analogous sound changes, should not be included in this category.", parents = {"terms by phonemic property"}, } labels["terms with unraised Middle English /ɛː/"] = { description = "Middle English and Early Modern English {{IPAchar|/ɛː/}} regularly becomes {{IPAchar|/iː/}} ({{IPAchar|/ɪə/}}/{{IPAchar|/ɪ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) in the modern standard, but in some lexical items it has exceptionally developed to {{IPAchar|/eɪ/}} ({{IPAchar|/ɛː/}}/{{IPAchar|/ɛ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) due to dialectal influence. This category also includes dialectal forms where {{IPAchar|[eɪ]}} or something like it (commonly {{IPAchar|[eː]}}) is a more typical development, such as {{m|en|Jaysus}}, {{m|en|tay}}.", displaytitle = "{{{langname}}} terms with unraised Middle English {{IPAchar|/ɛː/}}", parents = {"terms by phonemic property"}, } labels["terms with Middle English prothetic /j w/"] = { description = "In Late Middle English, long vowels tended to develop a prothetic semivowel when word-initial or following {{IPAchar|/h/}}; {{IPAchar|/j/}} when preceding a front vowel, while {{IPAchar|/w/}} when preceding a back vowel. While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|one}}, {{m|en|yew}}), others survive only dialectally or informally (e.g. {{m|en|wold|t=old}}). in some dialects, this process has been extended to post-consonantal position (e.g. {{m|en|tyebble}}); this category does not include such forms.", displaytitle = "{{{langname}}} terms with Middle English prothetic {{IPAchar|/j w/}}", parents = {"terms by phonemic property"}, } labels["terms with open-syllable lengthening of Middle English /i u/"] = { description = "In Northern Middle English, Old English {{IPAchar|/i/|/u/}} often lengthened to {{IPAchar|/eː/|/oː/}} in stressed open syllables of multisyllabic words. Though the majority of forms with this development have been replaced with those displaying the reflex of unlengthened vowels in modern Northern English dialects and Scots, some have either remained dialectally (e.g. {{m|en|aboon}}) or entered the standard language (e.g. {{m|en|week}}) due to the southward dissemination of lengthened forms in later Middle English.", displaytitle = "{{{langname}}} terms with open-syllable lengthening of Middle English {{IPAchar|/i u/}}", parents = {"terms by phonemic property"}, } labels["terms with unexpected syllabic -ed"] = { description = "English words with ⟨-ed⟩ pronounced {{IPAchar|/əd/}} or {{IPAchar|/ɪd/}} after a vowel or after a consonant other than {{IPAchar|/d/}} or {{IPAchar|/t/}}.", parents = {"terms by phonemic property"}, } labels["terms with initial /t͡s/"] = { description = "The [[w:voiceless alveolar affricate|voiceless alveolar affricate]] ({{IPAchar|/t͡s/}}) does not occur at the beginning of native English words, but words containing it have been borrowed into English from a number of other languages, including German, Greek, Hebrew, Japanese, Russian, Tswana, and Yiddish and can usually be identified by the prefix ''ts-'' or ''tz-'' (more rarely ''cz-'' or ''z-''). In less formal speech, the sound may be substituted by {{IPAchar|/s/}}, {{IPAchar|/z/}} or rarely {{IPAchar|/t/}}.", displaytitle = "{{{langname}}} terms with initial {{IPAchar|/t͡s/}}", parents = {"terms by phonemic property"}, } labels["terms with /x/"] = { description = "The [[w:voiceless velar fricative|voiceless velar fricative]] ({{IPAchar|/x/}}) fell out of use in most English dialects, but survived in Scottish English and has subsequently been reborrowed into other dialects. In addition, some words borrowed from other languages such as German and Hebrew also include this sound. Speakers who struggle to produce {{IPAchar|/x/}} usually substitute {{IPAchar|/k/}}, or in cases where the sound occurs at the beginning of a word, {{IPAchar|/h/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/x/}}", parents = {"terms by phonemic property"}, } labels["productive prefixes"] = { description = "{{{langname}}} prefixes that have been used recently to form new words.", parents = {"prefixes"}, } labels["productive suffixes"] = { description = "{{{langname}}} suffixes that have been used recently to form new words.", parents = {"suffixes"}, } labels["unproductive prefixes"] = { description = "{{{langname}}} prefixes that are no longer used to form new words.", parents = {"prefixes"}, } labels["unproductive suffixes"] = { description = "{{{langname}}} suffixes that are no longer used to form new words.", parents = {"suffixes"}, } return {LABELS = labels} cwp0gbmrpci8kkoo97633qpdmdjetsg 237281 237280 2026-09-11T11:31:00Z Lee 19 පැරණි සංස්කරණයකින් ගත් කොටස්... 237281 Scribunto text/plain local labels = {} labels["translation hubs"] = { description = "{{{langname}}} terms that do not mean more than the sum of their parts but are retained for the benefit of translation, per {{section link|Wiktionary:Criteria for inclusion#Translation hubs}}.", additional = "See also {{tl|translation only}}.", parents = {"ප්‍රවේශ නඩත්තුව"}, } -- Add irregular plural categories. local irregular_plurals = require("Module:form of/lang-data/en/functions").irregular_plurals labels["irregular plurals"] = { description = "{{{langname}}} irregular noun plurals.", additional = "The criteria for inclusion and singular forms can be found in [[:Category:English nouns with irregular plurals]].", parents = {{name = "නාම පද ස්වරූප", sort = "*"}}, } labels["miscellaneous irregular plurals"] = { description = "{{{langname}}} irregular noun plurals that do not fall into one of the most common irregular plural categories (e.g. [[:Category:English plurals in -ae with singular in -a|Category:English plurals in ''-ae'' with singular in ''-a'']] or [[:Category:English plurals in -men with singular in -man|Category:English plurals in ''-men'' with singular in ''-man'']]).", additional = "This mostly includes nouns whose plurals originate from a language other than Greek, Latin, Italian or French, or native irregular plurals such as {{m|en|dice}} (plural of {{m|en|die}}).", parents = "irregular plurals", } local function replace_angle_brackets(text) return (text:gsub("<<(.-)>>", "{{m|en||%1}}")) end local function replace_angle_brackets_plain(text) return (text:gsub("<<(.-)>>", "%1")) end for _, irreg_plural in ipairs(irregular_plurals) do local cat, description = irreg_plural.cat, irreg_plural.description if not description then description = cat local desc_suffix = irreg_plural.desc_suffix if desc_suffix then description = description .. desc_suffix end description = "English " .. description .. "." end local breadcrumb = irreg_plural.breadcrumb if not breadcrumb then breadcrumb = cat:match("^plurals in (.*)") or cat:match("^plurals with (.*)") or cat end local additional = irreg_plural.additional labels[replace_angle_brackets_plain(cat)] = { description = replace_angle_brackets(description), additional = additional and replace_angle_brackets(additional), displaytitle = replace_angle_brackets("English " .. cat), breadcrumb = replace_angle_brackets(breadcrumb), parents = {{name = "irregular plurals", sort = irreg_plural.sort_key or replace_angle_brackets_plain(breadcrumb):gsub("^%-", "")}}, } end labels["auxiliary verb forms"] = { description = "{{{langname}}} auxiliary verbs that are inflected to display grammatical relations other than the main form.", parents = {"verb forms", "auxiliary verbs"}, } labels["terms with early reduction of Middle English /iu̯r(ə)/"] = { description = "In Modern English, {{IPAchar|/jə(ɹ)/}} ({{IPAchar|/t͡ʃə(ɹ)/|/d͡ʒə(ɹ)/|/ʃə(ɹ)/|/ʒə(ɹ)/}} after historic {{IPAchar|/t/|/d/|/s/|/z/}}) is the usual reflex of unstressed Middle English {{IPAchar|/iu̯r(ə)/}}. However, in the late Middle English vernacular, there was a tendency to reduce this sound to {{IPAchar|/ir/|/ur/}}, which regularly developed to modern {{IPAchar|/ə(ɹ)/}} instead of {{IPAchar|/jə(ɹ)/}}, While forms reflecting this tendency were adopted in the standard language for some words (e.g. {{m|en|fritter}}), in others such forms were eventually relegated to nonstandard speech before becoming extinct (e.g. {{m|en|nater}} for {{m|en|nature}}).", displaytitle = "{{{langname}}} terms with early reduction of Middle English {{IPAchar|/iu̯r(ə)/}}", parents = {"terms by phonemic property"}, } labels["terms with /ɛ/ for Old English /y/"] = { description = "In [[w:Old English dialects|Kentish]] Old English, historic {{IPAchar|/y/}} became {{IPAchar|/e/}}, which regularly developed to modern {{IPAchar|/ɛ/}}. Even in Kent, these forms have been mostly replaced by those showing the usual [[w:Old English dialects|Anglian]] development to modern {{IPAchar|/ɪ/}}, but a few survive, whether in the standard language or dialectally. Note that before {{IPAchar|/ɹ/}} then a consonant, this sound has developed further to {{IPAchar|/ɜː(ɹ)/}}. Additionally, terms which never had {{IPAchar|/y/}} in the variety of Old English they come from should not be included in this category (an example is {{m|en|elder|t=senior}}, which comes from Anglian {{m|ang|eldra}}, not West Saxon {{m|ang|ieldra}}, {{m|ang|yldra}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/ɛ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /ʌ~ʊ/ for Old English /y/"] = { description = "Especially in the southern West Midlands and the Southwest of England, Old English {{IPAchar|/y/}} often became Middle English {{IPAchar|/u/}} in the vicinity of a following {{IPAchar|/r/}}, labial consonant, or postalveolar consonant. Southern influence has resulted in such forms being reasonably common in the modern standard, where this {{IPAchar|/u/}} is regularly reflected as {{IPAchar|/ʌ/}}, {{IPAchar|/ʊ/}}, or before (historic) preconsonantal {{IPAchar|/ɹ/}}, {{IPAchar|/ɜ(ː)/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/ʌ~ʊ/}} for Old English {{IPAchar|/y/}}", parents = {"terms by phonemic property"}, } labels["terms with /i/ for expected final /ə/"] = { description = "In [[rhotic]] dialects of English, final {{IPAchar|/ə/}} generally does not appear in native vocabulary; as a result, some rhotic or historically-rhotic dialects tended to use word-final {{IPAchar|/i/}} where {{IPAchar|/ə/}} occurs in the standard language. Due to the influence of the standard language and other dialects, this feature is nearly extinct, though it has been adopted in the stanard language in {{m|en|nary}} (from {{m|en|ne'er}} {{m|en|a}}).", displaytitle = "{{{langname}}} terms with {{IPAchar|/i/}} for expected final {{IPAchar|/ə/}}", parents = {"terms by phonemic property"}, } labels["terms with assimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be assimilated before coronal consonants, especially {{IPAchar|/s/}}; this is distinct from later non-[[rhoticity]]. While forms reflecting this tendency have been adopted for some words in the standard language (such as {{m|en|bass|id=fish|t=fish}} ← {{m+|ang|bærs}}), others survive only dialectally or informally (e.g. {{m|en|hoss}}, {{m|en|passel}}).", displaytitle = "{{{langname}}} terms with assimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with dissimilation of historic /ɹ/"] = { description = "Beginning in the Middle English period, a tendency developed for {{IPAchar|/ɹ/}} to be lost in words when another {{IPAchar|/ɹ/}} occured. While forms reflecting this tendency have been adopted for some words in the standard language, others survive only dialectally or informally (e.g. {{m|en|catridge}}).", displaytitle = "{{{langname}}} terms with dissimilation of historic {{IPAchar|/ɹ/}}", parents = {"terms by phonemic property"}, } labels["terms with unetymological /ɹ/"] = { description = "Many English words have acquired an unetymological {{IPAchar|/ɹ/}}, either due to either purely phonetic processes or various kinds of {{glossary|hypercorrection}} (of non-rhoticity, the [[:Category:English terms with assimilation of historic /ɹ/|assimilation of {{IPAchar|/ɹ/}} before coronals]], or [[:Category:English terms with dissimilation of historic /ɹ/|dissimilation of {{IPAchar|/ɹ/}}]]). While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|parsnip}}), others survive only dialectally or informally (e.g. {{m|en|warsh}}).", displaytitle = "{{{langname}}} terms with unetymological {{IPAchar|/ɹ/}}", parents = {"hypercorrections"}, } labels["terms with unexpected final devoicing"] = { description = "In prehistoric Old English, final fricatives were {{w|final-obstruent devoicing|devoiced}}; compare {{m+|ang|līf}} to {{m+|goh|līb|t=life}}. In standard English, this process did not affect {{glossary|plosive|plosives}} (e.g. {{m|en|road}}) or secondary word-final fricatives (e.g. {{m|en|love}}), but some dialects devoiced these consonants, especially when unstressed (this was particularly common in Middle English). No modern variety universally has this devoicing, but some devoiced forms survive dialectally (e.g. {{m|en|anythink}}) or have been adopted in the standard language (most notably in the past tense of some irregular verbs, such as {{m|en|sent}}, aided by analogy with e.g. {{m|en|kept}}).", parents = {"terms by phonemic property"}, } labels["terms with Middle English front rounded vowel spellings"] = { description = "In Southern and southern West Midland Middle English, Old English ''y̆ ȳ'' {{IPAchar|/y/|/yː/}} retained their rounding, while ''ĕo ēo'' {{IPAchar|/eo̯/|/eːo̯/}} developed into the mid front rounded vowels {{IPAchar|/œ/|/øː/}}. While these vowels were eventually unrounded to {{IPAchar|/i/|/iː/}} and {{IPAchar|/ɛ/|/eː/}} respectively in Late Middle English in a recapitulation of the development that other dialects underwent earlier, the associated spellings ''u, ui, uy'' (especially for {{IPAchar|/y/|/yː/}}) and ''eo, eu, oe, ue'' (especially for {{IPAchar|/œ/|/øː/}}) are occasionally retained in Modern English due to these dialects’ influence, especially in placenames.", parents = {"terms by orthographic property"}, } labels["terms with Middle English initial fricative voicing"] = { description = "In Kentish, Southern, and Southwest Midland Middle English, the fricatives {{IPAchar|/f θ s ʃ/}} were voiced to {{IPAchar|/v ð z ʒ/}} at the beginning of a word or morpheme. This change has gradually been reversed due to the influence of the East Midland standard, but this was recent enough to leave traces in dialect literature in many regions, while relic items persist even today, whether dialectally or in the standard language. Terms where historically voiceless initial fricatives have come to be voiced due to other processes, such as borrowings from other Germanic languages with analogous sound changes, should not be included in this category.", parents = {"terms by phonemic property"}, } labels["terms with unraised Middle English /ɛː/"] = { description = "Middle English and Early Modern English {{IPAchar|/ɛː/}} regularly becomes {{IPAchar|/iː/}} ({{IPAchar|/ɪə/}}/{{IPAchar|/ɪ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) in the modern standard, but in some lexical items it has exceptionally developed to {{IPAchar|/eɪ/}} ({{IPAchar|/ɛː/}}/{{IPAchar|/ɛ(ə)ɹ/}} before earlier preconsonantal {{IPAchar|/ɹ/}}) due to dialectal influence. This category also includes dialectal forms where {{IPAchar|[eɪ]}} or something like it (commonly {{IPAchar|[eː]}}) is a more typical development, such as {{m|en|Jaysus}}, {{m|en|tay}}.", displaytitle = "{{{langname}}} terms with unraised Middle English {{IPAchar|/ɛː/}}", parents = {"terms by phonemic property"}, } labels["terms with Middle English prothetic /j w/"] = { description = "In Late Middle English, long vowels tended to develop a prothetic semivowel when word-initial or following {{IPAchar|/h/}}; {{IPAchar|/j/}} when preceding a front vowel, while {{IPAchar|/w/}} when preceding a back vowel. While forms reflecting this tendency have been adopted in the standard language (e.g. {{m|en|one}}, {{m|en|yew}}), others survive only dialectally or informally (e.g. {{m|en|wold|t=old}}). in some dialects, this process has been extended to post-consonantal position (e.g. {{m|en|tyebble}}); this category does not include such forms.", displaytitle = "{{{langname}}} terms with Middle English prothetic {{IPAchar|/j w/}}", parents = {"terms by phonemic property"}, } labels["terms with open-syllable lengthening of Middle English /i u/"] = { description = "In Northern Middle English, Old English {{IPAchar|/i/|/u/}} often lengthened to {{IPAchar|/eː/|/oː/}} in stressed open syllables of multisyllabic words. Though the majority of forms with this development have been replaced with those displaying the reflex of unlengthened vowels in modern Northern English dialects and Scots, some have either remained dialectally (e.g. {{m|en|aboon}}) or entered the standard language (e.g. {{m|en|week}}) due to the southward dissemination of lengthened forms in later Middle English.", displaytitle = "{{{langname}}} terms with open-syllable lengthening of Middle English {{IPAchar|/i u/}}", parents = {"terms by phonemic property"}, } labels["terms with unexpected syllabic -ed"] = { description = "English words with ⟨-ed⟩ pronounced {{IPAchar|/əd/}} or {{IPAchar|/ɪd/}} after a vowel or after a consonant other than {{IPAchar|/d/}} or {{IPAchar|/t/}}.", parents = {"terms by phonemic property"}, } labels["terms with initial /t͡s/"] = { description = "The [[w:voiceless alveolar affricate|voiceless alveolar affricate]] ({{IPAchar|/t͡s/}}) does not occur at the beginning of native English words, but words containing it have been borrowed into English from a number of other languages, including German, Greek, Hebrew, Japanese, Russian, Tswana, and Yiddish and can usually be identified by the prefix ''ts-'' or ''tz-'' (more rarely ''cz-'' or ''z-''). In less formal speech, the sound may be substituted by {{IPAchar|/s/}}, {{IPAchar|/z/}} or rarely {{IPAchar|/t/}}.", displaytitle = "{{{langname}}} terms with initial {{IPAchar|/t͡s/}}", parents = {"terms by phonemic property"}, } labels["terms with /x/"] = { description = "The [[w:voiceless velar fricative|voiceless velar fricative]] ({{IPAchar|/x/}}) fell out of use in most English dialects, but survived in Scottish English and has subsequently been reborrowed into other dialects. In addition, some words borrowed from other languages such as German and Hebrew also include this sound. Speakers who struggle to produce {{IPAchar|/x/}} usually substitute {{IPAchar|/k/}}, or in cases where the sound occurs at the beginning of a word, {{IPAchar|/h/}}.", displaytitle = "{{{langname}}} terms with {{IPAchar|/x/}}", parents = {"terms by phonemic property"}, } labels["productive prefixes"] = { description = "{{{langname}}} prefixes that have been used recently to form new words.", parents = {"prefixes"}, } labels["productive suffixes"] = { description = "{{{langname}}} suffixes that have been used recently to form new words.", parents = {"suffixes"}, } labels["unproductive prefixes"] = { description = "{{{langname}}} prefixes that are no longer used to form new words.", parents = {"prefixes"}, } labels["unproductive suffixes"] = { description = "{{{langname}}} suffixes that are no longer used to form new words.", parents = {"suffixes"}, } return {LABELS = labels} gcoroex0n2p7b4qec82vpbgmc4mbzta Module:template parser 828 15136 237273 221327 2025-12-16T07:39:55Z en>Benwing2 0 add a flag to allow redirect checking to be bypassed, for use on [[Module:headword/pages]] (on mainspace pages, we check only for #DEFAULTSORT: and #DISPLAYTITLE: builtins, which AFAIK can't be redirected to) 237273 Scribunto text/plain --[[ NOTE: This module works by using recursive backtracking to build a node tree, which can then be traversed as necessary. Because it is called by a number of high-use modules, it has been optimised for speed using a profiler, since it is used to scrape data from large numbers of pages very quickly. To that end, it rolls some of its own methods in cases where this is faster than using a function from one of the standard libraries. Please DO NOT "simplify" the code by removing these, since you are almost guaranteed to slow things down, which could seriously impact performance on pages which call this module hundreds or thousands of times. It has also been designed to emulate the native parser's behaviour as much as possible, which in some cases means replicating bugs or unintuitive behaviours in that code; these should not be "fixed", since it is important that the outputs are the same. Most of these originate from deficient regular expressions, which can't be used here, so the bugs have to be manually reintroduced as special cases (e.g. onlyinclude tags being case-sensitive and whitespace intolerant, unlike all other tags). If any of these are fixed, this module should also be updated accordingly. ]] local export = {} local data_module = "Module:template parser/data" local load_module = "Module:load" local magic_words_data_module = "Module:data/magic words" local pages_module = "Module:pages" local parser_extension_tags_data_module = "Module:data/parser extension tags" local parser_module = "Module:parser" local scribunto_module = "Module:Scribunto" 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_length_module = "Module:table/length" local table_shallow_copy_module = "Module:table/shallowCopy" local table_sorted_pairs_module = "Module:table/sortedPairs" local title_is_title_module = "Module:title/isTitle" local title_make_title_module = "Module:title/makeTitle" local title_new_title_module = "Module:title/newTitle" local title_redirect_target_module = "Module:title/redirectTarget" local require = require local m_parser = require(parser_module) local mw = mw local mw_title = mw.title local mw_uri = mw.uri local string = string local table = table local anchor_encode = mw_uri.anchorEncode local build_template -- defined as export.buildTemplate below local class_else_type = m_parser.class_else_type local concat = table.concat local encode_uri = mw_uri.encode local find = string.find local format = string.format local gsub = string.gsub local html_create = mw.html.create local insert = table.insert local is_node = m_parser.is_node local lower = string.lower local match = string.match local next = next local pairs = pairs local parse -- defined as export.parse below local parse_template_name -- defined below local pcall = pcall local rep = string.rep local select = select local sub = string.sub local title_equals = mw_title.equals local tostring = m_parser.tostring local type = type local umatch = mw.ustring.match --[==[ Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==] local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function encode_entities(...) encode_entities = require(string_utilities_module).encode_entities return encode_entities(...) end local function get_link_target(...) get_link_target = require(pages_module).get_link_target return get_link_target(...) end local function is_title(...) is_title = require(title_is_title_module) return is_title(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_title(...) make_title = require(title_make_title_module) return make_title(...) end local function new_title(...) new_title = require(title_new_title_module) return new_title(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function php_htmlspecialchars(...) php_htmlspecialchars = require(scribunto_module).php_htmlspecialchars return php_htmlspecialchars(...) end local function php_ltrim(...) php_ltrim = require(scribunto_module).php_ltrim return php_ltrim(...) end local function php_trim(...) php_trim = require(scribunto_module).php_trim return php_trim(...) end local function redirect_target(...) redirect_target = require(title_redirect_target_module) return redirect_target(...) 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 shallow_copy(...) shallow_copy = require(table_shallow_copy_module) return shallow_copy(...) end local function sorted_pairs(...) sorted_pairs = require(table_sorted_pairs_module) return sorted_pairs(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function table_len(...) table_len = require(table_length_module) return table_len(...) end local function uupper(...) uupper = require(string_utilities_module).upper return uupper(...) end --[==[ Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] local data local function get_data() data, get_data = load_data(data_module), nil return data end local frame local function get_frame() frame, get_frame = mw.getCurrentFrame(), nil return frame end local magic_words local function get_magic_words() magic_words, get_magic_words = load_data(magic_words_data_module), nil return magic_words end local parser_extension_tags local function get_parser_extension_tags() parser_extension_tags, get_parser_extension_tags = load_data(parser_extension_tags_data_module), nil return parser_extension_tags end ------------------------------------------------------------------------------------ -- -- Nodes -- ------------------------------------------------------------------------------------ local Node = m_parser.node() local new_node = Node.new local function expand(obj, frame_args) return is_node(obj) and obj:expand(frame_args) or obj end export.expand = expand function Node:expand(frame_args) local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return concat(output) end local Wikitext = Node:new_class("wikitext") -- force_node ensures the output will always be a Wikitext node. function Wikitext:new(this, force_node) if type(this) ~= "table" then return force_node and new_node(self, {this}) or this elseif #this == 1 then local this1 = this[1] return force_node and class_else_type(this1) ~= "wikitext" and new_node(self, this) or this1 end local success, str = pcall(concat, this) if success then return force_node and new_node(self, {str}) or str end return new_node(self, this) end -- First value is the parameter name. -- Second value is the parameter's default value. -- Any additional values are ignored: e.g. "{{{a|b|c}}}" is parameter "a" with default value "b" (*not* "b|c"). local Parameter = Node:new_class("parameter") function Parameter:new(this) local this2 = this[2] if class_else_type(this2) == "argument" then insert(this2, 2, "=") this2 = Wikitext:new(this2) end if this[3] == nil then this[2] = this2 else this = {this[1], this2} end return new_node(self, this) end function Parameter:__tostring() local output = {} for i = 1, #self do output[i] = tostring(self[i]) end return "{{{" .. concat(output, "|") .. "}}}" end function Parameter:get_name(frame_args) return scribunto_parameter_key(expand(self[1], frame_args)) end function Parameter:get_default(frame_args) local default = self[2] if default ~= nil then return expand(default, frame_args) end return "{{{" .. expand(self[1], frame_args) .. "}}}" end function Parameter:expand(frame_args) if frame_args == nil then return self:get_default() end local name = expand(self[1], frame_args) local val = frame_args[scribunto_parameter_key(name)] -- Parameter in use. if val ~= nil then return val end val = self[2] -- Default. if val ~= nil then return expand(val, frame_args) end return "{{{" .. name .. "}}}" end local Argument = Node:new_class("argument") function Argument:new(this) local key = this._parse_data.key this = Wikitext:new(this) if key == nil then return this end return new_node(self, {Wikitext:new(key), this}) end function Argument:__tostring() return tostring(self[1]) .. "=" .. tostring(self[2]) end function Argument:expand(frame_args) return expand(self[1], frame_args) .. "=" .. expand(self[2], frame_args) end local Template = Node:new_class("template") function Template:__tostring() local output = {} for i = 1, #self do output[i] = tostring(self[i]) end return "{{" .. concat(output, "|") .. "}}" end -- Normalize the template name, check it's a valid template, then memoize results (using false for invalid titles). -- Parser functions (e.g. {{#IF:a|b|c}}) need to have the first argument extracted from the title, as it comes after the colon. Because of this, the parser function and first argument are memoized as a table. -- FIXME: Some parser functions have special argument handling (e.g. {{#SWITCH:}}). do local templates, parser_variables, parser_functions = {}, {}, {} local function retrieve_magic_word_data(chunk) local mgw_data = (magic_words or get_magic_words())[chunk] if mgw_data then return mgw_data end local normalized = uupper(chunk) mgw_data = magic_words[normalized] if mgw_data and not mgw_data.case_sensitive then return mgw_data end end -- Returns the name required to transclude the title object `title` using -- template {{ }} syntax. If the `shortcut` flag is set, then any calls -- which require a namespace prefix will use the abbreviated form where one -- exists (e.g. "Template:PAGENAME" becomes "T:PAGENAME"). local function get_template_invocation_name(title, shortcut) if not (is_title(title) and not title.isExternal) then error("Template invocations require a valid page title, which cannot contain an interwiki prefix.") end local namespace = title.namespace -- If not in the template namespace, include the prefix (or ":" if -- mainspace). if namespace ~= 10 then return get_link_target(title, shortcut) end -- If in the template namespace and it shares a name with a magic word, -- it needs the prefix "Template:". local text, fragment = title.text, title.fragment if fragment and fragment ~= "" then text = text .. "#" .. fragment end local colon = find(text, ":", nil, true) if not colon then local mgw_data = retrieve_magic_word_data(text) return mgw_data and mgw_data.parser_variable and get_link_target(title, shortcut) or text end local mgw_data = retrieve_magic_word_data(sub(text, 1, colon - 1)) if mgw_data and (mgw_data.parser_function or mgw_data.transclusion_modifier) then return get_link_target(title, shortcut) end -- Also if "Template:" is necessary for disambiguation (e.g. -- "Template:Category:Foo" can't be called with "Category:Foo"). local check = new_title(text, namespace) return check and title_equals(title, check) and text or get_link_target(title, shortcut) end export.getTemplateInvocationName = get_template_invocation_name function parse_template_name(name, has_args, fragment, force_transclusion) local chunks, colon, start, n, p = {}, find(name, ":", nil, true), 1, 0, 0 while colon do local mgw_data = retrieve_magic_word_data(php_ltrim(sub(name, start, colon - 1))) if not mgw_data then break end local priority = mgw_data.priority if not (priority and priority > p) then local pf = mgw_data.parser_function and mgw_data.name or nil if pf then n = n + 1 chunks[n] = pf .. ":" return chunks, "parser function", sub(name, colon + 1) end break end n = n + 1 chunks[n] = mgw_data.name .. ":" start, p = colon + 1, priority colon = find(name, ":", start, true) end if start > 1 then name = sub(name, start) end name = php_trim(name) -- Parser variables can only take SUBST:/SAFESUBST: as modifiers. if not has_args and p <= 1 then local mgw_data = retrieve_magic_word_data(name) local pv = mgw_data and mgw_data.parser_variable and mgw_data.name or nil if pv then n = n + 1 chunks[n] = pv return chunks, "parser variable" end end -- Get the template title with the custom new_title() function in -- [[Module:title/newTitle]], with `allowOnlyFragment` set to false -- (e.g. "{{#foo}}" is invalid) and `allowRelative` set to true, for -- relative links for namespaces with subpages (e.g. "{{/foo}}"). local title = new_title(name, 10, false, true) if not (title and not title.isExternal) then return nil end if force_transclusion ~= "no_redirect" then -- Resolve any redirects. If the redirect target is an interwiki link, -- the template won't fail, but the redirect does not get resolved (i.e. -- the redirect page itself gets transcluded, so the template name -- should not be normalized to the target). local redirect = redirect_target(title, force_transclusion) if redirect and not redirect.isExternal then title = redirect end end -- If `fragment` is not true, unset it from the title object to prevent -- it from being included by get_template_invocation_name. if not fragment then title.fragment = "" end chunks[n + 1] = get_template_invocation_name(title) return chunks, "template" end -- Note: `force_transclusion` avoids incrementing the expensive parser function count by forcing transclusion -- instead. This should only be used when there is a real risk that the expensive parser function limit of -- 500 will be hit. If `force_transclusion` has the value "no_redirect", redirect checking is turned off -- entirely. This should only be used in very limited circumstances when it is otherwise impossible to avoid -- hitting the expensive parser limit and we are willing to handle the possible redirects ourselves. local function process_name(self, frame_args, force_transclusion) local name = expand(self[1], frame_args) local has_args, norm = #self > 1 if not has_args then norm = parser_variables[name] if norm then return norm, "parser variable" end end norm = templates[name] if norm then local pf_arg1 = parser_functions[name] return norm, pf_arg1 and "parser function" or "template", pf_arg1 elseif norm == false then return nil end local chunks, subclass, pf_arg1 = parse_template_name(name, has_args, nil, force_transclusion) -- Fail if invalid. if not chunks then templates[name] = false return nil end local chunk1 = chunks[1] -- Fail on SUBST:. if chunk1 == "SUBST:" then templates[name] = false return nil -- Any modifiers are ignored. elseif subclass == "parser function" then local pf = chunks[#chunks] templates[name] = pf parser_functions[name] = pf_arg1 return pf, "parser function", pf_arg1 end -- Ignore SAFESUBST:, and treat MSGNW: as a parser function with the pagename as its first argument (ignoring any RAW: that comes after). if chunks[chunk1 == "SAFESUBST:" and 2 or 1] == "MSGNW:" then pf_arg1 = chunks[#chunks] local pf = "MSGNW:" templates[name] = pf parser_functions[name] = pf_arg1 return pf, "parser function", pf_arg1 end -- Ignore any remaining modifiers, as they've done their job. local output = chunks[#chunks] if subclass == "parser variable" then parser_variables[name] = output else templates[name] = output end return output, subclass end function Template:get_name(frame_args, force_transclusion) -- Only return the first return value. return (process_name(self, frame_args, force_transclusion)) end function Template:get_arguments(frame_args) local name, subclass, pf_arg1 = process_name(self, frame_args) if name == nil then return nil elseif subclass == "parser variable" then return {} end local template_args = {} if subclass == "parser function" then template_args[1] = pf_arg1 for i = 2, #self do template_args[i] = expand(self[i], frame_args) -- Not trimmed. end return template_args end local implicit = 0 for i = 2, #self do local arg = self[i] if class_else_type(arg) == "argument" then template_args[scribunto_parameter_key(expand(arg[1], frame_args))] = php_trim((expand(arg[2], frame_args))) else implicit = implicit + 1 template_args[implicit] = expand(arg, frame_args) -- Not trimmed. end end return template_args end -- BIG TODO: manual template expansion. function Template:expand(frame_args) local name, subclass, pf_arg1 = process_name(self, frame_args) if name == nil then local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return "{{" .. concat(output, "|") .. "}}" elseif subclass == "parser variable" then return (frame or get_frame()):preprocess("{{" .. name .. "}}") elseif subclass == "parser function" then local f = frame or get_frame() if frame_args ~= nil then local success, new_f = pcall(f.newChild, f, {args = frame_args}) if success then f = new_f end end return f:preprocess(tostring(self)) end local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return (frame or get_frame()):preprocess("{{" .. concat(output, "|") .. "}}") end end local Tag = Node:new_class("tag") function Tag:__tostring() local open_tag, attributes, n = {"<", self.name}, self:get_attributes(), 2 for attr, value in next, attributes do n = n + 1 open_tag[n] = " " .. php_htmlspecialchars(attr) .. "=\"" .. php_htmlspecialchars(value, "compat") .. "\"" end if self.self_closing then return concat(open_tag) .. "/>" end return concat(open_tag) .. ">" .. concat(self) .. "</" .. self.name .. ">" end do local valid_attribute_name local function get_valid_attribute_name() valid_attribute_name, get_valid_attribute_name = (data or get_data()).valid_attribute_name, nil return valid_attribute_name end function Tag:get_attributes() local raw = self.attributes if not raw then self.attributes = {} return self.attributes elseif type(raw) == "table" then return raw end if sub(raw, -1) == "/" then raw = sub(raw, 1, -2) end local attributes, head = {}, 1 -- Semi-manual implementation of the native regex. while true do local name, loc = match(raw, "([^\t\n\f\r />][^\t\n\f\r /=>]*)()", head) if not name then break end head = loc local value loc = match(raw, "^[\t\n\f\r ]*=[\t\n\f\r ]*()", head) if loc then head = loc -- Either "", '' or the value ends on a space/at the end. Missing -- end quotes are repaired by closing the value at the end. value, loc = match(raw, "^\"([^\"]*)\"?()", head) if not value then value, loc = match(raw, "^'([^']*)'?()", head) if not value then value, loc = match(raw, "^([^\t\n\f\r ]*)()", head) end end head = loc end -- valid_attribute_name is a pattern matching a valid attribute name. -- Defined in the data due to its length - see there for more info. if umatch(name, valid_attribute_name or get_valid_attribute_name()) then -- Sanitizer applies PHP strtolower (ASCII-only). attributes[lower(name)] = value and decode_entities( php_trim((gsub(value, "[\t\n\r ]+", " "))) ) or "" end end self.attributes = attributes return attributes end end function Tag:expand() return (frame or get_frame()):preprocess(tostring(self)) end local Heading = Node:new_class("heading") function Heading:new(this) if #this > 1 then local success, str = pcall(concat, this) if success then return new_node(self, { str, level = this.level, section = this.section, index = this.index }) end end return new_node(self, this) end do local node_tostring = Node.__tostring function Heading:__tostring() local eq = rep("=", self.level) return eq .. node_tostring(self) .. eq end end do local expand_node = Node.expand -- Expanded heading names can contain "\n" (e.g. inside nowiki tags), which -- causes any heading containing them to fail. However, in such cases, the -- native parser still treats it as a heading for the purpose of section -- numbers. local function validate_name(self, frame_args) local name = expand_node(self, frame_args) if find(name, "\n", nil, true) then return nil end return name end function Heading:get_name(frame_args) local name = validate_name(self, frame_args) return name ~= nil and php_trim(name) or nil end -- FIXME: account for anchor disambiguation. function Heading:get_anchor(frame_args) local name = validate_name(self, frame_args) return name ~= nil and decode_entities(anchor_encode(name)) or nil end function Heading:expand(frame_args) local eq = rep("=", self.level) return eq .. expand_node(self, frame_args) .. eq end end ------------------------------------------------------------------------------------ -- -- Parser -- ------------------------------------------------------------------------------------ local Parser = m_parser.string_parser() -- Template or parameter. -- Parsed by matching the opening braces innermost-to-outermost (ignoring lone closing braces). Parameters {{{ }}} take priority over templates {{ }} where possible, but a double closing brace will always result in a closure, even if there are 3+ opening braces. -- For example, "{{{{foo}}}}" (4) is parsed as a parameter enclosed by single braces, and "{{{{{foo}}}}}" (5) is a parameter inside a template. However, "{{{{{foo }} }}}" is a template inside a parameter, due to "}}" forcing the closure of the inner node. do -- Handlers. local handle_name local handle_argument local handle_value local function do_template_or_parameter(self, inner_node) self:push_sublayer(handle_name) self:set_pattern("[\n<[{|}]") -- If a node has already been parsed, nest it at the start of the new -- outer node (e.g. when parsing"{{{{foo}}bar}}", the template "{{foo}}" -- is parsed first, since it's the innermost, and becomes the first -- node of the outer template. if inner_node then self:emit(inner_node) end end local function pipe(self) self:emit(Wikitext:new(self:pop_sublayer())) self:push_sublayer(handle_argument) self:set_pattern("[\n<=[{|}]") end local function rbrace(self, this) if self:read(1) == "}" then self:emit(Wikitext:new(self:pop_sublayer())) return self:pop() end self:emit(this) end function handle_name(self, ...) handle_name = self:switch(handle_name, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = pipe, ["}"] = rbrace, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_name(self, ...) end function handle_argument(self, ...) handle_argument = self:switch(handle_argument, { ["\n"] = function(self, this) return self:heading_block(this, "==") end, ["<"] = Parser.tag, ["="] = function(self) local key = self:pop_sublayer() self:push_sublayer(handle_value) self:set_pattern("[\n<[{|}]") self.current_layer._parse_data.key = key end, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = pipe, ["}"] = rbrace, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_argument(self, ...) end function handle_value(self, ...) handle_value = self:switch(handle_value, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = function(self) self:emit(Argument:new(self:pop_sublayer())) self:push_sublayer(handle_argument) self:set_pattern("[\n<=[{|}]") end, ["}"] = function(self, this) if self:read(1) == "}" then self:emit(Argument:new(self:pop_sublayer())) return self:pop() end self:emit(this) end, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_value(self, ...) end function Parser:template_or_parameter() local text, head, node_to_emit, failed = self.text, self.head -- Comments/tags interrupt the brace count. local braces = match(text, "^{+()", head) - head self:advance(braces) while true do local success, node = self:try(do_template_or_parameter, node_to_emit) -- Fail means no "}}" or "}}}" was found, so emit any remaining -- unmatched opening braces before any templates/parameters that -- were found. if not success then self:emit(rep("{", braces)) failed = true break -- If there are 3+ opening and closing braces, it's a parameter. elseif braces >= 3 and self:read(2) == "}" then self:advance(3) braces = braces - 3 node = Parameter:new(node) -- Otherwise, it's a template. else self:advance(2) braces = braces - 2 node = Template:new(node) end local index = head + braces node.index = index node.raw = sub(text, index, self.head - 1) node_to_emit = node -- Terminate once not enough braces remain for further matches. if braces == 0 then break -- Emit any stray opening brace before any matched nodes. elseif braces == 1 then self:emit("{") break end end if node_to_emit then self:emit(node_to_emit) end return braces, failed end end -- Tag. do local end_tags local function get_end_tags() end_tags, get_end_tags = (data or get_data()).end_tags, nil return end_tags end -- Handlers. local handle_start local handle_tag local function do_tag(self) local layer = self.current_layer layer._parse_data.handler, layer.index = handle_start, self.head self:set_pattern("[%s/>]") self:advance() end local function is_ignored_tag(self, this) if self.transcluded then return this == "includeonly" end return this == "noinclude" or this == "onlyinclude" end local function ignored_tag(self, text, head) local loc = find(text, ">", head, true) if not loc then return self:fail_route() end self:jump(loc) local tag = self:pop() tag.ignored = true return tag end function handle_start(self, this) if this == "/" then local text, head = self.text, self.head + 1 local this = match(text, "^[^%s/>]+", head) if this and is_ignored_tag(self, lower(this)) then head = head + #this if not match(text, "^/[^>]", head) then return ignored_tag(self, text, head) end end return self:fail_route() elseif this == "" then return self:fail_route() end -- Tags are only case-insensitive with ASCII characters. local raw_name = this this = lower(this) local end_tag_pattern = (end_tags or get_end_tags())[this] if not end_tag_pattern then -- Validity check. return self:fail_route() end local layer = self.current_layer local pdata = layer._parse_data local text, head = self.text, self.head + pdata.step if match(text, "^/[^>]", head) then return self:fail_route() elseif is_ignored_tag(self, this) then return ignored_tag(self, text, head) -- If an onlyinclude tag is not ignored (and cannot be active since it -- would have triggered special handling earlier), it must be plaintext. elseif this == "onlyinclude" then return self:fail_route() elseif this == "noinclude" or this == "includeonly" then layer.ignored = true -- Ignored block. layer.raw_name = raw_name end layer.name, pdata.handler, pdata.end_tag_pattern = this, handle_tag, end_tag_pattern self:set_pattern(">") end function handle_tag(self, this) if this == "" then return self:fail_route() end local layer = self.current_layer if this ~= ">" then layer.attributes = this return elseif self:read(-1) == "/" then layer.self_closing = true return self:pop() end local text, head = self.text, self.head + 1 local loc1, loc2 = find(text, layer._parse_data.end_tag_pattern, head) if loc1 then if loc1 > head then self:emit(sub(text, head, loc1 - 1)) end self:jump(loc2) return self:pop() -- noinclude and includeonly will tolerate having no closing tag, but -- only if given in lowercase. This is due to a preprocessor bug, as -- it uses a regex with the /i (case-insensitive) flag to check for -- end tags, but a simple array lookup with lowercase tag names when -- looking up which tags should tolerate no closing tag (exact match -- only, so case-sensitive). elseif layer.ignored then local raw_name = layer.raw_name if raw_name == "noinclude" or raw_name == "includeonly" then self:jump(#text) return self:pop() end end return self:fail_route() end function Parser:tag() -- HTML comment. if self:read(1, 3) == "!--" then local text = self.text self:jump(select(2, find(text, "-->", self.head + 4, true)) or #text) -- onlyinclude tags (which must be lowercase with no whitespace). elseif self.onlyinclude and self:read(1, 13) == "/onlyinclude>" then local text = self.text self:jump(select(2, find(text, "<onlyinclude>", self.head + 14, true)) or #text) else local success, tag = self:try(do_tag) if not success then self:emit("<") elseif not tag.ignored then self:emit(Tag:new(tag)) end end end end -- Heading. -- The preparser assigns each heading a number, which is used for things like section edit links. The preparser will only do this for heading blocks which aren't nested inside templates, parameters and parser tags. In some cases (e.g. when template blocks contain untrimmed newlines), a preparsed heading may not be treated as a heading in the final output. That does not affect the preparser, however, which will always count sections based on the preparser heading count, since it can't know what a template's final output will be. do -- Handlers. local handle_start local handle_body local handle_possible_end local function do_heading(self) local layer, head = self.current_layer, self.head layer._parse_data.handler, layer.index = handle_start, head self:set_pattern("[\t\n ]") -- Comments/tags interrupt the equals count. local eq = match(self.text, "^=+()", head) - head layer.level = eq self:advance(eq) end local function do_heading_possible_end(self) self.current_layer._parse_data.handler = handle_possible_end self:set_pattern("[\n<]") end function handle_start(self, ...) -- ===== is "=" as an L2; ======== is "==" as an L3 etc. local function newline(self) local layer = self.current_layer local eq = layer.level if eq <= 2 then return self:fail_route() end -- Calculate which equals signs determine the heading level. local level_eq = eq - (2 - eq % 2) level_eq = level_eq > 12 and 12 or level_eq -- Emit the excess. self:emit(rep("=", eq - level_eq)) layer.level = level_eq / 2 return self:pop() end local function whitespace(self) local success, possible_end = self:try(do_heading_possible_end) if success then self:emit(Wikitext:new(possible_end)) self.current_layer._parse_data.handler = handle_body self:set_pattern("[\n<=[{]") return self:consume() end return newline(self) end handle_start = self:switch(handle_start, { ["\t"] = whitespace, ["\n"] = newline, [" "] = whitespace, [""] = newline, [false] = function(self) -- Emit any excess = signs once we know it's a conventional heading. Up till now, we couldn't know if the heading is just a string of = signs (e.g. ========), so it wasn't guaranteed that the heading text starts after the 6th. local layer = self.current_layer local eq = layer.level if eq > 6 then self:emit(1, rep("=", eq - 6)) layer.level = 6 end layer._parse_data.handler = handle_body self:set_pattern("[\n<=[{]") return self:consume() end }) return handle_start(self, ...) end function handle_body(self, ...) handle_body = self:switch(handle_body, { ["\n"] = Parser.fail_route, ["<"] = Parser.tag, ["="] = function(self) -- Comments/tags interrupt the equals count. local eq = match(self.text, "^=+", self.head) local eq_len = #eq self:advance(eq_len) local success, possible_end = self:try(do_heading_possible_end) if success then self:emit(eq) self:emit(Wikitext:new(possible_end)) return self:consume() end local layer = self.current_layer local level = layer.level if eq_len > level then self:emit(rep("=", eq_len - level)) elseif level > eq_len then layer.level = eq_len self:emit(1, rep("=", level - eq_len)) end return self:pop() end, ["["] = Parser.wikilink_block, ["{"] = function(self, this) return self:braces(this, true) end, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_body(self, ...) end function handle_possible_end(self, ...) handle_possible_end = self:switch(handle_possible_end, { ["\n"] = Parser.fail_route, ["<"] = function(self) if self:read(1, 3) ~= "!--" then return self:pop() end local head = select(2, find(self.text, "-->", self.head + 4, true)) if not head then return self:pop() end self:jump(head) end, [""] = Parser.fail_route, [false] = function(self, this) if not match(this, "^[\t ]+()$") then return self:pop() end self:emit(this) end }) return handle_possible_end(self, ...) end function Parser:heading() local success, heading = self:try(do_heading) if success then local section = self.section + 1 heading.section = section self.section = section self:emit(Heading:new(heading)) return self:consume() else self:emit("=") end end end ------------------------------------------------------------------------------------ -- -- Block handlers -- ------------------------------------------------------------------------------------ -- Block handlers. -- These are blocks which can affect template/parameter parsing, since they're also parsed by Parsoid at the same time (even though they aren't processed until later). -- All blocks (including templates/parameters) can nest inside each other, but an inner block must be closed before the outer block which contains it. This is why, for example, the wikitext "{{template| [[ }}" will result in an unprocessed template, since the inner "[[" is treated as the opening of a wikilink block, which prevents "}}" from being treated as the closure of the template block. On the other hand, "{{template| [[ ]] }}" will process correctly, since the wikilink block is closed before the template closure. It makes no difference whether the block will be treated as valid or not when it's processed later on, so "{{template| [[ }} ]] }}" would also work, even though "[[ }} ]]" is not a valid wikilink. -- Note that nesting also affects pipes and equals signs, in addition to block closures. -- These blocks can be nested to any degree, so "{{template| [[ [[ [[ ]] }}" will not work, since only one of the three wikilink blocks has been closed. On the other hand, "{{template| [[ [[ [[ ]] ]] ]] }}" will work. -- All blocks are implicitly closed by the end of the text, since their validity is irrelevant at this stage. -- Language conversion block. -- Opens with "-{" and closes with "}-". However, templates/parameters take priority, so "-{{" is parsed as "-" followed by the opening of a template/parameter block (depending on what comes after). -- Note: Language conversion blocks aren't actually enabled on the English Wiktionary, but Parsoid still parses them at this stage, so they can affect the closure of outer blocks: e.g. "[[ -{ ]]" is not a valid wikilink block, since the "]]" falls inside the new language conversion block. do --Handler. local handle_language_conversion_block local function do_language_conversion_block(self) self.current_layer._parse_data.handler = handle_language_conversion_block self:set_pattern("[\n<[{}]") end function handle_language_conversion_block(self, ...) handle_language_conversion_block = self:switch(handle_language_conversion_block, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["}"] = function(self, this) if self:read(1) == "-" then self:emit("}-") self:advance() return self:pop() end self:emit(this) end, [""] = Parser.pop, [false] = Parser.emit }) return handle_language_conversion_block(self, ...) end function Parser:braces(this, fail_on_unclosed_braces) local language_conversion_block = self:read(-1) == "-" if self:read(1) == "{" then local braces, failed = self:template_or_parameter() -- Headings will fail if they contain an unclosed brace block. if failed and fail_on_unclosed_braces then return self:fail_route() -- Language conversion blocks cannot begin "-{{", but can begin -- "-{{{" iff parsed as "-{" + "{{". elseif not (language_conversion_block and braces == 1) then return self:consume() end else self:emit(this) if not language_conversion_block then return end self:advance() end self:emit(Wikitext:new(self:get(do_language_conversion_block))) end end --[==[ Headings Opens with "\n=" (or "=" at the start of the text), and closes with "\n" or the end of the text. Note that it doesn't matter whether the heading will fail to process due to a premature newline (e.g. if there are no closing signs), so at this stage the only thing that matters for closure is the newline or end of text. Note: Heading blocks are only parsed like this if they occur inside a template, since they do not iterate the preparser's heading count (i.e. they aren't proper headings). Note 2: if directly inside a template argument with no previous equals signs, a newline followed by a single equals sign is parsed as an argument equals sign, not the opening of a new L1 heading block. This does not apply to any other heading levels. As such, {{template|key\n=}}, {{template|key\n=value}} or even {{template|\n=}} will successfully close, but {{template|key\n==}}, {{template|key=value\n=more value}}, {{template\n=}} etc. will not, since in the latter cases the "}}" would fall inside the new heading block. ]==] do --Handler. local handle_heading_block local function do_heading_block(self) self.current_layer._parse_data.handler = handle_heading_block self:set_pattern("[\n<[{]") end function handle_heading_block(self, ...) handle_heading_block = self:switch(handle_heading_block, { ["\n"] = function(self) self:newline() return self:pop() end, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, [""] = Parser.pop, [false] = Parser.emit }) return handle_heading_block(self, ...) end function Parser:heading_block(this, nxt) self:newline() this = this .. (nxt or "=") local loc = #this - 1 while self:read(0, loc) == this do self:advance() self:emit(Wikitext:new(self:get(do_heading_block))) end end end -- Wikilink block. -- Opens with "[[" and closes with "]]". do -- Handler. local handle_wikilink_block local function do_wikilink_block(self) self.current_layer._parse_data.handler = handle_wikilink_block self:set_pattern("[\n<[%]{]") end function handle_wikilink_block(self, ...) handle_wikilink_block = self:switch(handle_wikilink_block, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["]"] = function(self, this) if self:read(1) == "]" then self:emit("]]") self:advance() return self:pop() end self:emit(this) end, ["{"] = Parser.braces, [""] = Parser.pop, [false] = Parser.emit }) return handle_wikilink_block(self, ...) end function Parser:wikilink_block() if self:read(1) == "[" then self:emit("[[") self:advance(2) self:emit(Wikitext:new(self:get(do_wikilink_block))) else self:emit("[") end end end -- Lines which only contain comments, " " and "\t" are eaten, so long as -- they're bookended by "\n" (i.e. not the first or last line). function Parser:newline() local text, head = self.text, self.head while true do repeat local loc = match(text, "^[\t ]*<!%-%-()", head + 1) if not loc then break end loc = select(2, find(text, "-->", loc, true)) head = loc or head until not loc -- Fail if no comments found. if head == self.head then break end head = match(text, "^[\t ]*()\n", head + 1) if not head then break end self:jump(head) end self:emit("\n") end do -- Handlers. local handle_start local main_handler -- If `transcluded` is true, then the text is checked for a pair of -- onlyinclude tags. If these are found (even if they're in the wrong -- order), then the start of the page is treated as though it is preceded -- by a closing onlyinclude tag. -- Note 1: unlike other parser extension tags, onlyinclude tags are case- -- sensitive and cannot contain whitespace. -- Note 2: onlyinclude tags *can* be implicitly closed by the end of the -- text, but the hard requirement above means this can only happen if -- either the tags are in the wrong order or there are multiple onlyinclude -- blocks. local function do_parse(self, transcluded) self.current_layer._parse_data.handler = handle_start self:set_pattern(".") self.section = 0 if not transcluded then return end self.transcluded = true local text = self.text if find(text, "</onlyinclude>", nil, true) then local head = find(text, "<onlyinclude>", nil, true) if head then self.onlyinclude = true self:jump(head + 13) end end end -- If the first character is "=", try parsing it as a heading. function handle_start(self, this) self.current_layer._parse_data.handler = main_handler self:set_pattern("[\n<{]") if this == "=" then return self:heading() end return self:consume() end function main_handler(self, ...) main_handler = self:switch(main_handler, { ["\n"] = function(self) self:newline() if self:read(1) == "=" then self:advance() return self:heading() end end, ["<"] = Parser.tag, ["{"] = function(self, this) if self:read(1) == "{" then self:template_or_parameter() return self:consume() end self:emit(this) end, [""] = Parser.pop, [false] = Parser.emit }) return main_handler(self, ...) end function export.parse(text, transcluded) local text_type = type(text) return (select(2, Parser:parse{ text = text_type == "string" and text or text_type == "number" and tostring(text) or error("bad argument #1 (string expected, got " .. text_type .. ")"), node = {Wikitext, true}, route = {do_parse, transcluded} })) end parse = export.parse end function export.find_templates(text, not_transcluded) return parse(text, not not_transcluded):iterate_nodes("template") end do local link_parameter_1, link_parameter_2 local function get_link_parameter_1() link_parameter_1, get_link_parameter_1 = (data or get_data()).template_link_param_1, nil return link_parameter_1 end local function get_link_parameter_2() link_parameter_2, get_link_parameter_2 = (data or get_data()).template_link_param_2, nil return link_parameter_2 end -- Generate a link. If the target title doesn't have a fragment, use "#top" -- (which is an implicit anchor at the top of every page), as this ensures -- self-links still display as links, since bold display is distracting and -- unintuitive for template links. local function link_page(title, display) local fragment = title.fragment if fragment == "" then fragment = "top" end return format( "[[:%s|%s]]", encode_uri(title.prefixedText .. "#" .. fragment, "WIKI"), display ) end -- pf_arg1 or pf_arg2 may need to be linked if a given parser function -- treats them as a pagename. If a key exists in `namespace`, the value is -- the namespace for the page: if not 0, then the namespace prefix will -- always be added to the input (e.g. {{#invoke:}} can only target the -- Module: namespace, so inputting "Template:foo" gives -- "Module:Template:foo", and "Module:foo" gives "Module:Module:foo"). -- However, this isn't possible with mainspace (namespace 0), so prefixes -- are respected. make_title() handles all of this automatically. local function finalize_arg(pagename, namespace) if namespace == nil then return pagename end local title = make_title(namespace, pagename) return title and not title.isExternal and link_page(title, pagename) or pagename end local function render_title(name, args) -- parse_template_name returns a table of transclusion modifiers plus -- the normalized template/magic word name, which will be used as link -- targets. The third return value pf_arg1 is the first argument of a -- a parser function, which comes after the colon (e.g. "foo" in -- "{{#IF:foo|bar|baz}}"). This means args[1] (i.e. the first argument -- that comes after a pipe is actually argument 2, and so on. Note: the -- second parameter of parse_template_name checks if there are any -- arguments, since parser variables cannot take arguments (e.g. -- {{CURRENTYEAR}} is a parser variable, but {{CURRENTYEAR|foo}} -- transcludes "Template:CURRENTYEAR"). In such cases, the returned -- table explicitly includes the "Template:" prefix in the template -- name. The third parameter instructs it to retain any fragment in the -- template name in the returned table, if present. local chunks, subclass, pf_arg1 = parse_template_name( name, args and pairs(args)(args) ~= nil, true ) if chunks == nil then return name, args end local chunks_len = #chunks -- Additionally, generate the corresponding table `rawchunks`, which -- is a list of colon-separated chunks in the raw input. This is used -- to retrieve the display forms for each chunk. local rawchunks = split(name, ":") for i = 1, chunks_len - 1 do chunks[i] = format( "[[%s|%s]]", encode_uri((magic_words or get_magic_words())[sub(chunks[i], 1, -2)].transclusion_modifier, "WIKI"), rawchunks[i] ) end local chunk = chunks[chunks_len] -- If it's a template, return a link to it with link_page, concatenating -- the remaining chunks in `rawchunks` to form the display text. -- Use new_title with the default namespace 10 (Template:) to generate -- a target title, which is the same setting used for retrieving -- templates (including those in other namespaces, as prefixes override -- the default). if subclass == "template" then chunks[chunks_len] = link_page( new_title(chunk, 10), concat(rawchunks, "&#58;", chunks_len) -- : ) return concat(chunks, "&#58;"), args -- : elseif subclass == "parser variable" then chunks[chunks_len] = format( "[[%s|%s]]", encode_uri((magic_words or get_magic_words())[chunk].parser_variable, "WIKI"), rawchunks[chunks_len] ) return concat(chunks, "&#58;"), args -- : end -- Otherwise, it must be a parser function. local mgw_data = (magic_words or get_magic_words())[sub(chunk, 1, -2)] local link = mgw_data.parser_function or mgw_data.transclusion_modifier local pf_arg2 = args and args[1] or nil -- Some magic words have different links, depending on whether argument -- 2 is specified (e.g. "baz" in {{foo:bar|baz}}). if type(link) == "table" then link = pf_arg2 and link[2] or link[1] end chunks[chunks_len] = format( "[[%s|%s]]", encode_uri(link, "WIKI"), rawchunks[chunks_len] ) -- #TAG: has special handling, because documentation links for parser -- extension tags come from [[Module:data/parser extension tags]]. if chunk == "#TAG:" then -- Tags are only case-insensitive with ASCII characters. local tag = (parser_extension_tags or get_parser_extension_tags())[lower(php_trim(pf_arg1))] if tag then pf_arg1 = format( "[[%s|%s]]", encode_uri(tag, "WIKI"), pf_arg1 ) end -- Otherwise, finalize pf_arg1 and add it to `chunks`. else pf_arg1 = finalize_arg(pf_arg1, (link_parameter_1 or get_link_parameter_1())[chunk]) end chunks[chunks_len + 1] = pf_arg1 -- Finalize pf_arg2 (if applicable), then return. if pf_arg2 then args = shallow_copy(args) -- Avoid destructively modifying args. args[1] = finalize_arg(pf_arg2, (link_parameter_2 or get_link_parameter_2())[chunk]) end return concat(chunks, "&#58;"), args -- : end function export.buildTemplate(title, args) local output = {title} if not args then return output end -- Iterate over all numbered parameters in order, followed by any -- remaining parameters in codepoint order. Implicit parameters are -- used wherever possible, even if explicit numbers are interpolated -- between them (e.g. 0 would go before any implicit parameters, and -- 2.5 between 2 and 3). -- TODO: handle "=" and "|" in params/values. local implicit for k, v in sorted_pairs(args) do if type(k) == "number" and k >= 1 and k % 1 == 0 then if implicit == nil then implicit = table_len(args) end insert(output, k <= implicit and v or k .. "=" .. v) else insert(output, k .. "=" .. v) end end return output end build_template = export.buildTemplate function export.templateLink(title, args, no_link) if not no_link then title, args = render_title(title, args) end local output = build_template(title, args) for i = 1, #output do output[i] = encode_entities(output[i], "={}", true, true) end return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&#123;&#123;" .. concat(output, "&#124;") .. "&#125;&#125;") -- {{ | }} ) end end do function export.find_parameters(text, not_transcluded) return parse(text, not not_transcluded):iterate_nodes("parameter") end function export.displayParameter(name, default) return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&#123;&#123;&#123;" .. concat({name, default}, "&#124;") .. "&#125;&#125;&#125;") -- {{{ | }}} ) end end do local function check_level(level) if type(level) ~= "number" then error("Heading levels must be numbers.") elseif level < 1 or level > 6 or level % 1 ~= 0 then error("Heading levels must be integers between 1 and 6.") end return level end -- FIXME: should headings which contain "\n" be returned? This may depend -- on variable factors, like template expansion. They iterate the heading -- count number, but fail on rendering. However, in some cases a different -- heading might still be rendered due to intermediate equals signs; it -- may even be of a different heading level: e.g., this is parsed as an -- L2 heading with a newline (due to the wikilink block), but renders as the -- L1 heading "=foo[[". Section edit links are sometimes (but not always) -- present in such cases. -- ==[[= -- ]]== -- TODO: section numbers for edit links seem to also include headings -- nested inside templates and parameters (but apparently not those in -- parser extension tags - need to test this more). If we ever want to add -- section edit links manually, this will need to be accounted for. function export.find_headings(text, i, j) local parsed = parse(text) if i == nil and j == nil then return parse(text):iterate_nodes("heading") end i = i and check_level(i) or 1 j = j and check_level(j) or 6 return parsed:iterate(function(v) if class_else_type(v) == "heading" then local level = v.level return level >= i and level <= j end end) end end do local function make_tag(tag) return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&lt;" .. tag .. "&gt;") ) end -- Note: invalid tags are returned without links. function export.wikitagLink(tag) -- ">" can't appear in tags (including attributes) since the parser -- unconditionally treats ">" as the end of a tag. if find(tag, ">", nil, true) then return make_tag(tag) end -- Tags must start "<tagname..." or "</tagname...", with no whitespace -- after "<" or "</". local slash, tagname, remainder = match(tag, "^(/?)([^/%s]+)(.*)$") if not tagname then return make_tag(tag) end -- Tags are only case-insensitive with ASCII characters. local link = lower(tagname) if ( -- onlyinclude tags must be lowercase and are whitespace intolerant. link == "onlyinclude" and (link ~= tagname or remainder ~= "") or -- Closing wikitags (except onlyinclude) can only have whitespace -- after the tag name. slash == "/" and not match(remainder, "^%s*()$") or -- Tagnames cannot be followed immediately by "/", unless it comes -- at the end (e.g. "<nowiki/>", but not "<nowiki/ >"). remainder ~= "/" and sub(remainder, 1, 1) == "/" ) then -- Output with no link. return make_tag(tag) end -- Partial transclusion tags aren't in the table of parser extension -- tags. if link == "noinclude" or link == "includeonly" or link == "onlyinclude" then link = "mw:Transclusion#Partial transclusion" else link = (parser_extension_tags or get_parser_extension_tags())[link] end if link then tag = gsub(tag, pattern_escape(tagname), "[[" .. replacement_escape(encode_uri(link, "WIKI")) .. "|%0]]", 1) end return make_tag(tag) end end -- For convenience. export.class_else_type = class_else_type return export g7883esvq9rqr796jeq8jsmk6y4r8t1 237274 237273 2026-09-11T11:23:50Z Lee 19 [[:en:Module:template_parser]] වෙතින් එක් සංශෝධනයක් 237273 Scribunto text/plain --[[ NOTE: This module works by using recursive backtracking to build a node tree, which can then be traversed as necessary. Because it is called by a number of high-use modules, it has been optimised for speed using a profiler, since it is used to scrape data from large numbers of pages very quickly. To that end, it rolls some of its own methods in cases where this is faster than using a function from one of the standard libraries. Please DO NOT "simplify" the code by removing these, since you are almost guaranteed to slow things down, which could seriously impact performance on pages which call this module hundreds or thousands of times. It has also been designed to emulate the native parser's behaviour as much as possible, which in some cases means replicating bugs or unintuitive behaviours in that code; these should not be "fixed", since it is important that the outputs are the same. Most of these originate from deficient regular expressions, which can't be used here, so the bugs have to be manually reintroduced as special cases (e.g. onlyinclude tags being case-sensitive and whitespace intolerant, unlike all other tags). If any of these are fixed, this module should also be updated accordingly. ]] local export = {} local data_module = "Module:template parser/data" local load_module = "Module:load" local magic_words_data_module = "Module:data/magic words" local pages_module = "Module:pages" local parser_extension_tags_data_module = "Module:data/parser extension tags" local parser_module = "Module:parser" local scribunto_module = "Module:Scribunto" 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_length_module = "Module:table/length" local table_shallow_copy_module = "Module:table/shallowCopy" local table_sorted_pairs_module = "Module:table/sortedPairs" local title_is_title_module = "Module:title/isTitle" local title_make_title_module = "Module:title/makeTitle" local title_new_title_module = "Module:title/newTitle" local title_redirect_target_module = "Module:title/redirectTarget" local require = require local m_parser = require(parser_module) local mw = mw local mw_title = mw.title local mw_uri = mw.uri local string = string local table = table local anchor_encode = mw_uri.anchorEncode local build_template -- defined as export.buildTemplate below local class_else_type = m_parser.class_else_type local concat = table.concat local encode_uri = mw_uri.encode local find = string.find local format = string.format local gsub = string.gsub local html_create = mw.html.create local insert = table.insert local is_node = m_parser.is_node local lower = string.lower local match = string.match local next = next local pairs = pairs local parse -- defined as export.parse below local parse_template_name -- defined below local pcall = pcall local rep = string.rep local select = select local sub = string.sub local title_equals = mw_title.equals local tostring = m_parser.tostring local type = type local umatch = mw.ustring.match --[==[ Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==] local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function encode_entities(...) encode_entities = require(string_utilities_module).encode_entities return encode_entities(...) end local function get_link_target(...) get_link_target = require(pages_module).get_link_target return get_link_target(...) end local function is_title(...) is_title = require(title_is_title_module) return is_title(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_title(...) make_title = require(title_make_title_module) return make_title(...) end local function new_title(...) new_title = require(title_new_title_module) return new_title(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function php_htmlspecialchars(...) php_htmlspecialchars = require(scribunto_module).php_htmlspecialchars return php_htmlspecialchars(...) end local function php_ltrim(...) php_ltrim = require(scribunto_module).php_ltrim return php_ltrim(...) end local function php_trim(...) php_trim = require(scribunto_module).php_trim return php_trim(...) end local function redirect_target(...) redirect_target = require(title_redirect_target_module) return redirect_target(...) 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 shallow_copy(...) shallow_copy = require(table_shallow_copy_module) return shallow_copy(...) end local function sorted_pairs(...) sorted_pairs = require(table_sorted_pairs_module) return sorted_pairs(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function table_len(...) table_len = require(table_length_module) return table_len(...) end local function uupper(...) uupper = require(string_utilities_module).upper return uupper(...) end --[==[ Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] local data local function get_data() data, get_data = load_data(data_module), nil return data end local frame local function get_frame() frame, get_frame = mw.getCurrentFrame(), nil return frame end local magic_words local function get_magic_words() magic_words, get_magic_words = load_data(magic_words_data_module), nil return magic_words end local parser_extension_tags local function get_parser_extension_tags() parser_extension_tags, get_parser_extension_tags = load_data(parser_extension_tags_data_module), nil return parser_extension_tags end ------------------------------------------------------------------------------------ -- -- Nodes -- ------------------------------------------------------------------------------------ local Node = m_parser.node() local new_node = Node.new local function expand(obj, frame_args) return is_node(obj) and obj:expand(frame_args) or obj end export.expand = expand function Node:expand(frame_args) local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return concat(output) end local Wikitext = Node:new_class("wikitext") -- force_node ensures the output will always be a Wikitext node. function Wikitext:new(this, force_node) if type(this) ~= "table" then return force_node and new_node(self, {this}) or this elseif #this == 1 then local this1 = this[1] return force_node and class_else_type(this1) ~= "wikitext" and new_node(self, this) or this1 end local success, str = pcall(concat, this) if success then return force_node and new_node(self, {str}) or str end return new_node(self, this) end -- First value is the parameter name. -- Second value is the parameter's default value. -- Any additional values are ignored: e.g. "{{{a|b|c}}}" is parameter "a" with default value "b" (*not* "b|c"). local Parameter = Node:new_class("parameter") function Parameter:new(this) local this2 = this[2] if class_else_type(this2) == "argument" then insert(this2, 2, "=") this2 = Wikitext:new(this2) end if this[3] == nil then this[2] = this2 else this = {this[1], this2} end return new_node(self, this) end function Parameter:__tostring() local output = {} for i = 1, #self do output[i] = tostring(self[i]) end return "{{{" .. concat(output, "|") .. "}}}" end function Parameter:get_name(frame_args) return scribunto_parameter_key(expand(self[1], frame_args)) end function Parameter:get_default(frame_args) local default = self[2] if default ~= nil then return expand(default, frame_args) end return "{{{" .. expand(self[1], frame_args) .. "}}}" end function Parameter:expand(frame_args) if frame_args == nil then return self:get_default() end local name = expand(self[1], frame_args) local val = frame_args[scribunto_parameter_key(name)] -- Parameter in use. if val ~= nil then return val end val = self[2] -- Default. if val ~= nil then return expand(val, frame_args) end return "{{{" .. name .. "}}}" end local Argument = Node:new_class("argument") function Argument:new(this) local key = this._parse_data.key this = Wikitext:new(this) if key == nil then return this end return new_node(self, {Wikitext:new(key), this}) end function Argument:__tostring() return tostring(self[1]) .. "=" .. tostring(self[2]) end function Argument:expand(frame_args) return expand(self[1], frame_args) .. "=" .. expand(self[2], frame_args) end local Template = Node:new_class("template") function Template:__tostring() local output = {} for i = 1, #self do output[i] = tostring(self[i]) end return "{{" .. concat(output, "|") .. "}}" end -- Normalize the template name, check it's a valid template, then memoize results (using false for invalid titles). -- Parser functions (e.g. {{#IF:a|b|c}}) need to have the first argument extracted from the title, as it comes after the colon. Because of this, the parser function and first argument are memoized as a table. -- FIXME: Some parser functions have special argument handling (e.g. {{#SWITCH:}}). do local templates, parser_variables, parser_functions = {}, {}, {} local function retrieve_magic_word_data(chunk) local mgw_data = (magic_words or get_magic_words())[chunk] if mgw_data then return mgw_data end local normalized = uupper(chunk) mgw_data = magic_words[normalized] if mgw_data and not mgw_data.case_sensitive then return mgw_data end end -- Returns the name required to transclude the title object `title` using -- template {{ }} syntax. If the `shortcut` flag is set, then any calls -- which require a namespace prefix will use the abbreviated form where one -- exists (e.g. "Template:PAGENAME" becomes "T:PAGENAME"). local function get_template_invocation_name(title, shortcut) if not (is_title(title) and not title.isExternal) then error("Template invocations require a valid page title, which cannot contain an interwiki prefix.") end local namespace = title.namespace -- If not in the template namespace, include the prefix (or ":" if -- mainspace). if namespace ~= 10 then return get_link_target(title, shortcut) end -- If in the template namespace and it shares a name with a magic word, -- it needs the prefix "Template:". local text, fragment = title.text, title.fragment if fragment and fragment ~= "" then text = text .. "#" .. fragment end local colon = find(text, ":", nil, true) if not colon then local mgw_data = retrieve_magic_word_data(text) return mgw_data and mgw_data.parser_variable and get_link_target(title, shortcut) or text end local mgw_data = retrieve_magic_word_data(sub(text, 1, colon - 1)) if mgw_data and (mgw_data.parser_function or mgw_data.transclusion_modifier) then return get_link_target(title, shortcut) end -- Also if "Template:" is necessary for disambiguation (e.g. -- "Template:Category:Foo" can't be called with "Category:Foo"). local check = new_title(text, namespace) return check and title_equals(title, check) and text or get_link_target(title, shortcut) end export.getTemplateInvocationName = get_template_invocation_name function parse_template_name(name, has_args, fragment, force_transclusion) local chunks, colon, start, n, p = {}, find(name, ":", nil, true), 1, 0, 0 while colon do local mgw_data = retrieve_magic_word_data(php_ltrim(sub(name, start, colon - 1))) if not mgw_data then break end local priority = mgw_data.priority if not (priority and priority > p) then local pf = mgw_data.parser_function and mgw_data.name or nil if pf then n = n + 1 chunks[n] = pf .. ":" return chunks, "parser function", sub(name, colon + 1) end break end n = n + 1 chunks[n] = mgw_data.name .. ":" start, p = colon + 1, priority colon = find(name, ":", start, true) end if start > 1 then name = sub(name, start) end name = php_trim(name) -- Parser variables can only take SUBST:/SAFESUBST: as modifiers. if not has_args and p <= 1 then local mgw_data = retrieve_magic_word_data(name) local pv = mgw_data and mgw_data.parser_variable and mgw_data.name or nil if pv then n = n + 1 chunks[n] = pv return chunks, "parser variable" end end -- Get the template title with the custom new_title() function in -- [[Module:title/newTitle]], with `allowOnlyFragment` set to false -- (e.g. "{{#foo}}" is invalid) and `allowRelative` set to true, for -- relative links for namespaces with subpages (e.g. "{{/foo}}"). local title = new_title(name, 10, false, true) if not (title and not title.isExternal) then return nil end if force_transclusion ~= "no_redirect" then -- Resolve any redirects. If the redirect target is an interwiki link, -- the template won't fail, but the redirect does not get resolved (i.e. -- the redirect page itself gets transcluded, so the template name -- should not be normalized to the target). local redirect = redirect_target(title, force_transclusion) if redirect and not redirect.isExternal then title = redirect end end -- If `fragment` is not true, unset it from the title object to prevent -- it from being included by get_template_invocation_name. if not fragment then title.fragment = "" end chunks[n + 1] = get_template_invocation_name(title) return chunks, "template" end -- Note: `force_transclusion` avoids incrementing the expensive parser function count by forcing transclusion -- instead. This should only be used when there is a real risk that the expensive parser function limit of -- 500 will be hit. If `force_transclusion` has the value "no_redirect", redirect checking is turned off -- entirely. This should only be used in very limited circumstances when it is otherwise impossible to avoid -- hitting the expensive parser limit and we are willing to handle the possible redirects ourselves. local function process_name(self, frame_args, force_transclusion) local name = expand(self[1], frame_args) local has_args, norm = #self > 1 if not has_args then norm = parser_variables[name] if norm then return norm, "parser variable" end end norm = templates[name] if norm then local pf_arg1 = parser_functions[name] return norm, pf_arg1 and "parser function" or "template", pf_arg1 elseif norm == false then return nil end local chunks, subclass, pf_arg1 = parse_template_name(name, has_args, nil, force_transclusion) -- Fail if invalid. if not chunks then templates[name] = false return nil end local chunk1 = chunks[1] -- Fail on SUBST:. if chunk1 == "SUBST:" then templates[name] = false return nil -- Any modifiers are ignored. elseif subclass == "parser function" then local pf = chunks[#chunks] templates[name] = pf parser_functions[name] = pf_arg1 return pf, "parser function", pf_arg1 end -- Ignore SAFESUBST:, and treat MSGNW: as a parser function with the pagename as its first argument (ignoring any RAW: that comes after). if chunks[chunk1 == "SAFESUBST:" and 2 or 1] == "MSGNW:" then pf_arg1 = chunks[#chunks] local pf = "MSGNW:" templates[name] = pf parser_functions[name] = pf_arg1 return pf, "parser function", pf_arg1 end -- Ignore any remaining modifiers, as they've done their job. local output = chunks[#chunks] if subclass == "parser variable" then parser_variables[name] = output else templates[name] = output end return output, subclass end function Template:get_name(frame_args, force_transclusion) -- Only return the first return value. return (process_name(self, frame_args, force_transclusion)) end function Template:get_arguments(frame_args) local name, subclass, pf_arg1 = process_name(self, frame_args) if name == nil then return nil elseif subclass == "parser variable" then return {} end local template_args = {} if subclass == "parser function" then template_args[1] = pf_arg1 for i = 2, #self do template_args[i] = expand(self[i], frame_args) -- Not trimmed. end return template_args end local implicit = 0 for i = 2, #self do local arg = self[i] if class_else_type(arg) == "argument" then template_args[scribunto_parameter_key(expand(arg[1], frame_args))] = php_trim((expand(arg[2], frame_args))) else implicit = implicit + 1 template_args[implicit] = expand(arg, frame_args) -- Not trimmed. end end return template_args end -- BIG TODO: manual template expansion. function Template:expand(frame_args) local name, subclass, pf_arg1 = process_name(self, frame_args) if name == nil then local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return "{{" .. concat(output, "|") .. "}}" elseif subclass == "parser variable" then return (frame or get_frame()):preprocess("{{" .. name .. "}}") elseif subclass == "parser function" then local f = frame or get_frame() if frame_args ~= nil then local success, new_f = pcall(f.newChild, f, {args = frame_args}) if success then f = new_f end end return f:preprocess(tostring(self)) end local output = {} for i = 1, #self do output[i] = expand(self[i], frame_args) end return (frame or get_frame()):preprocess("{{" .. concat(output, "|") .. "}}") end end local Tag = Node:new_class("tag") function Tag:__tostring() local open_tag, attributes, n = {"<", self.name}, self:get_attributes(), 2 for attr, value in next, attributes do n = n + 1 open_tag[n] = " " .. php_htmlspecialchars(attr) .. "=\"" .. php_htmlspecialchars(value, "compat") .. "\"" end if self.self_closing then return concat(open_tag) .. "/>" end return concat(open_tag) .. ">" .. concat(self) .. "</" .. self.name .. ">" end do local valid_attribute_name local function get_valid_attribute_name() valid_attribute_name, get_valid_attribute_name = (data or get_data()).valid_attribute_name, nil return valid_attribute_name end function Tag:get_attributes() local raw = self.attributes if not raw then self.attributes = {} return self.attributes elseif type(raw) == "table" then return raw end if sub(raw, -1) == "/" then raw = sub(raw, 1, -2) end local attributes, head = {}, 1 -- Semi-manual implementation of the native regex. while true do local name, loc = match(raw, "([^\t\n\f\r />][^\t\n\f\r /=>]*)()", head) if not name then break end head = loc local value loc = match(raw, "^[\t\n\f\r ]*=[\t\n\f\r ]*()", head) if loc then head = loc -- Either "", '' or the value ends on a space/at the end. Missing -- end quotes are repaired by closing the value at the end. value, loc = match(raw, "^\"([^\"]*)\"?()", head) if not value then value, loc = match(raw, "^'([^']*)'?()", head) if not value then value, loc = match(raw, "^([^\t\n\f\r ]*)()", head) end end head = loc end -- valid_attribute_name is a pattern matching a valid attribute name. -- Defined in the data due to its length - see there for more info. if umatch(name, valid_attribute_name or get_valid_attribute_name()) then -- Sanitizer applies PHP strtolower (ASCII-only). attributes[lower(name)] = value and decode_entities( php_trim((gsub(value, "[\t\n\r ]+", " "))) ) or "" end end self.attributes = attributes return attributes end end function Tag:expand() return (frame or get_frame()):preprocess(tostring(self)) end local Heading = Node:new_class("heading") function Heading:new(this) if #this > 1 then local success, str = pcall(concat, this) if success then return new_node(self, { str, level = this.level, section = this.section, index = this.index }) end end return new_node(self, this) end do local node_tostring = Node.__tostring function Heading:__tostring() local eq = rep("=", self.level) return eq .. node_tostring(self) .. eq end end do local expand_node = Node.expand -- Expanded heading names can contain "\n" (e.g. inside nowiki tags), which -- causes any heading containing them to fail. However, in such cases, the -- native parser still treats it as a heading for the purpose of section -- numbers. local function validate_name(self, frame_args) local name = expand_node(self, frame_args) if find(name, "\n", nil, true) then return nil end return name end function Heading:get_name(frame_args) local name = validate_name(self, frame_args) return name ~= nil and php_trim(name) or nil end -- FIXME: account for anchor disambiguation. function Heading:get_anchor(frame_args) local name = validate_name(self, frame_args) return name ~= nil and decode_entities(anchor_encode(name)) or nil end function Heading:expand(frame_args) local eq = rep("=", self.level) return eq .. expand_node(self, frame_args) .. eq end end ------------------------------------------------------------------------------------ -- -- Parser -- ------------------------------------------------------------------------------------ local Parser = m_parser.string_parser() -- Template or parameter. -- Parsed by matching the opening braces innermost-to-outermost (ignoring lone closing braces). Parameters {{{ }}} take priority over templates {{ }} where possible, but a double closing brace will always result in a closure, even if there are 3+ opening braces. -- For example, "{{{{foo}}}}" (4) is parsed as a parameter enclosed by single braces, and "{{{{{foo}}}}}" (5) is a parameter inside a template. However, "{{{{{foo }} }}}" is a template inside a parameter, due to "}}" forcing the closure of the inner node. do -- Handlers. local handle_name local handle_argument local handle_value local function do_template_or_parameter(self, inner_node) self:push_sublayer(handle_name) self:set_pattern("[\n<[{|}]") -- If a node has already been parsed, nest it at the start of the new -- outer node (e.g. when parsing"{{{{foo}}bar}}", the template "{{foo}}" -- is parsed first, since it's the innermost, and becomes the first -- node of the outer template. if inner_node then self:emit(inner_node) end end local function pipe(self) self:emit(Wikitext:new(self:pop_sublayer())) self:push_sublayer(handle_argument) self:set_pattern("[\n<=[{|}]") end local function rbrace(self, this) if self:read(1) == "}" then self:emit(Wikitext:new(self:pop_sublayer())) return self:pop() end self:emit(this) end function handle_name(self, ...) handle_name = self:switch(handle_name, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = pipe, ["}"] = rbrace, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_name(self, ...) end function handle_argument(self, ...) handle_argument = self:switch(handle_argument, { ["\n"] = function(self, this) return self:heading_block(this, "==") end, ["<"] = Parser.tag, ["="] = function(self) local key = self:pop_sublayer() self:push_sublayer(handle_value) self:set_pattern("[\n<[{|}]") self.current_layer._parse_data.key = key end, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = pipe, ["}"] = rbrace, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_argument(self, ...) end function handle_value(self, ...) handle_value = self:switch(handle_value, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["|"] = function(self) self:emit(Argument:new(self:pop_sublayer())) self:push_sublayer(handle_argument) self:set_pattern("[\n<=[{|}]") end, ["}"] = function(self, this) if self:read(1) == "}" then self:emit(Argument:new(self:pop_sublayer())) return self:pop() end self:emit(this) end, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_value(self, ...) end function Parser:template_or_parameter() local text, head, node_to_emit, failed = self.text, self.head -- Comments/tags interrupt the brace count. local braces = match(text, "^{+()", head) - head self:advance(braces) while true do local success, node = self:try(do_template_or_parameter, node_to_emit) -- Fail means no "}}" or "}}}" was found, so emit any remaining -- unmatched opening braces before any templates/parameters that -- were found. if not success then self:emit(rep("{", braces)) failed = true break -- If there are 3+ opening and closing braces, it's a parameter. elseif braces >= 3 and self:read(2) == "}" then self:advance(3) braces = braces - 3 node = Parameter:new(node) -- Otherwise, it's a template. else self:advance(2) braces = braces - 2 node = Template:new(node) end local index = head + braces node.index = index node.raw = sub(text, index, self.head - 1) node_to_emit = node -- Terminate once not enough braces remain for further matches. if braces == 0 then break -- Emit any stray opening brace before any matched nodes. elseif braces == 1 then self:emit("{") break end end if node_to_emit then self:emit(node_to_emit) end return braces, failed end end -- Tag. do local end_tags local function get_end_tags() end_tags, get_end_tags = (data or get_data()).end_tags, nil return end_tags end -- Handlers. local handle_start local handle_tag local function do_tag(self) local layer = self.current_layer layer._parse_data.handler, layer.index = handle_start, self.head self:set_pattern("[%s/>]") self:advance() end local function is_ignored_tag(self, this) if self.transcluded then return this == "includeonly" end return this == "noinclude" or this == "onlyinclude" end local function ignored_tag(self, text, head) local loc = find(text, ">", head, true) if not loc then return self:fail_route() end self:jump(loc) local tag = self:pop() tag.ignored = true return tag end function handle_start(self, this) if this == "/" then local text, head = self.text, self.head + 1 local this = match(text, "^[^%s/>]+", head) if this and is_ignored_tag(self, lower(this)) then head = head + #this if not match(text, "^/[^>]", head) then return ignored_tag(self, text, head) end end return self:fail_route() elseif this == "" then return self:fail_route() end -- Tags are only case-insensitive with ASCII characters. local raw_name = this this = lower(this) local end_tag_pattern = (end_tags or get_end_tags())[this] if not end_tag_pattern then -- Validity check. return self:fail_route() end local layer = self.current_layer local pdata = layer._parse_data local text, head = self.text, self.head + pdata.step if match(text, "^/[^>]", head) then return self:fail_route() elseif is_ignored_tag(self, this) then return ignored_tag(self, text, head) -- If an onlyinclude tag is not ignored (and cannot be active since it -- would have triggered special handling earlier), it must be plaintext. elseif this == "onlyinclude" then return self:fail_route() elseif this == "noinclude" or this == "includeonly" then layer.ignored = true -- Ignored block. layer.raw_name = raw_name end layer.name, pdata.handler, pdata.end_tag_pattern = this, handle_tag, end_tag_pattern self:set_pattern(">") end function handle_tag(self, this) if this == "" then return self:fail_route() end local layer = self.current_layer if this ~= ">" then layer.attributes = this return elseif self:read(-1) == "/" then layer.self_closing = true return self:pop() end local text, head = self.text, self.head + 1 local loc1, loc2 = find(text, layer._parse_data.end_tag_pattern, head) if loc1 then if loc1 > head then self:emit(sub(text, head, loc1 - 1)) end self:jump(loc2) return self:pop() -- noinclude and includeonly will tolerate having no closing tag, but -- only if given in lowercase. This is due to a preprocessor bug, as -- it uses a regex with the /i (case-insensitive) flag to check for -- end tags, but a simple array lookup with lowercase tag names when -- looking up which tags should tolerate no closing tag (exact match -- only, so case-sensitive). elseif layer.ignored then local raw_name = layer.raw_name if raw_name == "noinclude" or raw_name == "includeonly" then self:jump(#text) return self:pop() end end return self:fail_route() end function Parser:tag() -- HTML comment. if self:read(1, 3) == "!--" then local text = self.text self:jump(select(2, find(text, "-->", self.head + 4, true)) or #text) -- onlyinclude tags (which must be lowercase with no whitespace). elseif self.onlyinclude and self:read(1, 13) == "/onlyinclude>" then local text = self.text self:jump(select(2, find(text, "<onlyinclude>", self.head + 14, true)) or #text) else local success, tag = self:try(do_tag) if not success then self:emit("<") elseif not tag.ignored then self:emit(Tag:new(tag)) end end end end -- Heading. -- The preparser assigns each heading a number, which is used for things like section edit links. The preparser will only do this for heading blocks which aren't nested inside templates, parameters and parser tags. In some cases (e.g. when template blocks contain untrimmed newlines), a preparsed heading may not be treated as a heading in the final output. That does not affect the preparser, however, which will always count sections based on the preparser heading count, since it can't know what a template's final output will be. do -- Handlers. local handle_start local handle_body local handle_possible_end local function do_heading(self) local layer, head = self.current_layer, self.head layer._parse_data.handler, layer.index = handle_start, head self:set_pattern("[\t\n ]") -- Comments/tags interrupt the equals count. local eq = match(self.text, "^=+()", head) - head layer.level = eq self:advance(eq) end local function do_heading_possible_end(self) self.current_layer._parse_data.handler = handle_possible_end self:set_pattern("[\n<]") end function handle_start(self, ...) -- ===== is "=" as an L2; ======== is "==" as an L3 etc. local function newline(self) local layer = self.current_layer local eq = layer.level if eq <= 2 then return self:fail_route() end -- Calculate which equals signs determine the heading level. local level_eq = eq - (2 - eq % 2) level_eq = level_eq > 12 and 12 or level_eq -- Emit the excess. self:emit(rep("=", eq - level_eq)) layer.level = level_eq / 2 return self:pop() end local function whitespace(self) local success, possible_end = self:try(do_heading_possible_end) if success then self:emit(Wikitext:new(possible_end)) self.current_layer._parse_data.handler = handle_body self:set_pattern("[\n<=[{]") return self:consume() end return newline(self) end handle_start = self:switch(handle_start, { ["\t"] = whitespace, ["\n"] = newline, [" "] = whitespace, [""] = newline, [false] = function(self) -- Emit any excess = signs once we know it's a conventional heading. Up till now, we couldn't know if the heading is just a string of = signs (e.g. ========), so it wasn't guaranteed that the heading text starts after the 6th. local layer = self.current_layer local eq = layer.level if eq > 6 then self:emit(1, rep("=", eq - 6)) layer.level = 6 end layer._parse_data.handler = handle_body self:set_pattern("[\n<=[{]") return self:consume() end }) return handle_start(self, ...) end function handle_body(self, ...) handle_body = self:switch(handle_body, { ["\n"] = Parser.fail_route, ["<"] = Parser.tag, ["="] = function(self) -- Comments/tags interrupt the equals count. local eq = match(self.text, "^=+", self.head) local eq_len = #eq self:advance(eq_len) local success, possible_end = self:try(do_heading_possible_end) if success then self:emit(eq) self:emit(Wikitext:new(possible_end)) return self:consume() end local layer = self.current_layer local level = layer.level if eq_len > level then self:emit(rep("=", eq_len - level)) elseif level > eq_len then layer.level = eq_len self:emit(1, rep("=", level - eq_len)) end return self:pop() end, ["["] = Parser.wikilink_block, ["{"] = function(self, this) return self:braces(this, true) end, [""] = Parser.fail_route, [false] = Parser.emit }) return handle_body(self, ...) end function handle_possible_end(self, ...) handle_possible_end = self:switch(handle_possible_end, { ["\n"] = Parser.fail_route, ["<"] = function(self) if self:read(1, 3) ~= "!--" then return self:pop() end local head = select(2, find(self.text, "-->", self.head + 4, true)) if not head then return self:pop() end self:jump(head) end, [""] = Parser.fail_route, [false] = function(self, this) if not match(this, "^[\t ]+()$") then return self:pop() end self:emit(this) end }) return handle_possible_end(self, ...) end function Parser:heading() local success, heading = self:try(do_heading) if success then local section = self.section + 1 heading.section = section self.section = section self:emit(Heading:new(heading)) return self:consume() else self:emit("=") end end end ------------------------------------------------------------------------------------ -- -- Block handlers -- ------------------------------------------------------------------------------------ -- Block handlers. -- These are blocks which can affect template/parameter parsing, since they're also parsed by Parsoid at the same time (even though they aren't processed until later). -- All blocks (including templates/parameters) can nest inside each other, but an inner block must be closed before the outer block which contains it. This is why, for example, the wikitext "{{template| [[ }}" will result in an unprocessed template, since the inner "[[" is treated as the opening of a wikilink block, which prevents "}}" from being treated as the closure of the template block. On the other hand, "{{template| [[ ]] }}" will process correctly, since the wikilink block is closed before the template closure. It makes no difference whether the block will be treated as valid or not when it's processed later on, so "{{template| [[ }} ]] }}" would also work, even though "[[ }} ]]" is not a valid wikilink. -- Note that nesting also affects pipes and equals signs, in addition to block closures. -- These blocks can be nested to any degree, so "{{template| [[ [[ [[ ]] }}" will not work, since only one of the three wikilink blocks has been closed. On the other hand, "{{template| [[ [[ [[ ]] ]] ]] }}" will work. -- All blocks are implicitly closed by the end of the text, since their validity is irrelevant at this stage. -- Language conversion block. -- Opens with "-{" and closes with "}-". However, templates/parameters take priority, so "-{{" is parsed as "-" followed by the opening of a template/parameter block (depending on what comes after). -- Note: Language conversion blocks aren't actually enabled on the English Wiktionary, but Parsoid still parses them at this stage, so they can affect the closure of outer blocks: e.g. "[[ -{ ]]" is not a valid wikilink block, since the "]]" falls inside the new language conversion block. do --Handler. local handle_language_conversion_block local function do_language_conversion_block(self) self.current_layer._parse_data.handler = handle_language_conversion_block self:set_pattern("[\n<[{}]") end function handle_language_conversion_block(self, ...) handle_language_conversion_block = self:switch(handle_language_conversion_block, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, ["}"] = function(self, this) if self:read(1) == "-" then self:emit("}-") self:advance() return self:pop() end self:emit(this) end, [""] = Parser.pop, [false] = Parser.emit }) return handle_language_conversion_block(self, ...) end function Parser:braces(this, fail_on_unclosed_braces) local language_conversion_block = self:read(-1) == "-" if self:read(1) == "{" then local braces, failed = self:template_or_parameter() -- Headings will fail if they contain an unclosed brace block. if failed and fail_on_unclosed_braces then return self:fail_route() -- Language conversion blocks cannot begin "-{{", but can begin -- "-{{{" iff parsed as "-{" + "{{". elseif not (language_conversion_block and braces == 1) then return self:consume() end else self:emit(this) if not language_conversion_block then return end self:advance() end self:emit(Wikitext:new(self:get(do_language_conversion_block))) end end --[==[ Headings Opens with "\n=" (or "=" at the start of the text), and closes with "\n" or the end of the text. Note that it doesn't matter whether the heading will fail to process due to a premature newline (e.g. if there are no closing signs), so at this stage the only thing that matters for closure is the newline or end of text. Note: Heading blocks are only parsed like this if they occur inside a template, since they do not iterate the preparser's heading count (i.e. they aren't proper headings). Note 2: if directly inside a template argument with no previous equals signs, a newline followed by a single equals sign is parsed as an argument equals sign, not the opening of a new L1 heading block. This does not apply to any other heading levels. As such, {{template|key\n=}}, {{template|key\n=value}} or even {{template|\n=}} will successfully close, but {{template|key\n==}}, {{template|key=value\n=more value}}, {{template\n=}} etc. will not, since in the latter cases the "}}" would fall inside the new heading block. ]==] do --Handler. local handle_heading_block local function do_heading_block(self) self.current_layer._parse_data.handler = handle_heading_block self:set_pattern("[\n<[{]") end function handle_heading_block(self, ...) handle_heading_block = self:switch(handle_heading_block, { ["\n"] = function(self) self:newline() return self:pop() end, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["{"] = Parser.braces, [""] = Parser.pop, [false] = Parser.emit }) return handle_heading_block(self, ...) end function Parser:heading_block(this, nxt) self:newline() this = this .. (nxt or "=") local loc = #this - 1 while self:read(0, loc) == this do self:advance() self:emit(Wikitext:new(self:get(do_heading_block))) end end end -- Wikilink block. -- Opens with "[[" and closes with "]]". do -- Handler. local handle_wikilink_block local function do_wikilink_block(self) self.current_layer._parse_data.handler = handle_wikilink_block self:set_pattern("[\n<[%]{]") end function handle_wikilink_block(self, ...) handle_wikilink_block = self:switch(handle_wikilink_block, { ["\n"] = Parser.heading_block, ["<"] = Parser.tag, ["["] = Parser.wikilink_block, ["]"] = function(self, this) if self:read(1) == "]" then self:emit("]]") self:advance() return self:pop() end self:emit(this) end, ["{"] = Parser.braces, [""] = Parser.pop, [false] = Parser.emit }) return handle_wikilink_block(self, ...) end function Parser:wikilink_block() if self:read(1) == "[" then self:emit("[[") self:advance(2) self:emit(Wikitext:new(self:get(do_wikilink_block))) else self:emit("[") end end end -- Lines which only contain comments, " " and "\t" are eaten, so long as -- they're bookended by "\n" (i.e. not the first or last line). function Parser:newline() local text, head = self.text, self.head while true do repeat local loc = match(text, "^[\t ]*<!%-%-()", head + 1) if not loc then break end loc = select(2, find(text, "-->", loc, true)) head = loc or head until not loc -- Fail if no comments found. if head == self.head then break end head = match(text, "^[\t ]*()\n", head + 1) if not head then break end self:jump(head) end self:emit("\n") end do -- Handlers. local handle_start local main_handler -- If `transcluded` is true, then the text is checked for a pair of -- onlyinclude tags. If these are found (even if they're in the wrong -- order), then the start of the page is treated as though it is preceded -- by a closing onlyinclude tag. -- Note 1: unlike other parser extension tags, onlyinclude tags are case- -- sensitive and cannot contain whitespace. -- Note 2: onlyinclude tags *can* be implicitly closed by the end of the -- text, but the hard requirement above means this can only happen if -- either the tags are in the wrong order or there are multiple onlyinclude -- blocks. local function do_parse(self, transcluded) self.current_layer._parse_data.handler = handle_start self:set_pattern(".") self.section = 0 if not transcluded then return end self.transcluded = true local text = self.text if find(text, "</onlyinclude>", nil, true) then local head = find(text, "<onlyinclude>", nil, true) if head then self.onlyinclude = true self:jump(head + 13) end end end -- If the first character is "=", try parsing it as a heading. function handle_start(self, this) self.current_layer._parse_data.handler = main_handler self:set_pattern("[\n<{]") if this == "=" then return self:heading() end return self:consume() end function main_handler(self, ...) main_handler = self:switch(main_handler, { ["\n"] = function(self) self:newline() if self:read(1) == "=" then self:advance() return self:heading() end end, ["<"] = Parser.tag, ["{"] = function(self, this) if self:read(1) == "{" then self:template_or_parameter() return self:consume() end self:emit(this) end, [""] = Parser.pop, [false] = Parser.emit }) return main_handler(self, ...) end function export.parse(text, transcluded) local text_type = type(text) return (select(2, Parser:parse{ text = text_type == "string" and text or text_type == "number" and tostring(text) or error("bad argument #1 (string expected, got " .. text_type .. ")"), node = {Wikitext, true}, route = {do_parse, transcluded} })) end parse = export.parse end function export.find_templates(text, not_transcluded) return parse(text, not not_transcluded):iterate_nodes("template") end do local link_parameter_1, link_parameter_2 local function get_link_parameter_1() link_parameter_1, get_link_parameter_1 = (data or get_data()).template_link_param_1, nil return link_parameter_1 end local function get_link_parameter_2() link_parameter_2, get_link_parameter_2 = (data or get_data()).template_link_param_2, nil return link_parameter_2 end -- Generate a link. If the target title doesn't have a fragment, use "#top" -- (which is an implicit anchor at the top of every page), as this ensures -- self-links still display as links, since bold display is distracting and -- unintuitive for template links. local function link_page(title, display) local fragment = title.fragment if fragment == "" then fragment = "top" end return format( "[[:%s|%s]]", encode_uri(title.prefixedText .. "#" .. fragment, "WIKI"), display ) end -- pf_arg1 or pf_arg2 may need to be linked if a given parser function -- treats them as a pagename. If a key exists in `namespace`, the value is -- the namespace for the page: if not 0, then the namespace prefix will -- always be added to the input (e.g. {{#invoke:}} can only target the -- Module: namespace, so inputting "Template:foo" gives -- "Module:Template:foo", and "Module:foo" gives "Module:Module:foo"). -- However, this isn't possible with mainspace (namespace 0), so prefixes -- are respected. make_title() handles all of this automatically. local function finalize_arg(pagename, namespace) if namespace == nil then return pagename end local title = make_title(namespace, pagename) return title and not title.isExternal and link_page(title, pagename) or pagename end local function render_title(name, args) -- parse_template_name returns a table of transclusion modifiers plus -- the normalized template/magic word name, which will be used as link -- targets. The third return value pf_arg1 is the first argument of a -- a parser function, which comes after the colon (e.g. "foo" in -- "{{#IF:foo|bar|baz}}"). This means args[1] (i.e. the first argument -- that comes after a pipe is actually argument 2, and so on. Note: the -- second parameter of parse_template_name checks if there are any -- arguments, since parser variables cannot take arguments (e.g. -- {{CURRENTYEAR}} is a parser variable, but {{CURRENTYEAR|foo}} -- transcludes "Template:CURRENTYEAR"). In such cases, the returned -- table explicitly includes the "Template:" prefix in the template -- name. The third parameter instructs it to retain any fragment in the -- template name in the returned table, if present. local chunks, subclass, pf_arg1 = parse_template_name( name, args and pairs(args)(args) ~= nil, true ) if chunks == nil then return name, args end local chunks_len = #chunks -- Additionally, generate the corresponding table `rawchunks`, which -- is a list of colon-separated chunks in the raw input. This is used -- to retrieve the display forms for each chunk. local rawchunks = split(name, ":") for i = 1, chunks_len - 1 do chunks[i] = format( "[[%s|%s]]", encode_uri((magic_words or get_magic_words())[sub(chunks[i], 1, -2)].transclusion_modifier, "WIKI"), rawchunks[i] ) end local chunk = chunks[chunks_len] -- If it's a template, return a link to it with link_page, concatenating -- the remaining chunks in `rawchunks` to form the display text. -- Use new_title with the default namespace 10 (Template:) to generate -- a target title, which is the same setting used for retrieving -- templates (including those in other namespaces, as prefixes override -- the default). if subclass == "template" then chunks[chunks_len] = link_page( new_title(chunk, 10), concat(rawchunks, "&#58;", chunks_len) -- : ) return concat(chunks, "&#58;"), args -- : elseif subclass == "parser variable" then chunks[chunks_len] = format( "[[%s|%s]]", encode_uri((magic_words or get_magic_words())[chunk].parser_variable, "WIKI"), rawchunks[chunks_len] ) return concat(chunks, "&#58;"), args -- : end -- Otherwise, it must be a parser function. local mgw_data = (magic_words or get_magic_words())[sub(chunk, 1, -2)] local link = mgw_data.parser_function or mgw_data.transclusion_modifier local pf_arg2 = args and args[1] or nil -- Some magic words have different links, depending on whether argument -- 2 is specified (e.g. "baz" in {{foo:bar|baz}}). if type(link) == "table" then link = pf_arg2 and link[2] or link[1] end chunks[chunks_len] = format( "[[%s|%s]]", encode_uri(link, "WIKI"), rawchunks[chunks_len] ) -- #TAG: has special handling, because documentation links for parser -- extension tags come from [[Module:data/parser extension tags]]. if chunk == "#TAG:" then -- Tags are only case-insensitive with ASCII characters. local tag = (parser_extension_tags or get_parser_extension_tags())[lower(php_trim(pf_arg1))] if tag then pf_arg1 = format( "[[%s|%s]]", encode_uri(tag, "WIKI"), pf_arg1 ) end -- Otherwise, finalize pf_arg1 and add it to `chunks`. else pf_arg1 = finalize_arg(pf_arg1, (link_parameter_1 or get_link_parameter_1())[chunk]) end chunks[chunks_len + 1] = pf_arg1 -- Finalize pf_arg2 (if applicable), then return. if pf_arg2 then args = shallow_copy(args) -- Avoid destructively modifying args. args[1] = finalize_arg(pf_arg2, (link_parameter_2 or get_link_parameter_2())[chunk]) end return concat(chunks, "&#58;"), args -- : end function export.buildTemplate(title, args) local output = {title} if not args then return output end -- Iterate over all numbered parameters in order, followed by any -- remaining parameters in codepoint order. Implicit parameters are -- used wherever possible, even if explicit numbers are interpolated -- between them (e.g. 0 would go before any implicit parameters, and -- 2.5 between 2 and 3). -- TODO: handle "=" and "|" in params/values. local implicit for k, v in sorted_pairs(args) do if type(k) == "number" and k >= 1 and k % 1 == 0 then if implicit == nil then implicit = table_len(args) end insert(output, k <= implicit and v or k .. "=" .. v) else insert(output, k .. "=" .. v) end end return output end build_template = export.buildTemplate function export.templateLink(title, args, no_link) if not no_link then title, args = render_title(title, args) end local output = build_template(title, args) for i = 1, #output do output[i] = encode_entities(output[i], "={}", true, true) end return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&#123;&#123;" .. concat(output, "&#124;") .. "&#125;&#125;") -- {{ | }} ) end end do function export.find_parameters(text, not_transcluded) return parse(text, not not_transcluded):iterate_nodes("parameter") end function export.displayParameter(name, default) return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&#123;&#123;&#123;" .. concat({name, default}, "&#124;") .. "&#125;&#125;&#125;") -- {{{ | }}} ) end end do local function check_level(level) if type(level) ~= "number" then error("Heading levels must be numbers.") elseif level < 1 or level > 6 or level % 1 ~= 0 then error("Heading levels must be integers between 1 and 6.") end return level end -- FIXME: should headings which contain "\n" be returned? This may depend -- on variable factors, like template expansion. They iterate the heading -- count number, but fail on rendering. However, in some cases a different -- heading might still be rendered due to intermediate equals signs; it -- may even be of a different heading level: e.g., this is parsed as an -- L2 heading with a newline (due to the wikilink block), but renders as the -- L1 heading "=foo[[". Section edit links are sometimes (but not always) -- present in such cases. -- ==[[= -- ]]== -- TODO: section numbers for edit links seem to also include headings -- nested inside templates and parameters (but apparently not those in -- parser extension tags - need to test this more). If we ever want to add -- section edit links manually, this will need to be accounted for. function export.find_headings(text, i, j) local parsed = parse(text) if i == nil and j == nil then return parse(text):iterate_nodes("heading") end i = i and check_level(i) or 1 j = j and check_level(j) or 6 return parsed:iterate(function(v) if class_else_type(v) == "heading" then local level = v.level return level >= i and level <= j end end) end end do local function make_tag(tag) return tostring(html_create("code") :css("white-space", "pre-wrap") :wikitext("&lt;" .. tag .. "&gt;") ) end -- Note: invalid tags are returned without links. function export.wikitagLink(tag) -- ">" can't appear in tags (including attributes) since the parser -- unconditionally treats ">" as the end of a tag. if find(tag, ">", nil, true) then return make_tag(tag) end -- Tags must start "<tagname..." or "</tagname...", with no whitespace -- after "<" or "</". local slash, tagname, remainder = match(tag, "^(/?)([^/%s]+)(.*)$") if not tagname then return make_tag(tag) end -- Tags are only case-insensitive with ASCII characters. local link = lower(tagname) if ( -- onlyinclude tags must be lowercase and are whitespace intolerant. link == "onlyinclude" and (link ~= tagname or remainder ~= "") or -- Closing wikitags (except onlyinclude) can only have whitespace -- after the tag name. slash == "/" and not match(remainder, "^%s*()$") or -- Tagnames cannot be followed immediately by "/", unless it comes -- at the end (e.g. "<nowiki/>", but not "<nowiki/ >"). remainder ~= "/" and sub(remainder, 1, 1) == "/" ) then -- Output with no link. return make_tag(tag) end -- Partial transclusion tags aren't in the table of parser extension -- tags. if link == "noinclude" or link == "includeonly" or link == "onlyinclude" then link = "mw:Transclusion#Partial transclusion" else link = (parser_extension_tags or get_parser_extension_tags())[link] end if link then tag = gsub(tag, pattern_escape(tagname), "[[" .. replacement_escape(encode_uri(link, "WIKI")) .. "|%0]]", 1) end return make_tag(tag) end end -- For convenience. export.class_else_type = class_else_type return export g7883esvq9rqr796jeq8jsmk6y4r8t1 Module:template parser/templates 828 119941 237275 195875 2025-04-24T12:26:46Z en>SurjectionBot 0 (bot) slight optimization to 5.2 compat: prefer unpack to table.unpack 237275 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local m_template_parser = require("Module:template parser") local display_parameter = m_template_parser.displayParameter local process_params = require("Module:parameters").process local template_link = m_template_parser.templateLink local unpack = unpack or table.unpack -- Lua 5.2 compatibility local wikitag_link = m_template_parser.wikitagLink local function get_offset_template_args(frame) -- Process parameters with the return_unknown flag set. `title` contains -- the title at key 1; everything else goes in `args`. local title, args = process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true} }, true) title = title[1] -- Shift all implicit arguments down by 1. Non-sequential numbered -- parameters don't get shifted; however, this offset means that if the -- input contains (e.g.) {{tl|l|en|3=alt}}, representing {{l|en|3=alt}}, -- the parameter at 3= is instead treated as sequential by this module, -- because it's indistinguishable from {{tl|l|en|alt}}, which represents -- {{l|en|alt}}. On the other hand, {{tl|l|en|4=tr}} is handled correctly, -- because there's still a gap before 4=. -- Unfortunately, there's no way to know the original input, so -- there's no clear way to fix this; the only difference is that explicit -- parameters have whitespace trimmed from their values while implicit ones -- don't, but we can't assume that every input with no whitespace was given -- with explicit numbering. -- This also causes bigger problems for any parser functions which treat -- their inputs as arrays, or in some other nonstandard way (e.g. -- {{#IF:foo|bar=baz|qux}} treats "bar=baz" as parameter 1). Without -- knowing the original input, these can't be reconstructed accurately. -- The way around this is to use <nowiki> tags in the input, since this -- module won't unstrip them by design. local i = 2 repeat local arg = args[i] args[i - 1] = arg i = i + 1 until arg == nil return title, args end function export.template_link_t(frame) local iargs = process_params(frame.args, { ["annotate"] = true, ["nolink"] = {type = "boolean"}, }) -- iargs.annotate allows a template to specify the title, so the input -- arguments will match the output. local title = iargs.annotate if title then return template_link(title, frame:getParent().args, iargs.nolink) end -- Otherwise, get template arguments offset by 1. local args title, args = get_offset_template_args(frame) return template_link(title, args, iargs.nolink) end function export.template_demo_t(frame) local title, args = get_offset_template_args(frame) return template_link(title, args) .. " ⇒<br style=\"line-height: 200%;\" />" .. frame:expandTemplate{title = title, args = args} end function export.parameter_t(frame) return display_parameter(unpack(process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true}, [2] = {allow_empty = true, no_trim = true}, }))) end function export.wikitag_link_t(frame) return wikitag_link(process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true} })[1]) end return export gmu9dpbh2ydrhfx4p61dfx6c72aig0i 237276 237275 2026-09-11T11:25:05Z Lee 19 [[:en:Module:template_parser/templates]] වෙතින් එක් සංශෝධනයක් 237275 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local m_template_parser = require("Module:template parser") local display_parameter = m_template_parser.displayParameter local process_params = require("Module:parameters").process local template_link = m_template_parser.templateLink local unpack = unpack or table.unpack -- Lua 5.2 compatibility local wikitag_link = m_template_parser.wikitagLink local function get_offset_template_args(frame) -- Process parameters with the return_unknown flag set. `title` contains -- the title at key 1; everything else goes in `args`. local title, args = process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true} }, true) title = title[1] -- Shift all implicit arguments down by 1. Non-sequential numbered -- parameters don't get shifted; however, this offset means that if the -- input contains (e.g.) {{tl|l|en|3=alt}}, representing {{l|en|3=alt}}, -- the parameter at 3= is instead treated as sequential by this module, -- because it's indistinguishable from {{tl|l|en|alt}}, which represents -- {{l|en|alt}}. On the other hand, {{tl|l|en|4=tr}} is handled correctly, -- because there's still a gap before 4=. -- Unfortunately, there's no way to know the original input, so -- there's no clear way to fix this; the only difference is that explicit -- parameters have whitespace trimmed from their values while implicit ones -- don't, but we can't assume that every input with no whitespace was given -- with explicit numbering. -- This also causes bigger problems for any parser functions which treat -- their inputs as arrays, or in some other nonstandard way (e.g. -- {{#IF:foo|bar=baz|qux}} treats "bar=baz" as parameter 1). Without -- knowing the original input, these can't be reconstructed accurately. -- The way around this is to use <nowiki> tags in the input, since this -- module won't unstrip them by design. local i = 2 repeat local arg = args[i] args[i - 1] = arg i = i + 1 until arg == nil return title, args end function export.template_link_t(frame) local iargs = process_params(frame.args, { ["annotate"] = true, ["nolink"] = {type = "boolean"}, }) -- iargs.annotate allows a template to specify the title, so the input -- arguments will match the output. local title = iargs.annotate if title then return template_link(title, frame:getParent().args, iargs.nolink) end -- Otherwise, get template arguments offset by 1. local args title, args = get_offset_template_args(frame) return template_link(title, args, iargs.nolink) end function export.template_demo_t(frame) local title, args = get_offset_template_args(frame) return template_link(title, args) .. " ⇒<br style=\"line-height: 200%;\" />" .. frame:expandTemplate{title = title, args = args} end function export.parameter_t(frame) return display_parameter(unpack(process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true}, [2] = {allow_empty = true, no_trim = true}, }))) end function export.wikitag_link_t(frame) return wikitag_link(process_params(frame:getParent().args, { [1] = {required = true, allow_empty = true, no_trim = true} })[1]) end return export gmu9dpbh2ydrhfx4p61dfx6c72aig0i Module:template parser/templates/documentation 828 119942 237277 182568 2025-01-11T10:40:07Z en>Whatback11 0 Undo revision [[Special:Diff/83571514|83571514]] by [[Special:Contributions/Whatback11|Whatback11]] ([[User talk:Whatback11|talk]]) 182567 wikitext text/x-wiki This module implements {{tl|temp}}, {{tl|paramref}} and {{tl|wikitag}}. {{module cat|-|Internal link,Documentation}} 4i17g7hy0mdn23yr8923pqqdvogalvm 237278 210376 2026-09-11T11:25:27Z Lee 19 [[:en:Module:template_parser/templates/documentation]] වෙතින් එක් සංශෝධනයක් 210376 wikitext text/x-wiki This module implements {{tl|temp}}, {{tl|paramref}} and {{tl|wikitag}}. {{module cat|-|අභ්‍යන්තර සබැඳි,උපදෙස්}} 16qgpl7tpnvb4plujx7453wy8rixsy1 ප්‍රවර්ගය:Japanese-only CJKV Characters 14 121996 237252 188059 2025-04-22T09:23:02Z en>This, that and the other 0 rfd → rfm 237252 wikitext text/x-wiki {{rfm|ja}} This category collects those {{m|ja|国字||[[kokuji]], Japanese-coined characters}} which are used only in Japan. Japanese-coined characters used not only in Japan should instead be found in [[:Category:Japanese-coined CJKV characters used outside Japanese|Japanese-coined CJKV characters used outside Japanese]]. CJKV Characters are the characters of the Chinese writing system but were also formerly used in North Korea and Vietnam and continue in use also in Japan and occasionally South Korea. Some countries invented a few of their own characters which were never used in China. For characters used in China, but simplified to a different form in Japan and in China, see instead [[:Category:CJKV characters simplified differently in Japan and China|CJKV characters simplified differently in Japan and China]]. == See also == * [[:Category:CJKV characters simplified differently in Japan and China]] * [[:Category:Korean-only CJKV Characters]] * [[:Category:Vietnamese Han tu]] [[Category:Japanese-coined CJKV characters]] meruo3s3fqdvj1b5nsk5jx3t7fklwd2 237253 237252 2026-09-11T10:57:56Z Lee 19 [[:en:Category:Japanese-only_CJKV_Characters]] වෙතින් එක් සංශෝධනයක් 237252 wikitext text/x-wiki {{rfm|ja}} This category collects those {{m|ja|国字||[[kokuji]], Japanese-coined characters}} which are used only in Japan. Japanese-coined characters used not only in Japan should instead be found in [[:Category:Japanese-coined CJKV characters used outside Japanese|Japanese-coined CJKV characters used outside Japanese]]. CJKV Characters are the characters of the Chinese writing system but were also formerly used in North Korea and Vietnam and continue in use also in Japan and occasionally South Korea. Some countries invented a few of their own characters which were never used in China. For characters used in China, but simplified to a different form in Japan and in China, see instead [[:Category:CJKV characters simplified differently in Japan and China|CJKV characters simplified differently in Japan and China]]. == See also == * [[:Category:CJKV characters simplified differently in Japan and China]] * [[:Category:Korean-only CJKV Characters]] * [[:Category:Vietnamese Han tu]] [[Category:Japanese-coined CJKV characters]] meruo3s3fqdvj1b5nsk5jx3t7fklwd2 237254 237253 2026-09-11T10:58:30Z Lee 19 237254 wikitext text/x-wiki This category collects those {{m|ja|国字||[[kokuji]], Japanese-coined characters}} which are used only in Japan. Japanese-coined characters used not only in Japan should instead be found in [[:Category:Japanese-coined CJKV characters used outside Japanese|Japanese-coined CJKV characters used outside Japanese]]. CJKV Characters are the characters of the Chinese writing system but were also formerly used in North Korea and Vietnam and continue in use also in Japan and occasionally South Korea. Some countries invented a few of their own characters which were never used in China. For characters used in China, but simplified to a different form in Japan and in China, see instead [[:Category:CJKV characters simplified differently in Japan and China|CJKV characters simplified differently in Japan and China]]. == See also == * [[:Category:CJKV characters simplified differently in Japan and China]] * [[:Category:Korean-only CJKV Characters]] * [[:Category:Vietnamese Han tu]] [[Category:Japanese-coined CJKV characters]] kdio81l5c8unpqjjf9xp2yzc7sm0l0a 乄 0 145035 237255 2025-10-24T18:25:46Z en>AutoDooz 0 Han ref: removed unused param 'ud' 237255 wikitext text/x-wiki {{also|メ}} {{character info}} ==Translingual== ===Han character=== {{Han char|rn=4|rad=丿|as=01|sn=2|four=|canj=KU,XXKU|ids=⿻㇢丶}} ====References==== * {{Han ref|kx=0081.181|dkj=00116|hdz=10049.051|uh=4E44}} ==Japanese== ===Kanji=== {{ja-kanji|grade=uc|rs=丿01}} # {{lb|ja|uncommon}} {{alt form|ja|〆}} ====Usage notes==== * Typically, {{codepoint|〆}} is used instead. See {{pedia|lang=ja|〆#符号位置}} ====Readings==== {{ja-readings |kun=しめ-, して- }} [[Category:Japanese-only CJKV Characters|丿+01]] [[Category:Japanese symbols|しめ]] 02n8try828ftc3psi2slmqck8ujnpr4 237256 237255 2026-09-11T10:59:10Z Lee 19 [[:en:乄]] වෙතින් එක් සංශෝධනයක් 237255 wikitext text/x-wiki {{also|メ}} {{character info}} ==Translingual== ===Han character=== {{Han char|rn=4|rad=丿|as=01|sn=2|four=|canj=KU,XXKU|ids=⿻㇢丶}} ====References==== * {{Han ref|kx=0081.181|dkj=00116|hdz=10049.051|uh=4E44}} ==Japanese== ===Kanji=== {{ja-kanji|grade=uc|rs=丿01}} # {{lb|ja|uncommon}} {{alt form|ja|〆}} ====Usage notes==== * Typically, {{codepoint|〆}} is used instead. See {{pedia|lang=ja|〆#符号位置}} ====Readings==== {{ja-readings |kun=しめ-, して- }} [[Category:Japanese-only CJKV Characters|丿+01]] [[Category:Japanese symbols|しめ]] 02n8try828ftc3psi2slmqck8ujnpr4 සැකිල්ල:codepoint 10 145036 237257 2026-04-15T19:49:50Z en>Surjection 0 Changed protection settings for "[[Template:codepoint]]" ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 237257 wikitext text/x-wiki <includeonly>{{#invoke:Unicode data/templates/codepoint|show}}<templatestyles src="Template:codepoint/style.css" /></includeonly><noinclude>{{documentation}}</noinclude> o5kb8ahk5u31y1ipt23x7f8dmfpmjue 237258 237257 2026-09-11T11:18:19Z Lee 19 [[:en:Template:codepoint]] වෙතින් එක් සංශෝධනයක් 237257 wikitext text/x-wiki <includeonly>{{#invoke:Unicode data/templates/codepoint|show}}<templatestyles src="Template:codepoint/style.css" /></includeonly><noinclude>{{documentation}}</noinclude> o5kb8ahk5u31y1ipt23x7f8dmfpmjue සැකිල්ල:codepoint/documentation 10 145037 237259 2023-04-29T09:32:07Z en>Surjection 0 /* Examples */ 237259 wikitext text/x-wiki {{documentation subpage}} This template generates a textual reference to a Unicode codepoint. Implemented with [[Module:Unicode data/templates/codepoint]]. ==Parameters== ; {{para|1|req=1}} : The codepoint, either given as a single character or in the notation <kbd>U+xxxx</kbd>. ; {{para|display}} : Whether to display the referenced character. Done by default if the codepoint is assigned and represents a printable non-whitespace character. ; {{para|link}} : Whether to display a link to the referenced character. Done by default if the codepoint is assigned and represents a printable character. If the character is displayed, the link will be added to the character, and otherwise to the hexadecimal notation. ; {{para|plain|1}} : Automatically specifies {{para|display|0}}, {{para|link|0}}. ; {{para|html|1}} : Displays a HTML entity representation. ; {{para|noname|1}} : Hides the character name. ==Examples== <code>{{tl|codepoint|U+2010}}</code> :: {{codepoint|U+2010}} <code> {{tl|codepoint|U+2010|display=0}}</code> :: {{codepoint|U+2010|display=0}} <code>{{tl|codepoint|:}}</code> :: {{codepoint|:}} <includeonly> [[Category:Internal link templates‎|Codepoint]] </includeonly> t9l4ftrx5q3hb0h0i637988tqwpaujn 237260 237259 2026-09-11T11:18:55Z Lee 19 [[:en:Template:codepoint/documentation]] වෙතින් එක් සංශෝධනයක් 237259 wikitext text/x-wiki {{documentation subpage}} This template generates a textual reference to a Unicode codepoint. Implemented with [[Module:Unicode data/templates/codepoint]]. ==Parameters== ; {{para|1|req=1}} : The codepoint, either given as a single character or in the notation <kbd>U+xxxx</kbd>. ; {{para|display}} : Whether to display the referenced character. Done by default if the codepoint is assigned and represents a printable non-whitespace character. ; {{para|link}} : Whether to display a link to the referenced character. Done by default if the codepoint is assigned and represents a printable character. If the character is displayed, the link will be added to the character, and otherwise to the hexadecimal notation. ; {{para|plain|1}} : Automatically specifies {{para|display|0}}, {{para|link|0}}. ; {{para|html|1}} : Displays a HTML entity representation. ; {{para|noname|1}} : Hides the character name. ==Examples== <code>{{tl|codepoint|U+2010}}</code> :: {{codepoint|U+2010}} <code> {{tl|codepoint|U+2010|display=0}}</code> :: {{codepoint|U+2010|display=0}} <code>{{tl|codepoint|:}}</code> :: {{codepoint|:}} <includeonly> [[Category:Internal link templates‎|Codepoint]] </includeonly> t9l4ftrx5q3hb0h0i637988tqwpaujn සැකිල්ල:codepoint/style.css 10 145038 237261 2023-04-22T08:53:58Z en>Surjection 0 Created page with ".codepoint-character { font-size: 125%; } .codepoint-name { font-size: smaller; font-variant: small-caps; }" 237261 sanitized-css text/css .codepoint-character { font-size: 125%; } .codepoint-name { font-size: smaller; font-variant: small-caps; } b464q2iyeq80tij5a1tbtgu9yvu9giu 237262 237261 2026-09-11T11:19:21Z Lee 19 [[:en:Template:codepoint/style.css]] වෙතින් එක් සංශෝධනයක් 237261 sanitized-css text/css .codepoint-character { font-size: 125%; } .codepoint-name { font-size: smaller; font-variant: small-caps; } b464q2iyeq80tij5a1tbtgu9yvu9giu Module:Unicode data/templates/codepoint 828 145039 237263 2026-04-15T19:04:05Z en>Surjection 0 Changed protection settings for "[[Module:Unicode data/templates/codepoint]]" ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 237263 Scribunto text/plain local m_str_utils = require("Module:string utilities") local codepoint = m_str_utils.codepoint local find = m_str_utils.find local gcodepoint = m_str_utils.gcodepoint local len = m_str_utils.len local sub = m_str_utils.sub local u = m_str_utils.char local yesno = require("Module:yesno") local m_unicodedata = require("Module:Unicode data") local export = {} local function get_html_entity_character(c) local data = require("Module:Unicode data/data/html entities") if data[c] then return string.format("&%s;", data[c]) end -- hex? -- return string.format("&#x%x;", c) return string.format("&#%u;", c) end function export.get_html_entity(s, escape) local entity = "" for c in gcodepoint(s) do entity = entity .. get_html_entity_character(c) end if escape then entity = mw.text.encode(entity) end return entity end function export.get_codepoint_link_target(ch) local data = mw.loadData("Module:Unicode data/data") local c = codepoint(ch) if data.unsupported_title[c] then return data.unsupported_title[c] end return mw.uri.encode(ch, "PATH") end local function unicode_link(ch, text) return "[[" .. export.get_codepoint_link_target(ch) .. "#Translingual|" .. text .. "]]" end function export.show(frame) local args = frame:getParent().args if not args[1] then error("The first parameter is required.") end local c if len(args[1]) == 1 then c = codepoint(args[1], 1, 1) elseif find(args[1], "^U%+[0-9A-Fa-f]+$") then local hexcode = sub(args[1], 3) if len(hexcode) <= 7 then c = tonumber(hexcode, 16) end end local display if args["display"] then display = yesno(args["display"], nil) end local link if args["link"] then link = yesno(args["link"], nil) end if args["plain"] then display = false link = false end if not c then error("Argument 1 is unsupported (must be a single codepoint or a hex code of the form U+NNNN)") end if display == nil then display = m_unicodedata.is_assigned(c) and m_unicodedata.is_printable(c) if link == nil then link = display end display = display and not m_unicodedata.is_whitespace(c) end if link == nil then link = m_unicodedata.is_assigned(c) and m_unicodedata.is_printable(c) end local ch = u(c) local printed = unicode_reference local unicode_reference = '<span class="nowrap">' .. string.format("U+%04X", c) .. '</span>' local unicode_name = m_unicodedata.lookup_name(c) local unicode_name_display = '<span class="codepoint-name">' .. unicode_name .. "</span>" local extra = {} if link and not display then unicode_reference = unicode_link(ch, unicode_reference) end local unicode_display = unicode_reference if not args["noname"] then unicode_display = unicode_display .. " " .. unicode_name_display end if args["html"] then table.insert(extra, 'HTML <code class="nowrap">' .. export.get_html_entity(ch, true) .. '</code>') end if #extra > 0 then extra = table.concat(extra, ", ") else extra = nil end if display then local unicode_print = '<span class="Unicode codepoint-character">' .. ch .. "</span>" if link then unicode_print = unicode_link(ch, unicode_print) end if extra then unicode_display = unicode_print .. " (" .. unicode_display .. ", " .. extra .. ")" else unicode_display = unicode_print .. " (" .. unicode_display .. ")" end elseif extra then unicode_display = unicode_display .. " (" .. extra .. ")" end return unicode_display end return export meqh1bfnny1660uz0k9gwogy8gb6bbt 237264 237263 2026-09-11T11:20:12Z Lee 19 [[:en:Module:Unicode_data/templates/codepoint]] වෙතින් එක් සංශෝධනයක් 237263 Scribunto text/plain local m_str_utils = require("Module:string utilities") local codepoint = m_str_utils.codepoint local find = m_str_utils.find local gcodepoint = m_str_utils.gcodepoint local len = m_str_utils.len local sub = m_str_utils.sub local u = m_str_utils.char local yesno = require("Module:yesno") local m_unicodedata = require("Module:Unicode data") local export = {} local function get_html_entity_character(c) local data = require("Module:Unicode data/data/html entities") if data[c] then return string.format("&%s;", data[c]) end -- hex? -- return string.format("&#x%x;", c) return string.format("&#%u;", c) end function export.get_html_entity(s, escape) local entity = "" for c in gcodepoint(s) do entity = entity .. get_html_entity_character(c) end if escape then entity = mw.text.encode(entity) end return entity end function export.get_codepoint_link_target(ch) local data = mw.loadData("Module:Unicode data/data") local c = codepoint(ch) if data.unsupported_title[c] then return data.unsupported_title[c] end return mw.uri.encode(ch, "PATH") end local function unicode_link(ch, text) return "[[" .. export.get_codepoint_link_target(ch) .. "#Translingual|" .. text .. "]]" end function export.show(frame) local args = frame:getParent().args if not args[1] then error("The first parameter is required.") end local c if len(args[1]) == 1 then c = codepoint(args[1], 1, 1) elseif find(args[1], "^U%+[0-9A-Fa-f]+$") then local hexcode = sub(args[1], 3) if len(hexcode) <= 7 then c = tonumber(hexcode, 16) end end local display if args["display"] then display = yesno(args["display"], nil) end local link if args["link"] then link = yesno(args["link"], nil) end if args["plain"] then display = false link = false end if not c then error("Argument 1 is unsupported (must be a single codepoint or a hex code of the form U+NNNN)") end if display == nil then display = m_unicodedata.is_assigned(c) and m_unicodedata.is_printable(c) if link == nil then link = display end display = display and not m_unicodedata.is_whitespace(c) end if link == nil then link = m_unicodedata.is_assigned(c) and m_unicodedata.is_printable(c) end local ch = u(c) local printed = unicode_reference local unicode_reference = '<span class="nowrap">' .. string.format("U+%04X", c) .. '</span>' local unicode_name = m_unicodedata.lookup_name(c) local unicode_name_display = '<span class="codepoint-name">' .. unicode_name .. "</span>" local extra = {} if link and not display then unicode_reference = unicode_link(ch, unicode_reference) end local unicode_display = unicode_reference if not args["noname"] then unicode_display = unicode_display .. " " .. unicode_name_display end if args["html"] then table.insert(extra, 'HTML <code class="nowrap">' .. export.get_html_entity(ch, true) .. '</code>') end if #extra > 0 then extra = table.concat(extra, ", ") else extra = nil end if display then local unicode_print = '<span class="Unicode codepoint-character">' .. ch .. "</span>" if link then unicode_print = unicode_link(ch, unicode_print) end if extra then unicode_display = unicode_print .. " (" .. unicode_display .. ", " .. extra .. ")" else unicode_display = unicode_print .. " (" .. unicode_display .. ")" end elseif extra then unicode_display = unicode_display .. " (" .. extra .. ")" end return unicode_display end return export meqh1bfnny1660uz0k9gwogy8gb6bbt 〆 0 145040 237265 2026-05-30T06:09:24Z en>Chuck Entz 0 Reverted edits by [[Special:Contributions/~2026-32142-32|~2026-32142-32]]. If you think this rollback is in error, please leave a message on my talk page. 237265 wikitext text/x-wiki {{character info}} ==Japanese== {{ja-kanjitab|alt=乄:uncommon}} {{wp|ja:}} ===Glyph origin=== {{ja-etym-kokuji}}. From {{m|ja|占める|tr=shimeru}}, as cursive form of top component ト (also [[〆]]). Then applied to other kanji of the same pronunciation, namely 締め, 閉め, 絞め, and 搾め, all pronounced しめ ''shime.'' Sense of “closed, fastened” is due to {{m|ja|閉める||to close|tr=shimeru}} and {{m|ja|締める||to fasten|tr=shimeru}}. ===Kanji=== {{ja-pos|symbol|しめ}} # "letter closed" character (from 閉める, ''close'') # {{abbr of|ja|締め|tr=shime}} # [[sum]] (from 〆高, [[締高]], ''sum'') # [[measurement]] of [[paper]] # [[bundle]] (from [[締める]], ''fasten'') ====Usage notes==== {{m-self|ja|〆}} is primarily used as an abbreviation for {{ja-r|締め|しめ}}, most commonly in {{ja-r|〆%切|しめ%きり}}, as an abbreviation for {{ja-r|締%切|しめ%きり|deadline; locked (door)}}; also {{ja-r|締める|しめる}} as {{ja-r|〆る|しめる}} and {{ja-r|締%高|シメ%ダカ}} as {{ja-r|〆%高|シメ%ダカ}}. It is also sometimes used for {{ja-r|閉め|しめ|closed envelope}}. Even more rarely, it is used to abbreviate other kanji, including {{ja-r|絞め|しめ}}, {{ja-r|占め|しめ}}, and {{ja-r|搾め|しめ}}, as in {{ja-r|〆%粕|しめ%かす}} for {{ja-r|搾め糟|しめかす}}) There is also occasional use of {{m|ja|乄}}, as in {{ja-r|乄%高|シメ%ダカ}}. ====Descendants==== * {{desc|zh|𡆢}} ===See also=== {{list:Japanese scribal abbreviations/ja}} 8cuvmoje8kerjcht9z5v8yil112bsdf 237266 237265 2026-09-11T11:20:47Z Lee 19 [[:en:〆]] වෙතින් එක් සංශෝධනයක් 237265 wikitext text/x-wiki {{character info}} ==Japanese== {{ja-kanjitab|alt=乄:uncommon}} {{wp|ja:}} ===Glyph origin=== {{ja-etym-kokuji}}. From {{m|ja|占める|tr=shimeru}}, as cursive form of top component ト (also [[〆]]). Then applied to other kanji of the same pronunciation, namely 締め, 閉め, 絞め, and 搾め, all pronounced しめ ''shime.'' Sense of “closed, fastened” is due to {{m|ja|閉める||to close|tr=shimeru}} and {{m|ja|締める||to fasten|tr=shimeru}}. ===Kanji=== {{ja-pos|symbol|しめ}} # "letter closed" character (from 閉める, ''close'') # {{abbr of|ja|締め|tr=shime}} # [[sum]] (from 〆高, [[締高]], ''sum'') # [[measurement]] of [[paper]] # [[bundle]] (from [[締める]], ''fasten'') ====Usage notes==== {{m-self|ja|〆}} is primarily used as an abbreviation for {{ja-r|締め|しめ}}, most commonly in {{ja-r|〆%切|しめ%きり}}, as an abbreviation for {{ja-r|締%切|しめ%きり|deadline; locked (door)}}; also {{ja-r|締める|しめる}} as {{ja-r|〆る|しめる}} and {{ja-r|締%高|シメ%ダカ}} as {{ja-r|〆%高|シメ%ダカ}}. It is also sometimes used for {{ja-r|閉め|しめ|closed envelope}}. Even more rarely, it is used to abbreviate other kanji, including {{ja-r|絞め|しめ}}, {{ja-r|占め|しめ}}, and {{ja-r|搾め|しめ}}, as in {{ja-r|〆%粕|しめ%かす}} for {{ja-r|搾め糟|しめかす}}) There is also occasional use of {{m|ja|乄}}, as in {{ja-r|乄%高|シメ%ダカ}}. ====Descendants==== * {{desc|zh|𡆢}} ===See also=== {{list:Japanese scribal abbreviations/ja}} 8cuvmoje8kerjcht9z5v8yil112bsdf සැකිල්ල:ja-etym-kokuji 10 145041 237267 2026-04-06T17:59:49Z en>Kedymera 0 "nocap", like every other template 237267 wikitext text/x-wiki {{#if:{{{nocap|}}}|a|A}} {{#ifeq:{{{r|}}}|1|{{ja-r|国%字|こく%じ|rom=[[kokuji]]|[[Japan]]ese-[[coin#Verb|coined]] [[Chinese character|character]]}}|{{m|ja|国字|tr=[[kokuji]]||[[Japan]]ese-[[coin#Verb|coined]] [[Chinese character|character]]}}}}<!-- We need a Japanese radical-stroke sortkey module. -->{{categorize|ja|Japanese-coined CJKV characters|sort={{#invoke:Hani-sortkey/templates|sortkey|{{PAGENAME}}}}}}<!-- --><noinclude>{{documentation}}</noinclude> ps9bukktce6v44ub12gbsopke2h9v2n 237268 237267 2026-09-11T11:21:21Z Lee 19 [[:en:Template:ja-etym-kokuji]] වෙතින් එක් සංශෝධනයක් 237267 wikitext text/x-wiki {{#if:{{{nocap|}}}|a|A}} {{#ifeq:{{{r|}}}|1|{{ja-r|国%字|こく%じ|rom=[[kokuji]]|[[Japan]]ese-[[coin#Verb|coined]] [[Chinese character|character]]}}|{{m|ja|国字|tr=[[kokuji]]||[[Japan]]ese-[[coin#Verb|coined]] [[Chinese character|character]]}}}}<!-- We need a Japanese radical-stroke sortkey module. -->{{categorize|ja|Japanese-coined CJKV characters|sort={{#invoke:Hani-sortkey/templates|sortkey|{{PAGENAME}}}}}}<!-- --><noinclude>{{documentation}}</noinclude> ps9bukktce6v44ub12gbsopke2h9v2n සැකිල්ල:ja-etym-kokuji/documentation 10 145042 237269 2026-04-08T23:21:40Z en>Poketalker 0 Documentation update; can be demonstrated better to match current standards? 237269 wikitext text/x-wiki {{documentation subpage}} Used in '''Glyph origin''' headers under Japanese entries to explain that a character was created in Japan: * With capitalization and no ruby: {{ja-etym-kokuji}} * With {{para|r|1|opt=1}}: {{ja-etym-kokuji|r=1}} * With {{para|nocap|1}}: {{ja-etym-kokuji|nocap=1}} The template does not generate a full stop, so you should put one after it if appropriate. <includeonly> [[Category:Japanese etymology templates|etym-kokuji]] </includeonly> 0jp36nig26n4vu8snso99kcrlax9hdn 237270 237269 2026-09-11T11:21:47Z Lee 19 [[:en:Template:ja-etym-kokuji/documentation]] වෙතින් එක් සංශෝධනයක් 237269 wikitext text/x-wiki {{documentation subpage}} Used in '''Glyph origin''' headers under Japanese entries to explain that a character was created in Japan: * With capitalization and no ruby: {{ja-etym-kokuji}} * With {{para|r|1|opt=1}}: {{ja-etym-kokuji|r=1}} * With {{para|nocap|1}}: {{ja-etym-kokuji|nocap=1}} The template does not generate a full stop, so you should put one after it if appropriate. <includeonly> [[Category:Japanese etymology templates|etym-kokuji]] </includeonly> 0jp36nig26n4vu8snso99kcrlax9hdn සැකිල්ල:list:Japanese scribal abbreviations/ja 10 145043 237271 2025-01-24T22:06:44Z en>WingerBot 0 add a * before lists that don't use [[Module:topic list]], {{list helper 2}}, {{letters}} or {{letter names}} (which auto-add the *) (manually assisted) 237271 wikitext text/x-wiki {{list helper 2 |title=Japanese ligatures and scribal abbreviations <!--|cat=ja:Japanese months--> |list=<!-- -->{{ja-r|〆|しめ}}, <!-- -->{{ja-r|𪜈|とも}}, <!-- -->{{ja-r|ゟ|より}}, <!-- -->{{ja-r|ヿ|こと}}, <!-- -->{{ja-r|𬼀|して}}, <!-- -->{{ja-r|〼|ます}}, <!-- -->{{ja-r|ヶ||graphical abbreviation for {{ja-r|箇||rom=-}}|rom=-}}, <!-- -->{{ja-r|々||iteration mark|rom=-}}, <!-- -->{{ja-r|ゝ||iteration mark for hiragana|rom=-}}, <!-- -->{{ja-r|ヽ||iteration mark for katakana|rom=-}} <!-- -->{{ja-r|〱||iteration mark for multiple kana|rom=-}}, <!-- -->}}<noinclude>{{list doc}}</noinclude> 8b40yracdbxp6amtsyjssac010xw4gq 237272 237271 2026-09-11T11:22:15Z Lee 19 [[:en:Template:list:Japanese_scribal_abbreviations/ja]] වෙතින් එක් සංශෝධනයක් 237271 wikitext text/x-wiki {{list helper 2 |title=Japanese ligatures and scribal abbreviations <!--|cat=ja:Japanese months--> |list=<!-- -->{{ja-r|〆|しめ}}, <!-- -->{{ja-r|𪜈|とも}}, <!-- -->{{ja-r|ゟ|より}}, <!-- -->{{ja-r|ヿ|こと}}, <!-- -->{{ja-r|𬼀|して}}, <!-- -->{{ja-r|〼|ます}}, <!-- -->{{ja-r|ヶ||graphical abbreviation for {{ja-r|箇||rom=-}}|rom=-}}, <!-- -->{{ja-r|々||iteration mark|rom=-}}, <!-- -->{{ja-r|ゝ||iteration mark for hiragana|rom=-}}, <!-- -->{{ja-r|ヽ||iteration mark for katakana|rom=-}} <!-- -->{{ja-r|〱||iteration mark for multiple kana|rom=-}}, <!-- -->}}<noinclude>{{list doc}}</noinclude> 8b40yracdbxp6amtsyjssac010xw4gq