Module:Nomenclature: Difference between revisions

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
No edit summary
mNo edit summary
 
(91 intermediate revisions by 6 users not shown)
Line 1: Line 1:
local cargo = mw.ext.cargo
local expgame = require('Module:Exp Game')
local tab2 = require('Module:Tab2')
local term = require('Module:Term')
local translation = require('Module:Translation')
local utilsCode = require('Module:UtilsCode')
local utilsGame = require('Module:UtilsGame')
local utilsLanguage = require('Module:UtilsLanguage')
local utilsTable = require('Module:UtilsTable')
local utilsText = require('Module:UtilsText')
local p = {}
local p = {}
local h = {}
local h = {}


-- For creating nomenclature tables
local Franchise = require("Module:Franchise")
function p.Main( frame )
local Language = require("Module:Language")
local cargoData = translation.fetchTranslations(frame.args["term"])
local Term = require("Module:Term")
local skipMeanings = true
local utilsCargo = require("Module:UtilsCargo")
for _, row in ipairs(cargoData) do
local utilsTable = require('Module:UtilsTable')
if not utilsCode.IsEmpty(row["meaning"]) then
skipMeanings = false
break
end
end
local resultTable = h.CreateTable(skipMeanings)
local resultTable = h.CreateRows(resultTable, cargoData, skipMeanings)
return resultTable
end


-- For printing a single row in a translation page
local DISCORD_URL = require("Module:Constants/url/discord")
function p.MainRow (frame)
local resultRow = h.CreateNomenclatureRow(frame.args["game"], frame.args["term"], utilsText.split(frame.args["languages"]), frame.args["image"])
return resultRow
end


function h.CreateNomenclatureRow(game, term, languages, image)
-- For creating nomenclature tables
local cargoData = translation.fetchTranslationsByGame(game, term)
function p.Main(frame)
h.SortTranslations(cargoData)
local subject = frame.args["term"]
local tr = mw.html.create('tr')
if subject == nil or subject == "" then
h.PrintTerm(tr, game, term, image)
subject = mw.title.getCurrentTitle().subpageText
for _, lang in ipairs(languages) do
h.PrintNomenclatureNames(tr, cargoData, lang)
end
end
return tr
local translations = h.fetchTranslations(subject)
local translations, hasMeanings, displayGames = h.formatData(translations)
local nomenclatureTable = h.printNomenclatureTable(translations, hasMeanings, displayGames)
return nomenclatureTable
end
end


function h.PrintTerm(tr, game, termToPrint, image)
function h.fetchTranslations(page)
tr:tag('td')
local whereClause = utilsCargo.allOf({
:css{
    subject = page
["text-align"] = "center"
})
}
-- Fetch translations of synonyms
:wikitext('[[' .. image .. '|175x175px]]<br><b>' .. term.Main(game, termToPrint, "link", "", "") .. '</b>')
local term = Term.fetchTerm(page)
end
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.
function h.PrintNomenclatureNames(tr, cargoData, language)
whereClause = whereClause .. " OR " ..utilsCargo.allOf({
tr:tag('td')
    term = term
:wikitext(table.concat(h.GetNamesFromLanguage(cargoData, language), '<br>'))
}, "subject NOT LIKE '%)'") -- without this, requesting "Wood" would also fetch data for Wood (Character)
end
 
