Aller au contenu

Module:Debate/i18n

De Wikidébats, l'encyclopédie des débats et des arguments « pour » et « contre »

La documentation pour ce module peut être créée à Module:Debate/i18n/doc

-- Module:Debate
-- MediaWiki 1.43 — Wikidébats / Wikidebates
-- Objectif : rendre le modèle « Débat » en Lua, avec i18n centralisée.
-- Indentation : tabulations

local p = {}

----------------------------------------------------------------------
-- Chargement i18n
----------------------------------------------------------------------

local I18N = mw.loadData('Module:Debate/i18n')

-- Sélecteur de message avec fallback
local function L(lang, section, key, ...)
	local tbl = I18N[section]
	if not tbl then return key end
	local entry = tbl[key]
	if not entry then return key end
	local msg = entry[lang] or entry["fr"] or entry["en"]
	if not msg then return key end
	if select("#", ...) > 0 then
		return string.format(msg, ...)
	end
	return msg
end

----------------------------------------------------------------------
-- Détection de la langue
----------------------------------------------------------------------

local function getLang()
	-- simple : langue de contenu de la page courante
	local contentLang = mw.getContentLanguage():getCode()
	if I18N.text.no_intro[contentLang] then
		return contentLang
	end
	return "fr"
end

----------------------------------------------------------------------
-- Accès global au frame + VariablesLua
----------------------------------------------------------------------

local F = mw.getCurrentFrame()
local V = (mw.ext and mw.ext.VariablesLua) or nil

local function vset(name, val)
	if V and type(V.vardefine) == "function" then
		pcall(V.vardefine, name, val ~= nil and tostring(val) or "")
	end
end
local function vget(name)
	if V and type(V.var) == "function" then
		local ok, res = pcall(V.var, name)
		if ok then return res end
	end
	return nil
end

----------------------------------------------------------------------
-- Helpers
----------------------------------------------------------------------

local function getArgs(frame)
	local parent = frame:getParent()
	local A = {}
	for k, v in pairs(parent and parent.args or {}) do
		if type(v) == "string" and v ~= "" then
			A[k] = v
		end
	end
	for k, v in pairs(frame.args or {}) do
		if type(v) == "string" and v ~= "" then
			A[k] = v
		end
	end
	return A
end

local function splitCSV(s, sep)
	if not s or s == "" then return {} end
	sep = sep or ","
	local out = {}
	for part in mw.text.gsplit(s, sep, true) do
		part = mw.text.trim(part)
		if part ~= "" then
			table.insert(out, part)
		end
	end
	return out
end

local function expand(frame, title, params)
	local ok, res = pcall(function()
		return frame:expandTemplate{ title = title, args = params or {} }
	end)
	if ok then return res or "" end
	return ""
end

local function hasSMW()
	return type(mw.smw) == "table" and type(mw.smw.set) == "function"
end
local function smwSetSafe(props)
	if not hasSMW() then return end
	pcall(function() mw.smw.set(props) end)
end
local function smwAskSafe(q)
	if not hasSMW() then return nil end
	local ok, res = pcall(function() return mw.smw.ask(q) end)
	if ok then return res end
	return nil
end

local function seoSetSafe(params)
	if type(mw.ext) == "table" and type(mw.ext.seo) == "table" and type(mw.ext.seo.set) == "function" then
		pcall(function() mw.ext.seo.set(params) end)
	end
end

local function makeJsonLD(t)
	return mw.text.jsonEncode(t)
end

local function tag(name, content, attrs)
	local parts = {}
	if attrs then
		for k, v in pairs(attrs) do
			table.insert(parts, string.format("%s=%s", k, v))
		end
	end
	local src
	if #parts > 0 then
		src = string.format("{{#tag:%s|%s|%s}}", name, content or "", table.concat(parts, "|"))
	else
		src = string.format("{{#tag:%s|%s}}", name, content or "")
	end
	return F:preprocess(src)
end

local function pf_escape(v)
	if not v then return "" end
	v = tostring(v)
	v = v:gsub("|", "|")
	v = v:gsub("=", "=")
	return v
end

