Module:Nomenclature: Difference between revisions

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
(Prevent duplicate refs as seen in the Simplified Chinese name of Bomb, as reported by JumbledLimes on Discord earlier today)
(Previous bugfix for multiple usages was causing script errors if a term was used; using supplied term as a workaround so that module now works if used multiple times (unless multiple usages use the same term but that shouldn't happen))
Line 152: Line 152:
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
if frame:getParent().args[1] then
if frame:getParent().args[1] then
-- this functionality doesn't work if Nomenclature is used multiple times per page
-- workaround if Nomenclature is used multiple times per page
return
local subject = frame.args["term"]
return frame:extensionTag({
name = "ref",
args = { name = refNamePrefix..subject..'-'..citationIndex },
content = refContent,
})
end
end
return frame:extensionTag({
return frame:extensionTag({

Revision as of 16:16, 24 June 2023

This is the main module for Template:Nomenclature.


local p = {}
local h = {}

local Franchise = require("Module:Franchise")
local Language = require("Module:Language")
local Term = require("Module:Term")
local utilsCargo = require("Module:UtilsCargo")
local utilsTable = require('Module:UtilsTable')

local DISCORD_URL = require("Module:Constants/url/discord")

-- temporary to remove {{Names}}
function p.HasTranslationsStored(frame)
	local term = frame.args["term"]
	if term == nil or term == "" then
		term = mw.title.getCurrentTitle().subpageText
	end
	if #h.fetchTranslations(term) > 0 then
		return true
	else
		return false
	end
end

-- For creating nomenclature tables
function p.Main(frame)
	local subject = frame.args["term"]
	if subject == nil or subject == "" then
		subject = mw.title.getCurrentTitle().subpageText
	end
	
	local translations = h.fetchTranslations(subject)
	local translations, hasMeanings, displayGames = h.formatData(translations)
	local nomenclatureTable = h.printNomenclatureTable(translations, hasMeanings, displayGames)
	
	return nomenclatureTable
end

function h.fetchTranslations(page)
	local whereClause = utilsCargo.allOf({
    	subject = page
	})
	-- Fetch translations of synonyms
	local term = Term.fetchTerm(page)
	if term and not string.find(page, "%)$") then -- without this ) check, Wood (Character) would also fetch data for BotW Wood
		term = string.gsub(term, "#", "") -- terms with # in them are stored in a version of the page without the #, because MediaWiki. Also Cargo doesn't allow queries with # in them.
		whereClause = whereClause .. " OR " ..utilsCargo.allOf({
	    	term = term
		}, "subject NOT LIKE '%)'") -- without this, requesting "Wood" would also fetch data for Wood (Character)
	end
	local translations = utilsCargo.query("Translations", "game, term, lang, translation, meaning, ref", {
		where = whereClause
	})
	
	return translations
end

function h.formatData(translations)
	local hasMeanings = utilsTable.find(translations, function(translation)
		return translation.meaning == nil and translation.meaning ~= "" and translation.term ~= translation.translation
	end)
	
	-- Determine whether to display Exp Game
	local seenGames = {}
	local gameCount = 0
	local hasRemakes = false
	for i, translation in ipairs(translations) do
		local game = translation.game
		if not seenGames[game] then
			gameCount = gameCount + 1
			seenGames[game] = true
		end
		if Franchise.isRemake(game) or Franchise.hasRemakes(game) then
			hasRemakes = true
		end
	end
	local displayGames = gameCount > 1 or hasRemakes
	
	-- Group translations by language and then by name
	local gameOrderLookup = utilsTable.invert(Franchise.enum())
	translations = utilsTable.sortBy(translations, function(translation)
		return gameOrderLookup[translation.game] or 1000
	end)
	translations = utilsTable.groupBy(translations, "lang")
	translations = utilsTable.mapValues(translations, utilsTable._groupBy("translation"))
	
	-- Creates a list of unique translations grouped by language
	-- For each unique translation, lists which games have that translation, assigns a meaning to it, and creates the refs
	-- If multiple games have different meanings for the same translation, we use the latest game
	local hasMeanings = false
	local translationLists = {}
	for lang, langTranslations in pairs(translations) do
		local translationList = {}
		for translation, translationGames in pairs(langTranslations) do
			local translationListItem = {
				translation = translation,
				games = {},
				meaning = " ",
				term = translationGames[1].term,
				refs = "",
			}
			for i, translationGame in ipairs(translationGames) do
				local meaning = translationGame.meaning
				if meaning ~= nil and meaning ~= "" then
					translationListItem.meaning = meaning
					hasMeanings = true
				end
				table.insert(translationListItem.games, translationGame.game)
				translationListItem.refs = translationListItem.refs..h.printRef(translation, translationGame.ref)
			end
			table.insert(translationList, translationListItem)
		end
		-- Sort translations by their earliest appearance
		translationList = utilsTable.sortBy(translationList, function(translation)
			return gameOrderLookup[translation.games[1]]
		end)
		translationLists[lang] = translationList
	end
	return translationLists, hasMeanings, displayGames
end

local refCount = 0
local refNamePrefix = "nomenclature-"
local seenCitations = {} -- to prevent duplicate citations in the ==References== section on the page 
local seenRefs = {} -- to prevent duplicate reference markers in a given Nomenclature table row (e.g. [[Bomb]] Simplified Chinese)
function h.printRef(translation, citation)
	if citation == nil or citation == "" then
		return ""
	end
	seenRefs[translation] = seenRefs[translation] or {}
	local refSeen = seenRefs[translation][citation]
	local citationIndex = seenCitations[citation]
	
	local refContent
	if refSeen then
		 -- Do nothing, the ref is already being shown for this translation due to it being the same in multiple games 
		 -- (happens when the source is a book like E)
		return ""
	elseif citationIndex then
		-- refContent stays nil since we're re-using an existing ref
		refContent = nil
		seenRefs[translation][citation] = true 
	else
		-- create a new ref
		refCount = refCount + 1
		citationIndex = refCount
		refContent = citation
		seenCitations[citation] = citationIndex
		seenRefs[translation][citation] = true 
	end
	
	local frame = mw.getCurrentFrame()
	if frame:getParent().args[1] then
		-- workaround if Nomenclature is used multiple times per page
		local subject = frame.args["term"]
		return frame:extensionTag({
		name = "ref",
		args = { name = refNamePrefix..subject..'-'..citationIndex },
		content = refContent,
	})
	end
	return frame:extensionTag({
		name = "ref",
		args = { name = refNamePrefix..citationIndex },
		content = refContent,
	})
end

function h.printNomenclatureTable(translationsByLang, hasMeanings, displayGames)
	local html = mw.html.create("table")
		:addClass("wikitable")
		:tag("tr")
			:tag("th")
				:addClass("nomenclature__header")
				:attr("colspan", hasMeanings and 3 or 2)
				:wikitext("[[File:ZW Nomenclature Asset.png|20px|link=]] Names in Other Regions [[File:ZW Nomenclature Asset 2.png|link=]]")
				:done()
			:done()
		:done()
	
	local columns = html:tag("tr")
	columns:tag("th"):wikitext("Language")
	columns:tag("th"):wikitext("Names")
	if hasMeanings then
		columns:tag("th"):wikitext("Meanings")
	end
	
	for i, lang in ipairs(Language.enum()) do
		local translations = translationsByLang[lang]
		if translations then
			h.addRow(html, hasMeanings, displayGames, lang, translations)
		end
	end
	
	local footerText = mw.getCurrentFrame():preprocess("<small>This table was generated using [[Data:Translations|translation pages]].<br>To request an addition, please {{Discord|contact|plainlink= true}} a [[Zelda Wiki:Staff|staff member]] with a [[Guidelines:References|reference]].</small>")
	html:tag("tr")
		:tag("th")
		:attr("colspan", "3")
		:wikitext(footerText)
	
	return tostring(html:allDone())		
end

function h.addRow(html, hasMeanings, displayGames, lang, translations)
	local row = html:tag("tr")
	local langCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--language")
	local nameCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--name")
	local meaningCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--meanings")
	
	local lect = Language.getLect(lang)
	langCell:tag("div")
		:addClass("nomenclature__language")
		:tag("div")
			:addClass("nomenclature__language-flags")
			:wikitext(unpack(lect.flags))
			:done()
		:tag("div")
			:addClass("nomenclature__language-name")
			:wikitext(lect.abbr)
			:done()
		:done()
	
	local names = {}
	local meanings = {}
	for i, translation in ipairs(translations) do
		names[i] = h.printTranslationName(translation, displayGames)..translation.refs
		meanings[i] = translation.meaning
	end
	
	names = #names == 1 and names[1] or h.list(names)
	meanings = #meanings == 1 and meanings[1] or h.list(meanings)
	
	nameCell:wikitext(names)
	meaningCell:wikitext(meanings)
	
	-- When the foreign name is the exact same as the NoA name (see TotK page for example)
	if #translations == 1 and translations[1].translation == translations[1].term then
		nameCell:attr("colspan", 2)
		meaningCell = nil
	end

	row:node(langCell)
	row:node(nameCell)
	if hasMeanings and meaningCell then
		row:node(meaningCell)
	end
end

function h.printTranslationName(translationData, displayGames)
	local result = translationData.translation
	if displayGames then
		result = result .. " " .. mw.getCurrentFrame():expandTemplate({
			title = "Exp Game",
			args = {table.concat(translationData.games, ", ")}
		})
	end
	return result
end

function h.list(items)
	local list = mw.html.create("ul"):addClass("plainlist")
	for i, item in ipairs(items) do
		list:tag("li"):wikitext(item)
	end
	return tostring(list)
end

return p