function h.GetNamesFromLanguage(cargoData, language)
local names = {}
local name = ""
for _, row in ipairs(cargoData) do
if row['language'] == language then
name = row["translation"]
if not utilsCode.IsEmpty(row["meaning"]) then
name = "<span class='explain' rel='tooltip' title='" .. row["meaning"] .. "' style='color:Yellow;'>" .. name .. "</span>"
end
names[#names+1] = name
end
end
end
return names
local translations = utilsCargo.query("Translations", "game, term, lang, translation, meaning, ref", {
where = whereClause
})
return translations
end
end


--Create an empty table with headers
function h.formatData(translations)
function h.CreateTable(skipMeanings)
local hasMeanings = utilsTable.find(translations, function(translation)
--Table structure
return translation.meaning == nil and translation.meaning ~= "" and translation.term ~= translation.translation
local resultTable = mw.html.create("table")
end)
:addClass("wikitable")
:css{
["margin"] = "1em 0",
["font-size"] = "95%",
}:done()
--Global header
-- Determine whether to display Exp Game
local headerRow = mw.html.create("tr"):done()
local seenGames = {}
local headerContent = mw.html.create("th")
local gameCount = 0
:wikitext("[[File:TMC Forest Minish Artwork.png|20px]] Names in Other Regions [[File:TMC Jabber Nut Sprite.png]]")
local hasRemakes = false
:attr("colspan", "4")
for i, translation in ipairs(translations) do
:css{
local game = translation.game
["font-size"] = "110%",
if not seenGames[game] then
}:done()
gameCount = gameCount + 1
seenGames[game] = true
headerRow:node(headerContent)
end
resultTable:node(headerRow)
if Franchise.isRemake(game) or Franchise.hasRemakes(game) then
hasRemakes = true
--Individual headers
end
--Language
headerRow = mw.html.create("tr"):done()
headerContent = mw.html.create("th")
:wikitext("Language")
:attr("colspan", "2"):done()
headerRow:node(headerContent)
--Name
headerContent = mw.html.create("th")
:wikitext("Name"):done()
headerRow:node(headerContent)
--Meaning
if not skipMeanings then
headerContent = mw.html.create("th")
:wikitext("Meaning"):done()
headerRow:node(headerContent)
end
end
local displayGames = gameCount > 1 or hasRemakes
resultTable:node(headerRow)
-- 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"))
return resultTable
-- Creates a list of unique translations grouped by language
end
-- 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
function h.CreateRows(output, cargoData, skipMeanings)
local hasMeanings = false
h.SortTranslations(cargoData)
local translationLists = {}
for _, row in ipairs(cargoData) do
for lang, langTranslations in pairs(translations) do
if not row.skip then
local translationList = {}
h.ProcessRow(output, cargoData, row, skipMeanings)
for translation, translationGames in pairs(langTranslations) do
local translationListItem = {
translation = translation,
games = {},
meaning = "&nbsp;",
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
end
-- Sort translations by their earliest appearance
translationList = utilsTable.sortBy(translationList, function(translation)
return gameOrderLookup[translation.games[1]]
end)
translationLists[lang] = translationList
end
end
return translationLists, hasMeanings, displayGames
return output
end
end


function h.SortTranslations(translations)
local refCount = 0
local lookupLang = utilsTable.hash(utilsLanguage.GetCodeSortOrder())
local refNamePrefix = "nomenclature-"
local lookupGame = utilsTable.hash(utilsGame.GetSortOrder("canon"))
local seenCitations = {} -- to prevent duplicate citations in the ==References== section on the page
table.sort(translations, function (a,b)
local seenRefs = {} -- to prevent duplicate reference markers in a given Nomenclature table row (e.g. [[Bomb]] Simplified Chinese)
if (lookupLang[a.language] or 0) == (lookupLang[b.language] or 0) then
function h.printRef(translation, citation)
return (lookupGame[a.game] or 0) < (lookupGame[b.game] or 0)
if citation == nil or citation == "" then
else
return ""
return (lookupLang[a.language] or 0) < (lookupLang[b.language] or 0)
end
end
)
end
 
function h.ProcessRow(output, cargoData, row, skipMeanings)
local meanings = h.GetMeanings(cargoData, row)
local tr = output:tag('tr')
h.PrintFlag(tr, row)
h.PrintLanguage(tr, row)
h.PrintNames(tr, cargoData, row)
h.MarkRowsToSkip(cargoData, row)
if not skipMeanings then
h.PrintMeanings(tr, meanings)
end
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
end


function h.GetMeanings(cargoData, row)
function h.printNomenclatureTable(translationsByLang, hasMeanings, displayGames)
local ret = { row.meaning }
local html = mw.html.create("table")
for _, row2 in ipairs(cargoData) do
:addClass("wikitable")
if h.SameLangDifTranslations(row, row2) then
:tag("tr")
ret[#ret+1] = row2.meaning
:tag("th")
end
: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
end
return ret
end
for i, lang in ipairs(Language.enum()) do
 
local translations = translationsByLang[lang]
function h.PrintFlag(tr, row)
if translations then
tr:tag('td')
h.addRow(html, hasMeanings, displayGames, lang, translations)
:wikitext(utilsLanguage.CodeToFlag(row.language))
end
 
function h.PrintLanguage(tr, row)
tr:tag('td')
:wikitext(utilsLanguage.CodeToLanguage(row.language))
end
 
function h.PrintNames(tr, cargoData, row)
local td = tr:tag('td')
:wikitext(table.concat(h.GetNamesAndTheirGames(cargoData, row), '<br>'))
end
 
function h.GetNamesAndTheirGames(cargoData, row)
local ret = { h.GetOneNameAndGames(cargoData, row) }
for _, row2 in ipairs(cargoData) do
if h.SameLangDifTranslations(row, row2) then
games = h.GamesWithSameTranslation(row2, cargoData)
ret[#ret+1] = h.GetOneNameAndGames(cargoData, row2)
end
end
end
end
return ret
local footerText = mw.getCurrentFrame():preprocess("<small>This table was generated using [[Data:Translations|translation pages]].<br>To request an addition, please contact 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
end


function h.GetOneNameAndGames(cargoData, row)
function h.addRow(html, hasMeanings, displayGames, lang, translations)
local games = h.GamesWithSameTranslation(row, cargoData)
local row = html:tag("tr")
return ('%s %s'):format(row.translation, expgame.Display(games))
local langCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--language")
end
local nameCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--name")
 
local meaningCell = mw.html.create("td"):addClass("nomenclature__cell nomenclature__cell--meanings")
function h.GamesWithSameTranslation(row, cargoData)
local ret = {}
local lect = Language.getLect(lang)
for _, row2 in ipairs(cargoData) do
langCell:tag("div")
if h.SameLangSameTranslation(row, row2) then
:addClass("nomenclature__language")
ret[#ret+1] = row2.game
:tag("div")
end
: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
end
return ret
end
names = #names == 1 and names[1] or h.list(names)
 
meanings = #meanings == 1 and meanings[1] or h.list(meanings)
function h.SameLangSameTranslation(row1, row2)
return row1.language == row2.language and row1.translation == row2.translation
nameCell:wikitext(names)
end
meaningCell:wikitext(meanings)
 
function h.SameLangDifTranslations(row1, row2)
-- When the foreign name is the exact same as the NoA name (see TotK page for example)
return row1.language == row2.language and row1.translation ~= row2.translation
if #translations == 1 and translations[1].translation == translations[1].term then
end
nameCell:attr("colspan", 2)
 
meaningCell = nil
function h.SameLang(row1, row2)
return row1.language == row2.language
end
 
function h.PrintMeanings(tr, meanings)
local meaningsDisplays = h.ProcessMeanings(meanings)
td = tr:tag('td')
:wikitext(table.concat(meaningsDisplays, '<br>'))
end
 
function h.MarkRowsToSkip(cargoData, row)
for _, row2 in ipairs(cargoData) do
if h.SameLang(row, row2) then
row2.skip = true
end
end
end
end


function h.ProcessMeanings(meanings)
row:node(langCell)
local ret = {}
row:node(nameCell)
for k, v in pairs(meanings) do
if hasMeanings and meaningCell then
if utilsCode.IsEmpty(v) then
row:node(meaningCell)
ret[#ret+1] = '&nbsp;'
else
ret[#ret+1] = v
end
end
end
return ret
end
end


-- TRANSLATION PAGES
function h.printTranslationName(translationData, displayGames)
function p._CreateTranslationTables(frame)
local result = translationData.translation
local args = frame:getParent().args
if displayGames then
result = result .. " " .. mw.getCurrentFrame():expandTemplate({
local tabs = {}
title = "Exp Game",
local index = 0
args = {table.concat(translationData.games, ", ")}
while true do
})
index = index + 1
if utilsCode.IsEmpty(args["tab" .. index]) then
break
else
table.insert(tabs, {tabName = args["tab" .. index], tabContent = args["subjects"]})
end
end
end
return result
return p.CreateTranslationTables(args["game"], args["filetype"], tabs, args["subjects"])
end
end


function p.CreateTranslationTables(game, filetype, tabs, subjects)
function h.list(items)
-- Getting all translations for the game
local list = mw.html.create("ul"):addClass("plainlist")
local tables = "Translations"
for i, item in ipairs(items) do
local fields = "term, language, translation, meaning"
list:tag("li"):wikitext(item)
local args = {
where = "game = '" .. game .. "'"
}
local translations = cargo.query(tables, fields, args)
subjects = mw.text.split(subjects, '%s*,%s*')
for key, tab in ipairs(tabs) do
local languages = mw.text.split(tab["tabName"], '%s*,%s*')
--Creating tab contents
local headerRow = mw.html.create("tr")
:node(mw.html.create("th"):wikitext("Subject")):done()
for key2, language in ipairs(languages) do
headerRow:node(mw.html.create("th"):wikitext(utilsLanguage.CodeToFlag(language) .. "<br>" .. utilsLanguage.CodeToLanguage(language)):css("width", 100 / (#languages + 1) .. "%")):done()
end
local content = mw.html.create("table")
:addClass("wikitable")
:css("width", "100%")
:node(headerRow)
--Creating rows
for key2, subject in ipairs(subjects) do
local row = mw.html.create("tr"):node(mw.html.create("th"):wikitext("[[File:" .. game .. " " .. term.fetchTerm(game, subject) .. " " .. filetype .. ".png|175x175px]]<br>" .. term.Main(game, subject, "link", "", nil)))
for key3, language in ipairs(languages) do
outputs = {}
for key4, translation in ipairs(translations) do
if translation["term"] == subject then
if translation["language"] == language then
table.insert(outputs, translation["translation"])
end
end
end
local cell = mw.html.create("td"):addClass("facelift-centered")
if outputs[1] == "N/A" then
cell:css("background-color", "var(--zw-dark-2)")
else
cell:wikitext(table.concat(outputs, "<br>"))
end
row:node(cell):done()
end
content:node(row)
end
tab["tabContent"] = tostring(content)
-- Formatting tab names
for key2, language in ipairs(languages) do
languages[key2] = utilsLanguage.CodeToLanguage(language)
end
tab["tabName"] = table.concat(languages, ", ")
end
end
return tostring(list)
return tab2.Main(tabs, 1, "top", #tabs, "", "", "", "left")
end
end


return p
return p

Latest revision as of 16:33, 14 April 2024

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")

-- 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 = "&nbsp;",
				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 contact 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