local function pf_formlink(opts)
	local parts = { "#formlink:" }
	table.insert(parts, string.format("form=%s", pf_escape(opts.form or "")))
	if opts.target and opts.target ~= "" then
		if tostring(opts.target):find("{{", 1, true) then
			table.insert(parts, "target=" .. opts.target)
		else
			table.insert(parts, string.format("target=%s", pf_escape(opts.target)))
		end
	end
	if opts.link_text and opts.link_text ~= "" then
		table.insert(parts, string.format("link text=%s", pf_escape(opts.link_text)))
	end
	if opts.tooltip and opts.tooltip ~= "" then
		table.insert(parts, string.format("tooltip=%s", pf_escape(opts.tooltip)))
	end
	table.insert(parts, string.format("link type=%s", pf_escape(opts.link_type or "link")))
	if opts.query_string and opts.query_string ~= "" then
		table.insert(parts, "query string=" .. opts.query_string)
	end
	local wt = "{{" .. table.concat(parts, "|") .. "}}"
	return F:preprocess(wt)
end

local function pf_queryformlink(opts)
	local parts = { "#queryformlink:" }
	table.insert(parts, string.format("form=%s", pf_escape(opts.form or "")))
	if opts.link_text and opts.link_text ~= "" then
		table.insert(parts, string.format("link text=%s", pf_escape(opts.link_text)))
	end
	if opts.tooltip and opts.tooltip ~= "" then
		table.insert(parts, string.format("tooltip=%s", pf_escape(opts.tooltip)))
	end
	table.insert(parts, string.format("link type=%s", pf_escape(opts.link_type or "post button")))
	if opts.target and opts.target ~= "" then
		if tostring(opts.target):find("{{", 1, true) then
			table.insert(parts, "target=" .. opts.target)
		else
			table.insert(parts, string.format("target=%s", pf_escape(opts.target)))
		end
	end
	if opts.query_string and opts.query_string ~= "" then
		table.insert(parts, "query string=" .. opts.query_string)
	end
	local wt = "{{" .. table.concat(parts, "|") .. "}}"
	return F:preprocess(wt)
end

----------------------------------------------------------------------
-- Propriétés SMW bilingues
----------------------------------------------------------------------

local function smw_add(props_tbl, key, value)
	local labels = I18N.props[key]
	if type(labels) == "table" then
		for _, label in pairs(labels) do
			props_tbl[label] = value
		end
	else
		props_tbl[key] = value
	end
end

----------------------------------------------------------------------
-- Variables de page
----------------------------------------------------------------------

local function computePageVars()
	local cached = vget("WD_PageVars_JSON")
	if cached and cached ~= "" then
		local ok, pv = pcall(mw.text.jsonDecode, cached)
		if ok and type(pv) == "table" then
			pv.title = mw.title.getCurrentTitle()
			return pv
		end
	end

	local title = mw.title.getCurrentTitle()
	local rawTitle = mw.ustring.gsub(title.prefixedText, "'", "'")
	local encoded = mw.uri.encode(rawTitle, "WIKI")
	local uriEncoded = F:callParserFunction('urlencode', rawTitle)
	local pageUrl = tostring(mw.uri.fullUrl(title.prefixedText))
	local pageId = tostring(title.id or "")

	local pv = {
		title = title,
		rawTitle = rawTitle,
		encoded = encoded,
		uriEncoded = uriEncoded,
		pageUrl = pageUrl,
		pageId = pageId
	}

	vset("WD_PageVars_JSON", mw.text.jsonEncode(pv))
	return pv
end

local function emitLegacyVarDefines(pv)
	local function esc(s)
		s = tostring(s or "")
		s = s:gsub("|", "|"):gsub("=", "=")
		return s
	end
	local wt =
		'<span style="display:none;">'
		.. '{{#vardefine:Titre-page|' .. esc(pv.rawTitle) .. '}}'
		.. '{{#vardefine:Titre-page-encode|' .. esc(pv.encoded) .. '}}'
		.. '{{#vardefine:URL-page|' .. esc(pv.pageUrl) .. '}}'
		.. '{{#vardefine:ID-page|' .. esc(pv.pageId) .. '}}'
		.. '</span>'
	return F:preprocess(wt)
end

----------------------------------------------------------------------
-- SMW + SEO
----------------------------------------------------------------------

