Module:Auto cat

From Multilingual Bookbinding Dictionary
Jump to navigation Jump to search

Documentation for this module may be created at Module:Auto cat/doc

local export = {}


local function splitLabelLang(titleObject)
	local words = mw.text.split(titleObject.text, " ", true)
	local getByCanonicalName = require("Module:languages").getByCanonicalName
	local lang
	
	-- Progressively remove words from the end of the category name until it matches a language.
	while words[1] and not lang do
		words[#words] = nil
		lang = getByCanonicalName(table.concat(words, " "))
	end
	
	local label = (lang and titleObject.text:sub(#(lang:getCanonicalName() .. " ") + 1) or titleObject.text)
	
	return label, lang
end


local function getObj(name, family)
	if not family then
		return require("Module:etymology languages").getByCanonicalName(name)
			or require("Module:languages").getByCanonicalName(name)
	else
		return require("Module:families").getByCanonicalName(name)
	end
end


-- List of handler functions that try to match the page name.
-- A handler should return a table of template title plus arguments
-- that is passed to frame:expandTemplate.
-- If a handler does not recognise the page name, it should return nil.
-- Note that the order of functions matters!

local handlers = {}


-- Topical categories
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("^[a-z-]+:.") then
		return nil
	end
	
	local code, label = titleObject.text:match("^([a-z-]+):(.+)$")
	return {title = "topic cat", args = {code, label}}
end)
local topic_cat_with_lang = handlers[#handlers]


--[[	langcatboiler
		Shouldn't be used because there are additional parameters, such as
		countries where that the language is or was spoken,
		that should always be supplied. --]]

table.insert(handlers, function(titleObject)
	if not titleObject.text:find("[lL]anguage$") then
		return nil
	end
	
	local langName = titleObject.text:match("^(.+) language$")
	
	-- Use the entire category name if it doesn't end in "language", to handle
	-- cases where "language" is part of the name, e.g. ASL.
	local lang = require("Module:languages").getByCanonicalName(langName) or require("Module:languages").getByCanonicalName(titleObject.text)
	
	if not lang then
		local lang2 = require("Module:languages").getByName(langName)
		if lang2 then
			error('"' .. langName .. '" is not a valid canonical name. Use "' .. lang2:getCanonicalName() .. '" instead.')
		end
		
		return nil
	end
	
	return { title = "langcatboiler", args = { lang:getCode() } }
end)


-- Letter names
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("letter names$") then
		return nil
	end
	
	local langCode = titleObject.text:match("^([^:]+):")
	local lang, cat
	
	if langCode then
		lang = require("Module:languages").getByCode(langCode) or error('The language code "' .. langCode .. '" is not valid.')
		cat = titleObject.text:match(":(.+)$")
	else
		cat = titleObject.text
	end
	
	return {title = "topic cat", args = {lang and lang:getCode() or nil, cat}}
end)


-- letter cat
table.insert(handlers, function(titleObject)
	if not (mw.ustring.len(titleObject.text) <= 3
			or mw.ustring.len(titleObject.text) <= 6 and titleObject.text:find(":", 1, true)) then
		return nil
	end
	
	return {title = "letter cat"}
end)


-- Japanese kanji reading cat
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("^Japanese kanji") then
		return nil
	end
	
	return {title = "ja-readings-cat"}
end)


-- Unicode block cat
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("block$") then
		return nil
	end
	
	return {title = "Unicode block cat"}
end)


-- request cat
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("^Requests") then
		return nil
	end
	
	return {title = "request cat"}
end)


-- PIE root cat
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("[Tt]erms derived from the (.+) root") then
		return nil
	end
	
	return {title = "PIE root cat"}
end)


-- PIE word cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[tT]erms derived from the PIE word %*") then
		return nil
	end
	
	local word = label:match("^[Tt]erms derived from the PIE word %*(.+)$")
	return {title = "PIE word cat", args = {lang and lang:getCode() or nil, word}}
end)


-- ar-root cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not (lang and lang:getCode() == "ar" and label:find("^terms belonging to the root .+")) then
		return nil
	end
	
	return {title = "ar-root cat"}
end)


