Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:IPA/sandbox

From Wikipedia, the free encyclopedia
require('strict')
local p = {}

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

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

local function wrapAtSpacesSafely(s)
	local patterns = {
		'%[%[[^%]|]-%s[^%]|]-|', -- Piped links
		'</?[A-Za-z][^>]-%s[^>]->' -- HTML tags
	}
	s = mw.ustring.gsub(s, '%[%[([^%]|]-%s[^%]|]-)%]%]', '[[%1|%1]]') -- Pipe all links
	local t = {}
	local init
	while true do
		local i, j = multiFind(s, patterns, init)
		if not i then
			break
		end
		local pre = wrapAtSpaces(mw.ustring.sub(s, init, i - 1)) -- What precedes the match
		table.insert(t, pre)
		table.insert(t, mw.ustring.sub(s, i, j)) -- The match
		init = j + 1
	end
	local post = wrapAtSpaces(mw.ustring.sub(s, init)) -- What follows the last match
	table.insert(t, post)
	return table.concat(t)
end

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

local function renderCats(cats, isDebug)
	if not cats[1] or not checkNamespace(isDebug) then
		return ''
	end
	local t = {}
	for _, v in ipairs(cats) do
		table.insert(t, string.format(
			'[[%sCategory:%s]]',
			isDebug and ':' or '',
			v
		))
	end
	return table.concat(t)
end

local function resolveSynonym(s)
	return mw.loadData('Module:Lang/ISO 639 synonyms')[s] or s
end

local function splitTag(s)
	local langCode = s:gsub('%-.*', ''):lower()
	langCode = resolveSynonym(langCode)
	local regionCode = s:match('%-(.+)')
	local isPrivate = regionCode and regionCode:sub(1, 2) == 'x-'
	if regionCode and not isPrivate and #regionCode < 4 then
		regionCode = regionCode:upper()
	end
	return langCode, regionCode, isPrivate
end

local function getLangName(code, link, raw)
	return require('Module:Lang')._name_from_tag({
		code,
		link = link,
		raw = raw,
		-- Without linking, "{{IPA}}" gets expanded in some contexts
		template = '[[Template:IPA|IPA]]'
	})
end

local function linkLang(name, target, link)
	return link == 'yes' and string.format(
		'[[%s|%s]]',
		target or name .. ' language',
		name
	) or name
end

function p._main(args)
	local ret, cats = {}, {}
	local isDebug = args.debug == 'yes'
	local s, langCode, regionCode, isPrivate
	
	-- Guide-linking mode
	if args[2] and args[2] ~= '' then
		local data = mw.loadData('Module:IPA/data/sandbox')
		local isGeneric = args.generic == 'yes'
		s = args[2]
		langCode, regionCode, isPrivate = splitTag(args[1])
		local langData = data.langs[langCode] or {}
		if regionCode then
			if langData.dialects and langData.dialects[regionCode] then
				-- Overwrite language data with the dialect's
				local newLangData = {}
				for k, v in pairs(langData) do
					if k ~= 'dialects' then
						newLangData[k] = v
					end
				end
				local dialectData = langData.dialects[regionCode]
				if dialectData.aliasOf then
					-- Use the canonical region code
					regionCode = dialectData.aliasOf
					isPrivate = regionCode:sub(1, 2) == 'x-'
					dialectData = langData.dialects[regionCode]
				end
				-- Lowercase IANA variant
				if dialectData.isVariant then
					regionCode = regionCode:lower()
				end
				for k, v in pairs(dialectData) do
					newLangData[k] = v
				end
				langData = newLangData
			else
				isGeneric = true
			end
		end
		
		local fullLangCode = regionCode and langCode .. '-' .. regionCode
			or langCode
		local langName = langData.name
			and linkLang(langData.name, langData.link, args.link)
			or getLangName(fullLangCode, args.link)
		if langName:sub(1, 5) == '<span' then
			-- Module:Lang has returned an error
			return langName .. renderCats({ 'IPA template errors' }, isDebug)
		end
		if args.cat ~= 'no' then
			local catLangName = langData.name
				or getLangName(fullLangCode, nil, 'yes')
			if catLangName:sub(1, 5) == '<span' then
				-- Module:Lang has returned an error, but it's not fatal
				table.insert(cats, 'IPA template errors')
				mw.addWarning(catLangName)
			else
				table.insert(cats, string.format('Pages with %s IPA', catLangName))
			end
		end
		
		-- Label
		local label = args.label
		if not label then
			local labelCode = args[3] and args[3]:lower()
				or langData.defaultLabelCode
			if labelCode == '' then
				label = ''
			else
				local langText
				if langData.text then
					langText = linkLang(
						langData.text,
						mw.ustring.match(langName, '^%[%[([^|%]]+)'),
						args.link
					)
				else
					langText = mw.ustring.gsub(
						langName,
						'^%[%[(([^|]+) languages)%]%]$',
						'[[%1|%2]]'
					)
					langText = mw.ustring.gsub(
						langText,
						' languages(%]?%]?)$',
						'%1'
					)
				end
				if labelCode and data.labels[labelCode] then
					label = data.labels[labelCode]:format(langText)
				else
					label = data.defaultLabel:format(langText)
				end
			end
		end
		if label and label ~= '' then
			local span = mw.html.create('span')
				:addClass('IPA-label')
				:wikitext(label)
			if args.small ~= 'no' then
				span:addClass('IPA-label-small')
				table.insert(ret, mw.getCurrentFrame():extensionTag({
					name = 'templatestyles',
					args = { src = 'Module:IPA/sandbox/styles.css' }
				}))
			end
			table.insert(ret, tostring(span) .. ' ')
		end
		
		-- Brackets
		s = (not isGeneric and langData.format or '&#91;%s&#93;'):format(s)
		
		-- Link to key
		local key = not isGeneric and langData.key or data.defaultKey
		s = string.format('[[%s|%s]]', key, s)
	else
		-- Basic mode
		s = args[1]
		if args.lang and args.lang ~= '' then
			langCode, regionCode, isPrivate = splitTag(args.lang)
		end
		if args.cat ~= 'no' then
			table.insert(cats, 'Pages with plain IPA')
		end
	end
	
	-- Transcription
	do
		local lang = (langCode or 'und') .. '-Latn'
		if not isPrivate and regionCode then
			lang = lang .. '-' .. regionCode
		end
		lang = lang .. '-fonipa'
		local span = mw.html.create('span')
			:addClass('IPA')
			:addClass(args.class)
			:attr('lang', lang)
		-- 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 = wrapAtSpacesSafely(s)
			end
		end
		if (not args[2] or args[2] == '') and args.tooltip ~= '' then
			local tooltip = args.tooltip or
				'Representation in the International Phonetic Alphabet (IPA)'
			span:attr('title', tooltip)
		end
		s = tostring(span:wikitext(s))
		table.insert(ret, s)
	end
	
	-- Audio
	local audio = args.audio ~= '' and args.audio or args[4] ~= '' and args[4]
	if audio then
		local button = mw.getCurrentFrame():expandTemplate({
			title = 'Audio',
			args = { audio, '' }
		})
		table.insert(ret, ' ' .. button)
		table.insert(cats, 'Pages including recorded pronunciations')
	end
	
	-- Categories
	table.insert(ret, renderCats(cats, isDebug))
	
	return table.concat(ret)
end

function p.main(frame)
	local args = frame:getParent().args
	if not args[1] then
		return ''
	end
	for i, v in ipairs(args) do
		args[i] = mw.text.trim(v)
	end
	return p._main(args)
end

return p