Modul:IPA
Penampilan
- Laman modul ini kekurangan sublaman pendokumenan. Minta tolong ciptakan laman pendokumenan tersebut.
- Pautan berguna: senarai sublaman • pautan • transklusi • kes ujian • kotak pasir
local export = {}
local force_cat = false -- for testing
local decorations_module = "Module:decorations"
local pages_module = "Module:pages"
local qualifier_module = "Module:qualifier"
local string_utilities_module = "Module:string utilities"
local syllables_module = "Module:syllables"
local utilities_module = "Module:utilities"
local m_data = mw.loadData("Module:IPA/data")
local m_str_utils = require(string_utilities_module)
local m_syllables -- [[Module:syllables]]; loaded below if needed
local m_symbols = mw.loadData("Module:IPA/data/symbols")
local concat = table.concat
local decode_entities = m_str_utils.decode_entities
local find = string.find
local gcodepoint = m_str_utils.gcodepoint
local gmatch = m_str_utils.gmatch
local gsub = string.gsub
local insert = table.insert
local is_preview = require(pages_module).is_preview
local len = m_str_utils.len
local listToText = mw.text.listToText
local match = string.match
local pattern_escape = m_str_utils.pattern_escape
local sub = string.sub
local u = m_str_utils.char
local ugsub = m_str_utils.gsub
local umatch = m_str_utils.match
local usub = m_str_utils.sub
local function with_codepoints(s)
if find(s, "%S%s") then
local parts = {}
for ch in gmatch(s, "%S") do
parts[#parts + 1] = with_codepoints(ch)
end
return concat(parts, ", ")
end
local cps = {}
for cp in gcodepoint(s) do
cps[#cps + 1] = ("U+%04X"):format(cp)
end
return s .. " [" .. concat(cps, " ") .. "]"
end
local namespace = mw.title.getCurrentTitle().nsText
local function is_content_page(lang, namespace)
return namespace == "" or namespace == "Rekonstruksi" or
lang and lang:hasType("appendix-constructed") and namespace == "Lampiran"
end
-- Etymology-only languages are not L2 entry languages; IPA should use the parent full language.
local function assert_not_etymology_only_lang(lang)
if lang and lang.hasType and lang:hasType("language", "etymology-only") then
local parent_code = lang.getParentCode and lang:getParentCode() or nil
error(("Cannot use IPA with the etymology-only language %q; use the parent full language %q instead."):format(lang:getCode(), parent_code))
end
end
local function track(page)
require("Module:debug/track")("IPA/" .. page)
return true
end
local function process_maybe_split_categories(split_output, categories, prontext, lang, errtext)
if split_output ~= "raw" then
if categories[1] then
categories = require(utilities_module).format_categories(categories, lang, nil, nil, force_cat)
else
categories = ""
end
end
if split_output then -- for use of IPA in links, etc.
if errtext then
return prontext, categories, errtext
else
return prontext, categories
end
else
return prontext .. (errtext or "") .. categories
end
end
--[==[
Format a line of one or more IPA pronunciations as {{tl|IPA}} would do it, i.e. with a preceding {"IPA:"} followed by
the word {"key"} linking to an Appendix page describing the language's phonology, and with an added category
` ``lang`` terms with IPA pronunciation`. Other than the extra preceding text and category, this is identical
to {format_IPA_multiple()}, and the considerations described there in the documentation apply here as well. There is a
single parameter `data`, an object with the following fields:
* `lang`: Object representing the language of the pronunciations, which is used when adding cleanup categories for
pronunciations with invalid phonemes; for determining how many syllables the pronunciations have in them, in order to
add a category such as [[:Category:Italian 2-syllable words]] (for certain languages only); for adding a category
` ``lang`` terms with IPA pronunciation`; and for determining the proper sort keys for categories. Unlike
for {format_IPA_multiple()}, `lang` may not be {nil}.
* `items`: List of pronunciations, in exactly the same format as for {format_IPA_multiple()}.
* `err`: If not {nil}, a string containing an error message to use in place of the link to the language's phonology.
* `separator`: The default separator to use when separating formatted items. Defaults to {", "}. Does not apply to the
first item, where the default separator is always the empty string. Overridden by the per-item `separator` field in
`items`.
* `sort_key`: Explicit sort key used for categories.
* `no_count`: Suppress adding a {#-syllable words} category such as [[:Category:Italian 2-syllable words]]. Note that
only certain languages add such categories to begin with, because it depends on knowing how to count syllables in a
given language, which depends on the phonology of the language. Also, this does not suppress the addition of cleanup
or other categories. If you need them suppressed, use `split_output` to return the categories separately and ignore
them.
* `split_output`: If not given, the return value is a concatenation of the formatted pronunciation and formatted
categories. Otherwise, two values are returned: the formatted pronunciation and the categories. If `split_output` is
the value {"raw"}, the categories are returned in list form, where the list elements are a combination of category
strings and category objects of the form suitable for passing to {format_categories()} in [[Module:utilities]]. If
`split_output` is any other value besides {nil}, the categories are returned as a pre-formatted concatenated string.
* `include_langname`: If specified, prefix the result with the language name, followed by a colon.
* `q`: {nil} or a list of left qualifiers (as in {{tl|q}}) to display at the beginning, before the formatted
pronunciations and preceding {"IPA:"}.
* `qq`: {nil} or a list of right qualifiers to display after all formatted pronunciations.
* `a`: {nil} or a list of left accent qualifiers (as in {{tl|a}}) to display at the beginning, before the formatted
pronunciations and preceding {"IPA:"}.
* `aa`: {nil} or a list of right accent qualifiers to display after all formatted pronunciations.
]==]
function export.format_IPA_full(data)
if type(data) ~= "table" or data.getCode then
error("Must now supply a table of arguments to format_IPA_full(); first argument should be that table, not a language object")
end
local lang = data.lang
local items = data.items
local err = data.err
local separator = data.separator
local sort_key = data.sort_key
local no_count = data.no_count
local split_output = data.split_output
local q = data.q
local qq = data.qq
local a = data.a
local aa = data.aa
local include_langname = data.include_langname
if data.qualifiers then
-- FIXME: added 2026-09-18; consider removing eventually.
error("overall `.qualifiers` is no longer supported; change the code to use `.q` or `.qq`")
end
local hasKey = m_data.langs_with_infopages
if not lang or not lang.getCode then
error("Must specify language to format_IPA_full()")
end
assert_not_etymology_only_lang(lang)
local langname = lang:getCanonicalName()
local prefix_text
if err then
prefix_text = '<span class="error">' .. err .. '</span>'
else
if hasKey[lang:getCode()] then
prefix_text = "Lampiran:Sebutan bahasa " .. langname
else
prefix_text = "wikipedia:Fonologi bahasa " .. langname
end
prefix_text = "[[" .. prefix_text .. "|kekunci]]"
end
local prefix = "[[Wikikamus:Abjad Fonetik Antarabangsa|AFA]]<sup>(" .. prefix_text .. ")</sup>: "
local IPAs, categories = export.format_IPA_multiple(lang, items, separator, no_count, "raw")
if is_content_page(lang, namespace) then
insert(categories, {
cat = "Perkataan dengan sebutan AFA bahasa " .. langname,
sort_key = sort_key
})
end
local prontext = prefix .. IPAs
if q and q[1] or qq and qq[1] or a and a[1] or aa and aa[1] then
prontext = require(decorations_module).format_decorations {
lang = lang,
text = prontext,
q = q,
qq = qq,
a = a,
aa = aa,
}
end
if include_langname then
prontext = langname .. ": " .. prontext
end
return process_maybe_split_categories(split_output, categories, prontext, lang)
end
local function split_phonemic_phonetic(pron)
local reconstructed, phonemic, phonetic = match(pron, "^(%*?)(/.-/)%s+(%[.-%])$")
if reconstructed then
return reconstructed .. phonemic, reconstructed .. phonetic
else
return pron, nil
end
end
local function determine_repr(pron)
local reconstructed
-- Temporarily remove any initial asterisk before representation marks,
-- which avoids having to account for it in the data, but set the
-- `reconstructed` flag.
if sub(pron, 1, 1) == "*" then
reconstructed = true
pron = sub(pron, 2)
end
-- Some representation types have aliases for convenience (e.g. "// //" is
-- an alias for "⫽ ⫽"). and these need to be substituted in before checking
-- for other data.
local opening, n = match(pron, "^.[\128-\191]*")
local subs_data = m_data.representation_subs[opening]
if subs_data then
pron, n = ugsub(pron, subs_data[1], subs_data[2])
-- If the substitution was made, `opening` needs to be changed to the
-- new opening character.
if n ~= 0 then
opening = subs_data[3]
end
end
-- Get the type data based on the opening character (if any), and set the
-- representation type if the closing character matches.
local type_data, repr, closing = m_data.representation_types[opening]
if type_data then
closing = type_data[2]
if type_data and match(pron, pattern_escape(closing) .. "$", #opening + 1) then
repr = type_data[1]
end
end
-- Default to the empty string.
if not repr then
opening, closing = "", ""
end
-- Reattach the asterisk if reconstructed.
if reconstructed then
pron = "*" .. pron
end
return pron, repr, opening, closing, reconstructed
end
local function hasInvalidSeparators(transcription)
-- Escape certain characters as well as pauses, which have the format "(...)" (with any number of dots), to avoid false-positives.
transcription = transcription:gsub(".[\128-\191]*", m_symbols.separator_escapes)
:gsub("%(%.+%)", "\3")
:gsub("[()]+", "")
return (
transcription:find("..", nil, true) or
transcription:match("%.%f[%z \1\2\3,:;]") or
transcription:match("\1%f[%z \2\3,:;]") or
transcription:match("\2%f[%z \1\3,:;]") or
transcription:match("\3[:;]") or
transcription:match("%f[^%z \1\2\3,]%.")
) and true or false
end
--[==[
Format a line of one or more bare IPA pronunciations (i.e. without any preceding {"IPA:"} and without adding to a
category ` ``lang`` terms with IPA pronunciation`). Individual pronunciations are formatted using
{format_IPA()} and are combined with separators, decorations, pre-text, post-text, etc. to form a line of pronunciations.
Parameters accepted are:
* `lang` is an object representing the language of the pronunciations, which is used when adding cleanup categories for
pronunciations with invalid phonemes; for determining how many syllables the pronunciations have in them, in order to
add a category such as [[:Category:Italian 2-syllable words]] (for certain languages only); and for computing the
proper sort keys for categories. `lang` may be {nil}.
* `items` is a list of pronunciations, each of which is an object with the following properties:
** `pron`: the pronunciation, in the same format as is accepted by {format_IPA()}, i.e. it should be either phonemic
(surrounded by {/.../}), phonetic (surrounded by {[...]}), orthographic (surrounded by {⟨...⟩}) or a rhyme
(beginning with a hyphen);
** `pretext`: text to display directly before the formatted pronunciation, inside of any qualifiers or accent
qualifiers;
** `posttext`: text to display directly after the formatted pronunciation, inside of any qualifiers or accent
qualifiers;
** `q`: {nil} or a list of left qualifiers (as in {{tl|q}}) to display before the formatted pronunciation;
** `qq`: {nil} or a list of right qualifiers to display after the formatted pronunciation;
** `a`: {nil} or a list of left accent qualifiers (as in {{tl|a}}) to display before the formatted pronunciation;
** `aa`: {nil} or a list of right accent qualifiers to after before the formatted pronunciation;
** `refs`: {nil} or a list of references or reference specs to add after the pronunciation and any posttext and
qualifiers; the value of a list item is either a string containing the reference text (typically a call to a
citation template such as {{tl|cite-book}}, or a template wrapping such a call), or an object with fields `text`
(the reference text), `name` (the name of the reference, as in {{cd|<nowiki><ref name="foo">...</ref></nowiki>}}
or {{cd|<nowiki><ref name="foo" /></nowiki>}}) and/or `group` (the group of the reference, as in
{{cd|<nowiki><ref name="foo" group="bar">...</ref></nowiki>}} or
{{cd|<nowiki><ref name="foo" group="bar"/></nowiki>}}); this uses a parser function to format the reference
appropriately and insert a footnote number that hyperlinks to the actual reference, located in the
{{cd|<nowiki><references /></nowiki>}} section;
** `gloss`: {nil} or a gloss (definition) for this item, if different definitions have different pronunciations;
** `pos`: {nil} or a part of speech for this item, if different parts of speech have different pronunciations;
** `separator`: the separator text to insert directly before the formatted pronunciation and all decorations
and pre-text; defaults to the outer `separator` parameter.
* `separator`: The default separator to use when separating formatted items. Defaults to {", "}. Does not apply to the
first item, where the default separator is always the empty string. Overridden by the per-item `separator` field in
`items`.
* `no_count`: Suppress adding a {#-syllable words} category such as [[:Category:Italian 2-syllable words]]. Note that
only certain languages add such categories to begin with, because it depends on knowing how to count syllables in a
given language, which depends on the phonology of the language. Also, this does not suppress the addition of cleanup
categories. If you need them suppressed, use `split_output` to return the categories separately and ignore them.
* `split_output`: If not given, the return value is a concatenation of the formatted pronunciation and formatted
categories. Otherwise, two values are returned: the formatted pronunciation and the categories. If `split_output` is
the value {"raw"}, the categories are returned in list form, where the list elements are a combination of category
strings and category objects of the form suitable for passing to {format_categories()} in [[Module:utilities]]. If
`split_output` is any other value besides {nil}, the categories are returned as a pre-formatted concatenated string.
]==]
function export.format_IPA_multiple(lang, items, separator, no_count, split_output)
local categories = {}
separator = separator or ", "
if not lang then
track("format-multiple-nolang")
else
assert_not_etymology_only_lang(lang)
end
-- Format
if not items[1] then
if namespace == "Templat" then
insert(items, {pron = "/aɪ piː ˈeɪ/"})
else
insert(categories, "Templat sebutan tanpa sebutan")
end
end
local bits = {}
for i, item in ipairs(items) do
local bit
-- If the pronunciation is entirely empty, allow this and don't do anything, so that e.g. the pretext and/or
-- posttext can be specified to force something like ''unknown'' to appear in place of the pronunciation
-- (as happens e.g. when ? is used as a respelling in [[Module:ca-IPA]]; see [[guèiser]] for an example).
if item.pron == "" then
bit = ""
else
local item_categories, errtext
bit, item_categories, errtext = export.format_IPA(lang, item.pron, "raw")
bit = bit .. errtext
for _, cat in ipairs(item_categories) do
insert(categories, cat)
end
end
if item.pretext then
bit = item.pretext .. bit
end
if item.posttext then
bit = bit .. item.posttext
end
if item.qualifiers then
-- FIXME: added 2026-09-18; consider removing eventually.
error("`.qualifiers` is no longer supported; change the code to use `.q` or `.qq`")
end
local has_decorations = item.q and item.q[1] or item.qq and item.qq[1] or item.a and item.a[1] or
item.aa and item.aa[1] or item.refs and item.refs[1]
local has_gloss_or_pos = item.gloss or item.pos
if has_decorations or has_gloss_or_pos then
-- FIXME: Currently we tack the gloss and POS (in that order) onto the end of the regular left qualifiers.
-- Should we do something different?
local q = item.q
if has_gloss_or_pos then
q = mw.clone(item.q) or {}
if item.gloss then
local m_qualifier = require(qualifier_module)
insert(q, m_qualifier.wrap_qualifier_css("“", "quote") .. item.gloss ..
m_qualifier.wrap_qualifier_css("”", "quote"))
end
if item.pos then
-- FIXME: Consider expanding aliases as found in [[Module:headword/data]] or similar.
insert(q, item.pos)
end
end
bit = require(decorations_module).format_decorations {
lang = lang,
text = bit,
q = q,
qq = item.qq,
a = item.a,
aa = item.aa,
refs = item.refs,
}
end
bit = (item.separator or (i == 1 and "" or separator)) .. bit
insert(bits, bit)
--[=[ [[Special:WhatLinksHere/Wiktionary:Tracking/IPA/syntax-error]]
The length or gemination symbol should not appear after a syllable break or stress symbol. ]=]
-- The nature of the following pattern match is such that we don't have to split a combined '/.../ [...]' spec
-- into its parts in order to process.
if match(item.pron, "[.\203][\136\140]?\203[\144\145]") then -- [.ˈˌ][ːˑ]
track("syntax-error")
end
if lang then
-- Add syllable count if the language's diphthongs are listed in [[Module:syllables]].
-- Don't do this if the term has spaces, a liaison mark (‿) or isn't in mainspace.
if not no_count and namespace == "" then
m_syllables = m_syllables or require(syllables_module)
local langcode = lang:getCode()
if m_data.langs_to_generate_syllable_count_categories[langcode] then
local raw_phonemic, phonetic, use_it = split_phonemic_phonetic(item.pron)
local phonemic, repr = determine_repr(raw_phonemic)
if not phonetic then -- not a '/.../ [...]' combined pronunciation
if m_data.langs_to_use_phonetic_or_phonemic_notation[langcode] then
use_it = phonemic
elseif m_data.langs_to_use_phonetic_notation[langcode] then
use_it = repr == "phonetic" and phonemic or nil
else
use_it = repr == "phonemic" and phonemic or nil
end
elseif repr == "phonetic" then
use_it = phonetic
elseif repr == "phonemic" then
use_it = phonemic
end
-- Note: two uses of find with plain patterns is much faster than umatch with [ ‿].
if use_it and not (find(use_it, " ") or find(use_it, "‿")) then
local syllable_count = m_syllables.getVowels(use_it, lang)
if syllable_count then
insert(categories, "Perkataan " .. syllable_count .. " suku kata bahasa " .. lang:getCanonicalName())
end
end
end
end
end
end
return process_maybe_split_categories(split_output, categories, concat(bits), lang)
end
--[=[
Format a single IPA pronunciation, which cannot be a combined spec (such as {/.../ [...]}). This has been extracted from
{format_IPA()} to allow the latter to handle such combined specs. This works like {format_IPA()} but requires that
pre-created {err} (for error messages) and {categories} lists be passed in, and adds any generated error messages and
categories to those lists. A single value is returned, the pronunciation, which is usually the same as passed in, but
may have HTML added surrounding invalid characters so they appear in red.
]=]
local function format_one_IPA(lang, raw_pron, err, categories)
-- Disallow wikilinks.
if match(raw_pron, "%[%[.-%]%]") then
error("IPA input must not contain wikilinks.")
end
raw_pron = decode_entities(raw_pron)
-- Detect the type of transcription.
local pron, repr, opening, closing, reconstructed = determine_repr(raw_pron)
-- Strip any reconstruction asterisk and representation marks.
pron = sub(pron, #opening + 1 + (reconstructed and 1 or 0), -#closing - 1)
if not repr then
insert(categories, "Sebutan AFA dengan tanda perwakilan tidak sah")
-- insert(err, "tanda perwakilan tidak sah")
-- Removed because it's annoying when previewing pronunciation pages.
end
if repr ~= "orthographic" and lang and lang:getCode() == "en" and hasInvalidSeparators(pron) then
insert(categories, "Sebutan AFA bahasa Inggeris dengan pemisah tidak sah")
end
if pron == "" then
insert(categories, "Sebutan AFA dengan tiada sebutan")
end
-- Check for obsolete and nonstandard symbols
for _, symbol in ipairs(m_data.nonstandard) do
local result
for nonstandard in gmatch(pron, symbol) do
if not result then
result = {}
end
insert(result, nonstandard)
insert(categories,
{cat = "Sebutan AFA dengan aksara usang atau tidak standard", sort_key = nonstandard}
)
end
if result then
insert(err, "aksara usang atau tidak standard (" .. concat(result) .. ")")
break
end
end
--[[ Check for invalid symbols after removing the following:
1. wikilinks (handled above)
2. paired HTML tags
3. bolding
4. italics
5. asterisk at beginning of transcription
6. comma followed by spacing characters
7. superscripts enclosed in superscript parentheses ]]
local found_HTML
local result = gsub(pron, "<(%a+)[^>]*>([^<]+)</%1>",
function(tagName, content)
found_HTML = true
return content
end)
result = gsub(result, "'''([^']*)'''", "%1")
result = gsub(result, "''([^']*)''", "%1")
result = gsub(result, "^%*", "")
result = ugsub(result, ",%s+", "")
-- VS15
local vs15_class = "[" .. m_symbols.add_vs15 .. "]"
if umatch(pron, vs15_class) then
local vs15 = u(0xFE0E)
if find(result, vs15) then
result = gsub(result, vs15, "")
pron = gsub(pron, vs15, "")
end
pron = ugsub(pron, vs15_class, "%0" .. vs15)
end
if result ~= "" then
local content_page = is_content_page(lang, namespace)
if lang then
-- Get the per_lang_valid data, and convert any per-language valid sequences to spaces.
local per_lang_valid = m_symbols.per_lang_valid[lang:getCode()]
if per_lang_valid then
if type(per_lang_valid) == "table" then
for _, pattern in pairs(per_lang_valid) do
result = ugsub(result, pattern, " ")
end
else -- Should be a string.
result = ugsub(result, per_lang_valid, " ")
end
end
end
local suggestions = {}
-- Check for any invalid sequences, excluding anything in the per-language lookup table.
for k, v in pairs(m_symbols.invalid) do
if find(result, k, nil, true) then
insert(suggestions, with_codepoints(k) .. " dengan " .. with_codepoints(v))
end
end
if suggestions[1] then
local replacements = "menggantikan " .. listToText(suggestions)
if content_page then
error("Invalid IPA: " .. replacements)
end
insert(err, replacements)
end
-- Convert any valid character sequences to spaces
for _, pattern in pairs(m_symbols.valid) do
result = ugsub(result, pattern, " ")
end
if not match(result, "^ *$") then
local category = "Sebutan AFA dengan aksara AFA tidak sah"
if not content_page then
category = category .. "/non_mainspace"
end
insert(categories, category)
insert(err, "aksara AFA tidak sah: " .. with_codepoints(result))
end
end
if found_HTML then
insert(categories, "Sebutan AFA dengan tag HTML berpasangan")
end
if (repr == "phonemic" or repr == "rhyme") and lang and m_data.phonemes[lang:getCode()] then
local valid_phonemes = m_data.phonemes[lang:getCode()]
local rest = pron
local phonemes = {}
while #rest > 0 do
local longestmatch, longestmatch_len = "", 0
local rest_init = sub(rest, 1, 1)
if rest_init == "(" or rest_init == ")" then
longestmatch = rest_init
longestmatch_len = 1
else
for _, phoneme in ipairs(valid_phonemes) do
local phoneme_len = len(phoneme)
if phoneme_len > longestmatch_len and usub(rest, 1, phoneme_len) == phoneme then
longestmatch = phoneme
longestmatch_len = len(longestmatch)
end
end
end
if longestmatch_len > 0 then
insert(phonemes, longestmatch)
rest = usub(rest, longestmatch_len + 1)
else
local phoneme = usub(rest, 1, 1)
insert(phonemes, "<span style=\"color: var(--wikt-palette-red,red)\">" .. phoneme .. "</span>")
rest = usub(rest, 2)
insert(categories, "Sebutan AFA dengan fonem tidak sah/" .. lang:getCode())
track("fonem tidak sah/" .. phoneme)
end
end
pron = concat(phonemes)
end
return (reconstructed and "*" or "") .. opening .. pron .. closing
end
--[==[
Format an IPA pronunciation. This wraps the pronunciation in appropriate CSS classes and adds cleanup categories and
error messages as needed. The pronunciation `pron` should be either phonemic (surrounded by {/.../}), phonetic
(surrounded by {[...]}), orthographic (surrounded by {⟨...⟩}), a rhyme (beginning with a hyphen) or a combined
phonemic/phonetic spec (of the form {/.../ [...]}). `lang` indicates the language of the pronunciation and can be {nil}.
If not {nil}, and the specified language has data in [[Module:IPA/data]] indicating the allowed phonemes, then the page
will be added to a cleanup category and an error message displayed next to the outputted pronunciation. Note that {lang}
also determines sort key processing in the added cleanup categories. If `split_output` is not given, the return value is
a concatenation of the formatted pronunciation, error messages and formatted cleanup categories. Otherwise, three values
are returned: the formatted pronunciation, the cleanup categories and the concatenated error messages. If `split_output`
is the value {"raw"}, the cleanup categories are returned in list form, where the list elements are a combination of
category strings and category objects of the form suitable for passing to {format_categories()} in [[Module:utilities]].
If `split_output` is any other value besides {nil}, the cleanup categories are returned as a pre-formatted concatenated
string.
]==]
function export.format_IPA(lang, pron, split_output)
local err = {}
local categories = {}
-- `pron` shouldn't contain ref tags.
if match(pron, "\127'\"`UNIQ%-%-ref%-[%dA-F]+%-QINU`\"'\127") then
error("<ref> tags found inside pronunciation parameter.")
end
if not lang then
track("format-nolang")
else
assert_not_etymology_only_lang(lang)
end
local phonemic, phonetic = split_phonemic_phonetic(pron)
pron = format_one_IPA(lang, phonemic, err, categories)
if phonetic then
track("phonemic-phonetic") -- There's no benefit to supporting the "/.../ [...]" format within one parameter.
phonetic = format_one_IPA(lang, phonetic, err, categories)
pron = pron .. " " .. phonetic
end
if err[1] and is_preview() then
err = '<span class="error" style="font-size: small;> ' .. concat(err, ", ") .. "</span>"
else
err = ""
end
return process_maybe_split_categories(split_output, categories, '<span class="IPA nowrap">' .. pron .. "</span>", lang,
err)
end
--[==[
Format a line of one or more enPR pronunciations as {{tl|enPR}} would do it, i.e. with a preceding {"enPR:"} (linked to
[[Appendix:English pronunciation]]) followed by one or more formatted, comma-separated enPR pronunciations. The
pronunciations are formatted by wrapping them in the `AHD` and `enPR` CSS classes and adding any decorations
(qualifiers, accent qualifiers and references). In addition, the overall result is wrapped in any overall decorations.
There is a single parameter `data`, an object with the following fields:
* `items` is a list of enPR pronunciations, each of which is an object with the following properties:
** `pron`: the enPR pronunciation;
** `q`: {nil} or a list of left qualifiers (as in {{tl|q}}) to display before the formatted pronunciation;
** `qq`: {nil} or a list of right qualifiers to display after the formatted pronunciation;
** `a`: {nil} or a list of left accent qualifiers (as in {{tl|a}}) to display before the formatted pronunciation;
** `aa`: {nil} or a list of right accent qualifiers to after before the formatted pronunciation.
* `q`: {nil} or a list of left qualifiers (as in {{tl|q}}) to display at the beginning, before the formatted
pronunciations and preceding {"enPR:"}.
* `qq`: {nil} or a list of right qualifiers to display after all formatted pronunciations.
* `a`: {nil} or a list of left accent qualifiers (as in {{tl|a}}) to display at the beginning, before the formatted
pronunciations and preceding {"enPR:"}.
* `aa`: {nil} or a list of right accent qualifiers to display after all formatted pronunciations.
]==]
function export.format_enPR_full(data)
local prefix = "[[Appendix:English pronunciation|enPR]]: "
local lang = require("Module:languages").getByCode("en")
local parts = {}
for _, item in ipairs(data.items) do
local part = '<span class="AHD enPR">' .. item.pron .. "</span>"
if item.qualifiers then
-- FIXME: added 2026-09-18; consider removing eventually.
error("`.qualifiers` is no longer supported; change the code to use `.q` or `.qq`")
end
if item.q and item.q[1] or item.qq and item.qq[1] or item.a and item.a[1] or item.aa and item.aa[1] then
part = require(decorations_module).format_decorations {
lang = lang,
text = part,
q = item.q,
qq = item.qq,
a = item.a,
aa = item.aa,
}
end
insert(parts, part)
end
local prontext = prefix .. concat(parts, ", ")
if data.qualifiers then
-- FIXME: added 2026-09-18; consider removing eventually.
error("overall `.qualifiers` is no longer supported; change the code to use `.q` or `.qq`")
end
if data.q and data.q[1] or data.qq and data.qq[1] or data.a and data.a[1] or data.aa and data.aa[1] then
prontext = require(decorations_module).format_decorations {
lang = lang,
text = prontext,
q = data.q,
qq = data.qq,
a = data.a,
aa = data.aa,
}
end
return prontext
end
return export