This module powers Welsh mutation tables, including automatically generating the correct mutations for a given word.
|1=
|soft=
|nasal=
|aspirate=
|nocat=
|nocat=1
, then the resulting table will not contain any page categories. If left default or set to a false value then categories may get set, for example Welsh terms with irregular mutation in the case of mutation tables with at least one irregular value.local export = {}
local yesno = require("Module:yesno")
local toNFC = mw.ustring.toNFC
local toNFD = mw.ustring.toNFD
local ulower = mw.ustring.lower
local umatch = mw.ustring.match
local usub = mw.ustring.sub
local GRAVE = "\204\128"
local ACUTE = "\204\129"
local CIRC = "\204\130"
local DIAER = "\204\136"
local lang = require("Module:languages").getByCode("cy")
local PAGENAME = mw.loadData("Module:headword/data").pagename
local MARKER = "<sup>△</sup>"
local mutation_rules = {
= {"f", "m"},
= {"g", "ngh", "ch"},
= true,
= {"dd", "n"},
= true,
= true,
= {"", "ng"},
= true,
= true,
= true,
= true,
= {"l"},
= {"f"},
= true,
= true,
= {"b", "mh", "ph"},
= true,
= true,
= true,
= {"r"},
= true,
= {"d", "nh", "th"},
= true,
= true,
= {"j", colloquial = true}, -- TODO: add colloquial marker.
= true,
= true,
= true
}
function export.get_mutation_data(term)
local data = {radical = term}
local term_lower = term:gsub("^.*", ulower) -- term with lowercase initial
data.is_uppercase = term_lower ~= term
local normalized = toNFD(term_lower)
data.vowel = normalized:match("^") and true or false
if data.vowel then
data.final = term_lower
-- H-prothesis, unless initial "w" is a semivowel (followed by a vowel other than "y", or "y" with a diacritic).
if not (normalized:match("^w") or umatch(normalized, "^wy")) then
data.mut3 = "h"
end
return data
end
local initial, final, mut
for i = 3, 1, -1 do
initial = usub(normalized, 1, i)
mut = mutation_rules
if mut then
final = usub(normalized, i + 1)
break
elseif i == 1 then
error(("no mutation rule found for %s"):format(term))
end
end
if type(mut) == "table" then
for k, v in pairs(mut) do
if tonumber(k) then
data = v
end
end
data.colloquial = mut.colloquial
end
if initial == "tsi" then
-- "i" in "tsi" is retained if:
-- followed by a consonant (e.g. "tsips" → "jips")
-- followed by a semivowel (e.g. "tsiwawa" → "jiwawa", but "*tsiŵawa" → "*jŵawa"); "i" and "w" are semivowels if followed by any vowel, due to the preceding "i".
-- it has a diacritic (e.g. "tsïars" → "jïars")
if not (final:match("^") and not final:match("^")) then
final = "i" .. final
-- If "i" in "tsi" is not retained, the following vowel cannot have a diaeresis unless it's followed by a vowel.
elseif not umatch(final, "^" .. DIAER .. "?") then
final = final:gsub("^()" .. DIAER, "%1") -- If there's no diaeresis, this does nothing.
end
end
data.final = toNFC(final)
return data
end
local function construct_mutation(data, accel_form, initial, override)
local normal_mutation
if not initial then
normal_mutation = nil
else
normal_mutation = initial .. data.final
if data.is_uppercase then
normal_mutation = require("Module:string utilities").ucfirst(normal_mutation)
end
end
local has_override = override
if not yesno(override, true) or override == "-" then -- TODO: yesno to be removed.
override = nil
end
local has_irreg_mutation = has_override and override ~= normal_mutation
local mutation
-- don't combine the following into A and B or C because `override` may be nil
if has_override then
mutation = override
else
mutation = normal_mutation
end
local marker = has_irreg_mutation and MARKER or ""
if mutation then
return require("Module:links").full_link({lang = lang, accel = {form = accel_form, lemma = data.radical}, term = mutation}) .. marker, true, has_irreg_mutation
else
return "''unchanged''" .. marker, false, has_irreg_mutation
end
end
function export.show(frame)
local params = {
= {},
= {},
= {},
= {},
= {type = "boolean"},
}
local parargs = frame:getParent().args
local args = require("Module:parameters").process(parargs, params)
local title = args or PAGENAME
local data = export.get_mutation_data(title)
local soft, has_soft, has_irreg_soft = construct_mutation(data, "soft", data.mut1, args.soft)
local nasal, has_nasal, has_irreg_nasal = construct_mutation(data, "nasal", data.mut2, args.nasal)
local aspirate, has_aspirate, has_irreg_aspirate = construct_mutation(data, data.vowel and "h-prothesis" or "aspirate", data.mut3, args.aspirate)
local result = frame:expandTemplate{ title = 'inflection-table-top',
args = { title = '] of ' .. require("Module:links").full_link({lang = lang, alt = title}, 'term'), palette = 'green' } }
result = result .. '\n! ]'
result = result .. '\n! ]'
result = result .. '\n! ]'
result = result .. '\n! ' .. (data.vowel and ']' or ']')
result = result .. '\n|-'
result = result .. '\n| ' .. require("Module:links").full_link({lang = lang, term = data.radical})
result = result .. '\n| ' .. soft
result = result .. '\n| ' .. nasal
result = result .. '\n| ' .. aspirate
notes = ''
if has_irreg_soft or has_irreg_nasal or has_irreg_aspirate then
notes = notes .. '<p style="font-size:85%;">' .. MARKER .. 'Irregular.</p>'
end
if has_soft or has_nasal or has_aspirate then
notes = notes .. '<p style="font-size:85%;"><i>Note:</i> Certain mutated forms of some words can never occur in standard Welsh.<br>All possible mutated forms are displayed for convenience.</p>'
end
result = result .. '\n' .. frame:expandTemplate{ title = 'inflection-table-bottom', args = { notes = notes } }
if not args.nocat and (has_irreg_soft or has_irreg_nasal or has_irreg_aspirate) then
result = result .. require("Module:utilities").format_categories({"Welsh terms with irregular mutation"}, lang)
end
return result
end
return export