local function setSemanticData(args, pv, mapPour, mapContre, lang)
	local emptyFor		= L(lang, "text", "no_pro_args")
	local emptyAgainst	= L(lang, "text", "no_con_args")
	local headFor		= (lang == "en") and "FOR" or "POUR"
	local headAgainst	= (lang == "en") and "AGAINST" or "CONTRE"

	local arg_map_html =
		"<table style='background-color:transparent; width: 100%; margin: 0em 0.5em 0.15em 0;' class='navigation-not-searchable'>" ..
		"<tr><th style='text-align:left;'>" .. headFor ..
		"</th><th style='text-align:left; padding-left: 1em;'>" .. headAgainst ..
		"</th></tr>" ..
		"<tr style='vertical-align:top;'><td><div>" ..
			((mapPour ~= "" and mapPour) or ("<div style='font-size: 95%'>" .. emptyFor .. "</div>")) ..
		"</div></td><td style='padding-left: 1em;'><div>" ..
			((mapContre ~= "" and mapContre) or ("<div style='font-size: 95%'>" .. emptyAgainst .. "</div>")) ..
		"</div></td></tr></table>"

	local props = {}
	smw_add(props, "debate_name", pv.rawTitle)
	smw_add(props, "debate_number", pv.pageId)
	smw_add(props, "debate_parent", pv.rawTitle)
	smw_add(props, "breadcrumb", pv.rawTitle)
	if args["keywords"] and args["keywords"] ~= "" then
		smw_add(props, "keyword", args["keywords"])
	end
	smw_add(props, "arg_map", arg_map_html)
	smw_add(props, "arg_list", (mapPour or "") .. "-@@@-" .. (mapContre or ""))
	smw_add(props, "page_params", table.concat({ "", "", "", "" }, "<>"))
	if args["topic"] and mw.text.trim(args["topic"]) ~= "" then
		smw_add(props, "debate_subject", args["topic"])
		smw_add(props, "subject_title", args["topic"] .. " : [[" .. pv.rawTitle .. "]]")
	end
	smwSetSafe(props)

	local seoTitle = string.format(I18N.seo.title_prefix[lang], pv.rawTitle)
	seoSetSafe({
		title = seoTitle,
		title_mode = string.format(I18N.seo.title_mode[lang], pv.rawTitle),
		title_separator = "–",
		description = string.format(I18N.seo.desc_prefix[lang], (args["complete-topic"] or ""), (args["keywords"] or "")),
		keywords = (lang == "fr" and "débat, arguments, pour, contre, critiques, " or "debate, arguments, for, against, critiques, ")
			.. (args["keywords"] or "") .. ", " .. (args["sections"] or "")
			.. (lang == "fr" and ", objection, wiki, encyclopédie, opinion" or ", objection, wiki, encyclopedia, opinion"),
		image = "https://fr.wikidebates.org/w/resources/assets/logo-Wikidebats-Twitter.png",
		image_alt = L(lang, "text", "main_banner_alt"),
		type = "article",
		section = (lang == "fr") and "Débat" or "Debate",
		site_name = I18N.seo.site_name[lang],
		twitter_site = I18N.seo.twitter_site[lang],
		["google-site-verification"] = "76d1055d3ec815c",
		locale = (lang == "fr") and "fr_FR" or "en_US",
		["hreflang_de-de"] = "https://de.wikidebates.org/",
		["hreflang_en-us"] = "https://en.wikidebates.org/",
		["hreflang_es-es"] = "https://es.wikidebates.org/",
		["hreflang_it-it"] = "https://it.wikidebates.org/",
		["hreflang_pt-pt"] = "https://pt.wikidebates.org/",
		["og:url"] = pv.pageUrl
	})
end

----------------------------------------------------------------------
-- Rendu principal (simplifié ici)
----------------------------------------------------------------------

function p.render(frame)
	local lang = getLang()
	local args = getArgs(frame)
	local pv = computePageVars()
	local pieces = {}
	local cats = {}

	table.insert(pieces, emitLegacyVarDefines(pv))
	table.insert(cats, "[[Category:" .. L(lang,"categories","debates") .. "]]")

	-- Exemple d’utilisation d’un message i18n :
	table.insert(pieces,
		string.format(L(lang,"text","main_banner_title"), mw.text.nowiki(pv.rawTitle))
	)

	-- Ajout des catégories
	table.insert(pieces, table.concat(cats))

	-- NOCACHE
	table.insert(pieces, F:preprocess("__NOCACHE__"))

	return table.concat(pieces, "\n")
end

return p