Module:Sandbox/Nardog/5

Revision as of 21:07, 23 October 2022 by imported>Legoktm (Replace Module:No globals with require( "strict" ))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:Sandbox/Nardog/5/doc

require('strict')
local p = {}

local function multiFind(s, t)
	local i, j = mw.ustring.find(s, t[1])
	for n = 2, #t do
		local i2, j2 = mw.ustring.find(s, t[n])
		if i2 and (not i or i2 < i) then
			i, j = i2, j2
		end
	end
	return i, j
end

local function wrapSpaces(s)
	return mw.ustring.gsub(s, '(%s+)', '<span class="wrap">%1</span>')
end

local function escapeAndWrapSpaces(s)
	local patterns = {
		'%[%[[^%]|]-%s[^%]|]-|', -- Piped links
		'</?[A-Za-z][^>]-%s[^>]->' -- HTML tags
	}
	s = mw.ustring.gsub(s, '%[%[([^%]|]-%s[^%]|]-)%]%]', '[[%1|%1]]') -- Pipe unpiped links
	local i, j = multiFind(s, patterns)
	if i then -- Match found
		local remaining, escaped = {}, {}
		repeat
			table.insert(remaining, mw.ustring.sub(s, 1, i - 1)) -- What precedes the match
			table.insert(escaped, mw.ustring.sub(s, i, j)) -- The match
			s = mw.ustring.sub(s, j + 1) -- Truncate
			i, j = multiFind(s, patterns)
		until not i
		table.insert(remaining, s) -- What follows the last match
		s = {}
		for k, v in ipairs(remaining) do
			v = wrapSpaces(v)
			table.insert(s, v)
			table.insert(s, escaped[k])
		end
		s = table.concat(s)
	else
		s = wrapSpaces(s)
	end
	return s
end

local function checkNamespace()
	return require('Module:Category handler').main{ true }
end

local function renderCats(cats)
	local s = ''
	if cats and cats[1] and checkNamespace() then
		s = {}
		for _, v in ipairs(cats) do
			table.insert(s, '[[Category:' .. v .. ']]')
		end
		s = table.concat(s)
	end
	return s
end

local function renderError(s)
	return '<span class="error">' .. s .. '</span>' ..
		renderCats({ 'IPA template errors' })
end

