Implements {{frp-IPA}}
. Locality data in Module:frp-IPA/data.
local m_link = require("Module:links")
local frp = require("Module:languages").getByCode("frp")
local m_IPA = require("Module:IPA")
local format_accent = require("Module:accent qualifier").format_qualifiers
local locs_data = mw.loadData("Module:frp-IPA/data")
local get_section = require("Module:pages").get_section
local m_temp = require("Module:template parser")
local m_form_of = require("Module:form of")
local export = {}
local accents = mw.loadData("Module:labels/data/lang/frp")
local codes = { "nch", "onch", "vds", "ovds", "frb", "ofrb", "vls", "ovls", "vld",
"pms", "apl", "svy", "osvy", "gnv", "ognv", "cmt", "bgs", "dph", "odph",
"dmb", "brs", "obrs", "mcn", "bjl", "objl",
"lyn", "olyn", "frz", "ofrz" }
local allowed_codes = require("Module:table").listToSet(codes)
allowed_codes.sources = true
allowed_codes.cf = true
allowed_codes.note = true
export.codes = codes
local references = { "AIS", "ALF", "ALLy", "ALP", "ALV", "APV", "DFF", "DGL", "DLG",
"DPB", "DSV", "LPT", "MHN", "PhL", "PVA", "SSV", "TPh", "VFC", "VIV" }
export.references = references
local allowed_refs = require("Module:table").listToSet(references)
local function record(data, field)
return function(value)
if value ~= "" then
data = value
end
return ""
end
end
-- format: "<ortho>(loc1,loc2,...)ref"
local function parse(text, loc, require_pron)
local data = {}
text = text:gsub("]+]", record(data, "pron"))
if require_pron and not data.pron then error("Missing pronunciation in " .. loc) end
text = text:gsub("^<(+)>", record(data, "ortho"))
text = text:gsub("^%((+)%)", record(data, "locs"))
if text:match("^") then -- reference must start with capital letter
if not allowed_refs then
error("Invalid reference: " .. text)
end
data.ref = text
elseif text ~= "" then
error("Invalid input (" .. loc .. "): " .. text)
end
return data
end
local function link(text)
return m_link.full_link({ lang = frp, term = text })
end
local function format_ortho(text)
if text then
return " ⟨" .. m_link.full_link({ lang = frp, term = text }) .. "⟩"
end
return ""
end
-- Obtains data (i.e. location name, Wikipedia link, sortkey value) from one or more location
-- codes (separated by comma).
local function parse_locs(group, text)
local locs = mw.text.split(text, ",", true)
for i, code in ipairs(locs) do
local data = locs_data
if not data then
error("Invalid code " .. code .. " for " .. accents)
end
if type(data) == "string" then -- allow redirect once
code = data
data = locs_data
end
local wiki = (type(data) == "table") and data.wiki or code
-- The parens around <frp:makeSortKey> avoid the return table to be filled with
-- an unwanted empty table.
-- TODO: Perhaps, in the sortkey, articles should be ignored, with an expression
-- such as "^L?s?".
locs = {
wiki = wiki,
text = code,
sortkey = (frp:makeSortKey(code))
}
end
table.sort(locs, function(a, b) return a.sortkey < b.sortkey end)
return locs
end
-- Format locations into links to Wikipedia.
local function format_locs(locs, no_paren)
if not locs then
return ""
end
for i, loc in ipairs(locs) do
locs = "]"
end
return (no_paren and "%s" or " (%s)"):format(table.concat(locs, ", "))
end
-- check if each parameter name is valid
local function check_groups(args)
for a, _ in pairs(args) do
if type(a) == "number" then
error("This template does not accept numbered arguments.")
end
if not allowed_codes and not locs_data then
error("Invalid accent code: " .. a)
end
end
end
local function gather_data(data, args, require_pron)
for _, a in ipairs(codes) do
if args and args ~= "" then
data = {}
for term in mw.text.gsplit(args, ";", true) do
local loc_data = parse(term, a, require_pron)
table.insert(data, loc_data)
if loc_data.pron then
data.has_pron = true
end
if loc_data.ortho then
data.has_ortho = true
end
end
end
end
end
-- `next` doesn't seem to work
local function is_empty(args)
for _, _ in pairs(args) do
return false
end
return true
end
local function scrape(pagename)
local content = mw.title.new(pagename):getContent()
content = get_section(content, { "Franco-Provençal", "Alternative forms" }, 3)
for template in m_temp.find_templates(content) do
if template:get_name() == "frp-alt" then
return template:get_arguments()
end
end
error("Scraping failed.")
end
-- explode the locs and group by loc
local function record_locs(target, term, region_name)
local function add_one_loc(loc)
local key = loc and loc.text or ""
if not target then
if loc then
table.insert(target, loc)
end
target = {}
end
table.insert(target, term)
end
if not term.locs then
add_one_loc()
return
end
for _, loc in ipairs(parse_locs(region_name, term.locs)) do
add_one_loc(loc)
end
end
-- Orders the many transcription of a single wide region and minimises the lines needed
-- whenever possible.
-- The data in the input is the list of locations and the terms for each location.
local function order_data(data)
if #data == 0 then
return {""}
end
-- STEP 1: Order alphabetically by location name.
table.sort(data, function(a, b) return a.sortkey < b.sortkey end)
-- STEP 2: Merge adjacent locations with the same content.
-- Only one form is allowed: a location with multiple forms is not grouped.
function shares_content(loc1, loc2)
return #data == 1 and #data == 1
and data.display == data.display
end
local groups = {}
local current_group = {data}
for i=2, #data do
if shares_content(current_group, data) then
table.insert(current_group, data)
else
table.insert(groups, current_group)
current_group = {data}
end
end
table.insert(groups, current_group)
if data then
table.insert(groups, "")
end
return groups
end
-- gather the unique <field>s (e.g. pronunciations) for the collapsed view
local function uniques(groups, data, field)
local dedup = {}
function add_if_absent(val)
if not dedup then
table.insert(dedup,
field == "pron" and { pron = val } or val)
dedup = 1
end
end
for _, locs in ipairs(groups) do
local key = locs ~= "" and locs.text or ""
for _, term in ipairs(data) do
add_if_absent(term)
end
end
return dedup
end
-- Handles {{frp-IPA}}, the ==Pronunciation== section.
function export.show(frame)
local args = frame:getParent().args
local require_pron = true
if is_empty(args) then
args = scrape(mw.loadData("Module:headword/data").page.full_raw_pagename)
require_pron = false
end
check_groups(args)
local data = {}
gather_data(data, args, require_pron)
-- go through each lect in order
local show = {}
local hide = {}
local ref_used = {}
for _, a in ipairs(codes) do
if data and data.has_pron then
-- generate the display form and explode the locations
-- also, group by location
local processed = {}
for _, term in ipairs(data) do
if term.pron then
term.display = m_IPA.format_IPA(frp, term.pron)
.. format_ortho(term.ortho)
.. (term.ref and "<sup>" .. term.ref .. "</sup>" or "")
record_locs(processed, term, a)
if term.ref then
ref_used = true
end
end
end
-- group adjacent locs with the same form
-- however, if they have two forms, then they are not grouped
local groups = order_data(processed)
-- at this stage, "processed" should contain a list of the location groups
-- and also the terms of the locations
-- e.g. { ={Loc A}, ={Loc B, Loc C}, ={Loc D},
-- =form 3, =form 1, =form 1, ={form 4, form 2}}
local accent = format_accent(frp, {a})
table.insert(show, '* ' .. accent .. ': '
.. m_IPA.format_IPA_multiple(frp, uniques(groups, processed, "pron"), nil, 1))
table.insert(hide, '* ' .. accent)
for _, locs in ipairs(groups) do
local hide_text = "** "
local key = locs ~= "" and locs.text or ""
local terms = processed
for i, term in ipairs(terms) do
hide_text = hide_text .. term.display
-- Trails a comma if a term follows.
if i ~= #terms then hide_text = hide_text .. ", " end
end
hide_text = hide_text .. (locs ~= "" and format_locs(locs) or "")
table.insert(hide, hide_text)
end
end
end
-- reference
if args.sources or args.cf or args.note then
data.ref = require("Module:frp-IPA/ref").make_ref(args.sources, args.cf, args.note, ref_used)
else
data.ref = ""
end
return '<div class="vsSwitcher" data-toggle-category="pronunciations">'
.. '<span class="vsToggleElement"></span>'
.. '<div class="vsShow">\n'
.. table.concat(show, '\n')
.. '\n</div><div class="vsHide">\n'
.. table.concat(hide, '\n')
.. data.ref
.. '</div></div>[[Category:Franco-Provençal terms with IPA pronunciation|'
.. (frp:makeSortKey(mw.loadData("Module:headword/data").pagename)) .. ']]'
end
-- Handles {{frp-alt}}, the ==Alternative forms== section.
-- TODO: A good portion of this function is repeated from <export.show>, perhaps it can be avoided.
function export.show_alt(frame)
local args = frame:getParent().args
check_groups(args)
local data = {}
gather_data(data, args)
-- go through each lect in order
local show = {}
local hide = {}
local ref_used = {}
for _, a in ipairs(codes) do
if data and data.has_ortho then
local processed = {}
for _, term in ipairs(data) do
if term.ortho then
term.link = link(term.ortho)
term.display = term.link
.. (term.ref and "<sup>" .. term.ref .. "</sup>" or "")
record_locs(processed, term, a)
if term.ref then
ref_used = true
end
end
end
local groups = order_data(processed)
local accent = format_accent(frp, {a})
table.insert(show, accent .. ' '
.. table.concat(uniques(groups, processed, "link"), ", "))
table.insert(hide, '* ' .. accent)
for _, locs in ipairs(groups) do
local hide_text = "** "
local key = locs ~= "" and locs.text or ""
local terms = processed
for i, term in ipairs(terms) do
hide_text = hide_text .. term.display
-- Trails a comma if a term follows.
if i ~= #terms then hide_text = hide_text .. ", " end
end
hide_text = hide_text .. (locs ~= "" and format_locs(locs) or "")
table.insert(hide, hide_text)
end
end
end
-- reference
if args.sources or args.cf or args.note then
data.ref = require("Module:frp-IPA/ref").make_ref(args.sources, nil, nil, ref_used)
else
data.ref = ""
end
return '<div class="vsSwitcher" data-toggle-category="alternative forms">'
.. '<span class="vsToggleElement"></span>'
.. '<div class="vsShow">\n'
.. '* ' .. table.concat(show, '; ')
.. '\n</div><div class="vsHide">\n'
.. table.concat(hide, '\n')
.. data.ref
.. '</div></div>'
end
-- Handles {{frp-altform}}, the alternative form's entry definition line.
function export.show_altform(frame)
local args = frame:getParent().args
local allowed_para = { = true, = true }
local ns = mw.loadData("Module:headword/data").page.namespace
if ns == "Template" then
allowed_para.pagename = true
end
for key, _ in pairs(args) do
if not allowed_para then
error("Parameter " .. key .. " not used by this template.")
end
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local lemma_args = scrape(args)
local data = {}
gather_data(data, lemma_args)
local locs = {}
local loc_text
local seen
for _, a in ipairs(codes) do
if data then
local sublocs = {}
for _, term in ipairs(data) do
if term.ortho == pagename then
seen = true
if term.locs then
for _, subloc in ipairs(parse_locs(a, term.locs)) do
table.insert(sublocs, subloc)
end
end
end
end
if #sublocs > 0 then
table.sort(sublocs, function(a, b) return a.sortkey < b.sortkey end)
table.insert(locs, format_locs(sublocs, true))
end
end
end
if not seen then
error("Gathering localities failed. Please specify manually.")
end
if #locs > 0 then
loc_text = " documented in the following location(s): " .. table.concat(locs, "; ")
end
return m_form_of.format_form_of {
lemma_face = "term",
lemmas = { { lang = frp, term = args, gloss = args } },
text = "Alternative form of",
posttext = loc_text
}
end
return export