--HE root cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not (lang and lang:getCode() == "he" and label:find("^terms belonging to the root .+")) then
		return nil
	end
	
	local root = label:match("^terms belonging to the root (.+)$")
	local parts = mw.text.split(root, "־", true)
	return {title = "HE root cat", args = parts}
end)


-- he-patterncat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not (lang and lang:getCode() == "he" and label:find("^terms in the pattern .+")) then
		return nil
	end
	
	return {title = "he-patterncat"}
end)


-- derived cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Tt]erms derived from .") then
		return nil
	end
	
	local sourcename = label:match("^[Tt]erms derived from (.+)$")
	local source
	
	if sourcename:find(" [Ll]anguages$") then
		sourcename = sourcename:gsub(" languages$", "")
		source = getObj(sourcename, true)
	else
		source = getObj(sourcename)
	end
	
	if source then
		return {title = "derived cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)


-- inherited cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Tt]erms inherited from .") then
		return nil
	end
	
	local sourcename = label:match("^[Tt]erms inherited from (.+)$")
	local source = getObj(sourcename)
	
	if source then
		return {title = "inherited cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)


-- borrowed cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Tt]erms borrowed from .") then
		return nil
	end
	
	local sourcename = label:match("^[Tt]erms borrowed from (.+)$")
	local source
	
	if sourcename:find(" [Ll]anguages$") then
		sourcename = sourcename:gsub(" languages$", "")
		source = getObj(sourcename, true)
	else
		source = getObj(sourcename)
	end
	
	if source then
		return {title = "borrowed cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)


-- unadapted borrowing cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Uu]nadapted borrowings from .") then
		return nil
	end
	
	local sourcename = label:match("^[Uu]nadapted borrowings from (.+)$")
	local source
	
	if sourcename:find(" [Ll]anguages$") then
		sourcename = sourcename:gsub(" languages$", "")
		source = getObj(sourcename, true)
	else
		source = getObj(sourcename)
	end
	
	if source then
		return {title = "unadapted borrowing cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)


-- calque cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Tt]erms calqued from .") then
		return nil
	end
	
	local sourcename = label:match("^[Tt]erms calqued from (.+)$")
	local source
	
	if sourcename:find(" [Ll]anguages$") then
		sourcename = sourcename:gsub(" languages$", "")
		source = getObj(sourcename, true)
	else
		source = getObj(sourcename)
	end
	
	if source then
		return {title = "calque cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)

-- semantic loan cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Ss]emantic loans from .") then
		return nil
	end
	
	local sourcename = label:match("^[Ss]emantic loans from (.+)$")
	local source
	
	if sourcename:find(" [Ll]anguages$") then
		sourcename = sourcename:gsub(" languages$", "")
		source = getObj(sourcename, true)
	else
		source = getObj(sourcename)
	end
	
	if source then
		return {title = "semantic loan cat", args = {lang and lang:getCode() or nil, source:getCode()}}
	end
end)

-- translitcatboiler
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^terms transliterated from other languages") then
		return nil
	end
	
	return {title = "translitcatboiler", args = {lang and lang:getCode() or nil}}
end)


-- translitcatboiler
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^[Tt]ransliterations of") then
		return nil
	end
	
	local sourcename = label:match("[Tt]ransliterations of (.+) terms")
	local source = getObj(sourcename)
	
	if not lang then
		local lang = ""
	end
	
	if source then
		return {title = "translitcatboiler", args = {lang and lang:getCode(), source:getCode()}}
	end
end)


-- circumfixcat, infixcat, interfixcat, prefixcat, suffixcat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	for _, affixtype in ipairs({"circumfix", "infix", "interfix", "prefix", "suffix"}) do
		if label:find("^.+ " .. affixtype .. "ed with .") then
			local pos, after = label:match("^(.+) " .. affixtype .. "ed with (.+)$")
			
			if pos == "words" then
				pos = nil
			end
			
			local term, id
			
			if after:find(". %([^()]+%)$") then
				term, id = after:match("^(.+) %(([^()]+)%)$")
			else
				term = after
			end
			
			return {title = affixtype .. "cat", args = {lang:getCode(), term, pos = pos, id = id}}
		end
	end