function p._main(args, isConv)
	local function resolveSynonym(s)
		s = s:lower()
		return mw.loadData('Module:Lang/ISO 639 synonyms')[s] or s
	end
	local function getLangName(s)
		return require('Module:Lang')._name_from_tag({ s, link = args.link, template = 'IPA' })
	end
	local function makeLink(s, target)
		return args.link == 'yes'
			and string.format('[[%s%s]]', target and target .. '|' or '', s)
			or s
	end
	local function makeSmallText(s)
		if args.small == 'no' then -- Defaults to yes
			return s
		end
		local span = mw.html.create('span')
			:css('font-size', '85%')
			:wikitext(s)
		return tostring(span)
	end
	
	local ret, cats = {}, {}
	local s, label, langCode
	if args[2] then
		local data = mw.loadData('Module:Sandbox/Nardog/5d')
		
		local convArgs
		if isConv then
			convArgs = mw.clone(args)
			table.remove(convArgs, 1)
		else
			s = args[2]
		end
		
		langCode = resolveSynonym(args[1])
		local langData = data.langs[langCode]
		local langName = langData and langData.name
		langName = langName and makeLink(langName, langData.link)
			or getLangName(langCode, args.link)
		local key = langData and langData.key or data.defKey
		label = args.label
		if langName:sub(1, 5) == '<span' then
			return langName .. renderCats({ 'IPA template errors' })
		elseif not label then
			local function returnLabel()
				local labelCode = isConv and args[2] or args[3]
				if labelCode then
					if labelCode == '' then
						return ''
					end
					local customCodes = langData and langData.labels
					if customCodes and customCodes[labelCode] then
						return customCodes[labelCode]
					end
					local dialects = langData and langData.dialects
					if dialects then
						for codePat, labelPat in pairs(data.defDiaCodes) do
							for diaCode, diaName in pairs(dialects) do
								if labelCode == codePat:format(diaCode) then
									return labelPat:format(makeLink(
										diaName, dialects[diaCode .. '-link']))
								end
							end
						end
					end
					local defLabelMatch = data.defLabels[labelCode]
					if defLabelMatch then
						return defLabelMatch:format(langName)
					end
				end
			end
			label = returnLabel()
			if label then
				if isConv then
					table.remove(convArgs, 1)
				end
			else
				local defLabel = langData and langData.defLabel or data.defLabel
				label = defLabel:format(langName)
			end
		end
		if label and label ~= '' then
			label = makeSmallText(label) or label
			table.insert(ret, label .. ' ')
		end
		
		if isConv then
			local module = langData and langData.convModule
			if module then
				local hasError
				s, hasError = require(module).main(convArgs)
				if hasError then
					local errorCat = langData.convErrorCat
					if errorCat then
						table.insert(cats, errorCat)
					end
				end
				if langData.convArgs then
					for k, v in pairs (langData.convArgs) do
						args[k] = args[k] or v
					end
				end
				if langData.convStyles then
					table.insert(ret, 1, mw.getCurrentFrame():extensionTag{
						name = 'templatestyles',
						args = { src = langData.convStyles }
					})
				end
			else
				return renderError('IPA convert module not found for \'' .. langCode .. '\'')
			end
		end
		s = langData and langData.slashes and '/' .. s .. '/' or '[' .. s .. ']'
		s = string.format('[[%s|%s]]', key, s)
		if langData.iso then
			langCode = langData.iso ~= 'none' and langData.iso
		end
	else
		s = args[1]
	end
	
	-- Transcription
	do
		local span = mw.html.create('span')
			:attr('lang', (langCode or 'und') .. '-fonipa')
			:addClass('IPA')
			:addClass(args.class)
		-- wrap=all: Do nothing
		-- wrap=none: Never break
		-- Otherwise: Break at spaces only
		if args.wrap ~= 'all' then
			span:addClass('nowrap')
			if args.wrap ~= 'none' then
				s = escapeAndWrapSpaces(s)
			end
		end
		if not args[2] and args.tooltip ~= '' then -- tooltip is added unless blank
			span:attr('title', args.tooltip or
				'Representation in the International Phonetic Alphabet (IPA)')
		end
		s = tostring(span:wikitext(s))
		table.insert(ret, s)
	end
	
	-- Audio
	local audio = args.audio ~= '' and args.audio or not isConv and args[4] ~= '' and args[4]
	if audio then
		audio = '(' .. mw.getCurrentFrame():expandTemplate{
			title = 'Template:Audio',
			args = { audio, 'listen', help = 'no' }
		} .. ')'
		audio = makeSmallText(audio) or audio
		table.insert(ret, ' ' .. audio)
		table.insert(cats, 'Pages including recorded pronunciations')
	end
	
	-- Categories
	table.insert(ret, renderCats(cats))
	
	return table.concat(ret)
end

function p.main(frame)
	-- local args = frame:getParent().args
	local args = frame.args[1] and frame.args or frame:getParent().args
	for i, v in ipairs(args) do
		local s = mw.text.trim(v)
		args[i] = (s ~= '' or i == 3) and s
	end
	return args[1] and p._main(args)
end

function p._convert(args)
	return p._main(args, true)
end

function p.convert(frame)
	local args = {}
	-- for i, v in ipairs(frame:getParent().args) do
	for i, v in ipairs(frame.args[1] and frame.args or frame:getParent().args) do
		local s = mw.text.trim(v)
		if s ~= '' or i == 2 then
			table.insert(args, s)
		end
	end
	-- for k, v in pairs(frame:getParent().args) do
	for k, v in pairs(frame.args[1] and frame.args or frame:getParent().args) do
		if type(k) == 'string' then
			args[k] = v
		end
	end
	return args[1] and args[2] and p._convert(args)
end

return p