end)


table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not lang then
		return nil
	end
	
	for _, nametype in ipairs({"surnames", "male given names", "female given names"}) do
		local sourcename = label:match("^" .. nametype .. " from (.+)$")
		
		if sourcename then
			local source = require("Module:languages").getByCanonicalName(sourcename)
			
			if source then
				return {title = "nameboiler", args = {nametype, lang:getCode(), source:getCode()}}
			end
		end
	end
end)


-- charactercat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^terms spelled with .+") then
		return nil
	end
	
	local term = label:match("^terms spelled with (.+)$")
	return {title = "charactercat", args = {lang:getCode(), term}}
end)


-- pbcatboiler
table.insert(handlers, function(titleObject)
	if titleObject.text == "Phrasebooks by language" then
		return {title = "pbcatboiler", args = {}}
	else
		local label, lang = splitLabelLang(titleObject)
		
		if label == "phrasebook" then
			return {title = "pbcatboiler", args = {lang:getCode()}}
		elseif label:find("^phrasebook/.") then
			label = label:match("^phrasebook/(.+)$")
			return {title = "pbcatboiler", args = {lang:getCode(), label}}
		end
	end
end)

-- no entry cat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("entries that don't exist$") then
		return nil
	end
	
	return { title = "no entry cat", args = { lang:getCode() } }
end)

-- poscatboiler
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if lang then
		return {title = "poscatboiler", args = {lang:getCode(), label}}
	elseif label:find(". by language$") then
		local label = mw.getContentLanguage():lcfirst(label:match("^(.+) by language$"))
		return {title = "poscatboiler", args = {nil, label}}
	end
end)


--[[	famcatboiler
		
		Must go after the "derived", "borrowed", "transliterated", and poscatboiler
		category handlers, which sometimes have "languages" at the end.
]]
table.insert(handlers, function(titleObject)
	if not titleObject.text:find("languages$") then
		return nil
	end
	
	local familyName = titleObject.text:match("^(.+) languages$")
	
	local family = require("Module:families").getByCanonicalName(familyName) or
		require("Module:families").getByCanonicalName(mw.ustring.lower(familyName))
	
	if not family then
		return nil
	end
	
	return { title = "famcatboiler", args = { family:getCode() } }
end)


-- trredcat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^Terms with redundant transliterations") then
		return nil
	end
	
	langCode = label:match("/(.+)")
	
	if langCode then
		return {title = "trredcat", args = {langCode}}
	end
end)


-- trmandiffcat
table.insert(handlers, function(titleObject)
	local label, lang = splitLabelLang(titleObject)
	
	if not label:find("^Terms with manual transliterations different from the automated ones") then
		return nil
	end
	
	local langCode = label:match("/(.+)")
	
	if langCode then
		return {title = "trmandiffcat", args = {langCode}}
	end
end)


-- topic cat
table.insert(handlers, function(titleObject)
	return {title = "topic cat", args = {nil, titleObject.text}}
end)
local topic_cat_without_lang = handlers[#handlers]


function export.show(frame)
	local args = require("Module:parameters").process(frame:getParent().args, {
		nopos = { type = "boolean" },
	})
	local titleObject = mw.title.getCurrentTitle()
	
	if titleObject.nsText == "Template" then
		return "(This template should be used on pages in the Category: namespace.)"
	elseif titleObject.nsText ~= "Category" then
		error("This template/module can only be used on pages in the Category: namespace.")
	end
	
	-- Will the topic_cat handlers correctly handle "letter names" categories?
	for _, handler in ipairs(args.nopos and { topic_cat_with_lang, topic_cat_without_lang } or handlers) do
		local templateObject = handler(titleObject)
		
		if templateObject then
			require("Module:debug").track("auto cat/" .. templateObject.title)
			return frame:expandTemplate(templateObject)
		end
	end
end

-- test function for injecting title string
function export.test(title)
	if type(title) == "table" then
		title = title:getParent().args[1]
	end
	
	local titleObject = {}
	titleObject.text = title
	
	for _, handler in ipairs(handlers) do
		local t = handler(titleObject)
		
		if t then
			return t.title
		end
	end	
end

return export