Documentation for this module may be created at Модуль:translations/doc

local require = require
local require_when_needed = require("Module:require when needed")

local anchor_encode = mw.uri.anchorEncode
local concat = table.concat
local decode_uri = require_when_needed("Module:string utilities", "decode_uri")
local format_categories = require_when_needed("Module:utilities", "format_categories")
local html_create = mw.html.create
local insert = table.insert
local new_title = mw.title.new
local load_data = mw.loadData
local process_params = require_when_needed("Module:parameters", "process")

local en = require("Module:languages").getByCode("en")

local export = {}

local function is_translation_subpage(pagename)
	local data = load_data("Module:headword/data")
	if data.page.namespace ~= "" then
		return false
	elseif not pagename then
		pagename = data.encoded_pagename
	end
	return pagename:match("./translations$") and true or false
end

local function canonical_pagename()
	local pagename = load_data("Module:headword/data").encoded_pagename
	return is_translation_subpage(pagename) and pagename:sub(1, -14) or pagename
end

do
	local function interwiki(terminfo, lang, langcode, term, m_links, m_data)
		-- No interwiki link if term is empty/missing
		if not term or #term < 1 then
			terminfo.interwiki = false
			return
		end
		
		-- Percent-decode the term.
		term = decode_uri(term, "PATH")
		
		-- Don't show an interwiki link if it's an invalid title.
		if not new_title(term) then
			terminfo.interwiki = false
			return
		end
		
		local wmlangs
		local interwiki_langcode = m_data.interwiki_langs[langcode]
		if interwiki_langcode then
			wmlangs = {require("Module:wikimedia languages").getByCode(interwiki_langcode)}
		else
			wmlangs = lang:getWikimediaLanguages()
		end
		
		-- Don't show the interwiki link if the language is not recognised by Wikimedia.
		if #wmlangs == 0 then
			terminfo.interwiki = false
			return
		end
		
		local sc = terminfo.sc
		
		local target_page = m_links.get_link_page(term, lang, sc)
		local split = m_links.split_on_slashes(target_page)
		if not split[1] then
			terminfo.interwiki = false
			return
		end
		target_page = split[1]
		
		local wmlangcode = wmlangs[1]:getCode()
		local interwiki_link = m_links.language_link{
			lang = lang,
			sc = sc,
			term = wmlangcode .. ":" .. target_page,
			alt = "(" .. wmlangcode .. ")",
			tr = "-"
		}
		
		terminfo.interwiki = tostring(html_create("span")
			:addClass("tpos")
			:wikitext("&nbsp;" .. interwiki_link)
		)
	end
	
	function export.show_terminfo(terminfo, check)
		local m_data = load_data("Module:translations/data")
		local lang = terminfo.lang
		local langcode, langname = lang:getCode(), lang:getCanonicalName()
		-- Translations must be for mainspace languages.
		if not lang:hasType("regular") then
			error("Translations must be for attested and approved main-namespace languages.")
		else
			local err_msg = m_data.disallowed[langcode]
			if err_msg then
				error("Translations not allowed in " .. langname .. " (" .. langcode .. "). " .. langname .. " translations should " .. err_msg)
			end
			local fullcode = lang:getFullCode()
			if fullcode ~= langcode then
				err_msg = m_data.disallowed[fullcode]
				if err_msg then
					langname = lang:getFullName()
					error("Translations not allowed in " .. langname .. " (" .. fullcode .. "). " .. langname .. " translations should " .. err_msg)
				end
			end
		end
		
		local term = terminfo.term
		local m_links = require("Module:links")
		
		-- Check if there is a term. Don't show the interwiki link if there is nothing to link to.
		if not term then
			-- Track entries that don't provide a term.
			-- FIXME: This should be a category.
			local track = require("Module:debug/track")
			track("translations/no term")
			track("translations/no term/" .. langcode)
		end
		if terminfo.interwiki then
			interwiki(terminfo, lang, langcode, term, m_links, m_data)
		end
		
		langcode = lang:getFullCode()
		
		if m_data.need_super[langcode] then
			local tr = terminfo.tr
			terminfo.tr = tr and tr:gsub("%d[%d%*%-]*%f[^%d%*]", "<sup>%0</sup>") or nil
		end
		
		local link = m_links.full_link(terminfo, "translation")
		local categories = {"Terms with " .. lang:getFullName() .. " translations"}
		
		if check then
			link = tostring(html_create("span")
				:addClass("ttbc")
				:tag("sup")
					:addClass("ttbc")
					:wikitext("(please [[WT:Translations#Translations to be checked|verify]])")
					:done()
				:wikitext(" " .. link)
			)
			insert(categories, "Requests for review of " .. langname .. " translations")
		end
		
		return link .. format_categories(categories, en, nil, canonical_pagename())
	end
end

-- Implements {{t}}, {{t+}}, {{t-check}} and {{t+check}}.
function export.show(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["translation"])
	local check = frame.args["check"]
	return export.show_terminfo({
		lang = args[1],
		sc = args["sc"],
		track_sc = true,
		term = args[2],
		alt = args["alt"],
		id = args["id"],
		genders = args[3],
		tr = args["tr"],
		ts = args["ts"],
		lit = args["lit"],
		interwiki = frame.args["interwiki"],
	}, check and check ~= "")
end

local function add_id(div, id)
	return id and div:attr("id", anchor_encode("Translations-" .. id)) or div
end

-- Implements {{trans-top}} and part of {{trans-top-also}}.
local function top(args, title, id, navhead)
	local column_width = (args["column-width"] == "wide" or args["column-width"] == "narrow") and "-" .. args["column-width"] or ""
	
	local div = html_create("div")
		:addClass("NavFrame")
		:node(navhead)
		:tag("div")
			:addClass("NavContent")
			:tag("table")
				:addClass("translations")
				:attr("role", "presentation")
				:attr("data-gloss", title or "")
				:tag("tr")
					:tag("td")
						:addClass("translations-cell")
						:addClass("multicolumn-list" .. column_width)
						:attr("colspan", "3")
		:allDone()
	div = add_id(div, id)

	local categories = {}

	if not title then
		insert(categories, "Translation table header lacks gloss")
	end

	local pagename = canonical_pagename()
	if is_translation_subpage() then
		insert(categories, "Translation subpages")
	end

	return (tostring(div):gsub("</td></tr></table></div></div>$", "")) ..
		(#categories > 0 and format_categories(categories, en, nil, pagename) or "") ..
		-- Category to trigger [[MediaWiki:Gadget-TranslationAdder.js]]; we want this even on
		-- user pages and such.
		format_categories({"Entries with translation boxes"}, en, nil, pagename, true) ..
		require("Module:TemplateStyles")("Module:translations/styles.css")
end

-- Entry point for {{trans-top}}.
function export.top(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["trans-top"])
	local title = args[1]
	local id = args.id or title
	title = title and require("Module:links").remove_links(title)
	return top(args, title, id, html_create("div")
		:addClass("NavHead")
		:css("text-align", "left")
		:wikitext(title or "Translations")
	)
end

-- Entry point for {{checktrans-top}}.
function export.check_top(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["checktrans-top"])
	
	local text = "\n:''The translations below need to be checked and inserted above into the appropriate translation tables. See instructions at " ..
		frame:expandTemplate{
			title = "section link",
			args = {"Wiktionary:Entry layout#Translations"}
		} ..
		".''\n"
	
	local header = html_create("div")
		:addClass("checktrans")
		:wikitext(text)
		
	local subtitle = args[1]
	local title = "Translations to be checked"
	if subtitle then
		title = title .. "&zwnj;: \"" .. subtitle .. "\""
	end
	-- No ID, since these should always accompany proper translation tables, and can't be trusted anyway (i.e. there's no use-case for links).
	return tostring(header) .. "\n" .. top(args, title, nil, html_create("div")
		:addClass("NavHead")
		:css("text-align", "left")
		:wikitext(title or "Translations")
	)
end

-- Implements {{trans-bottom}}.
function export.bottom(frame)
	-- Check nothing is being passed as a parameter.
	process_params(frame:getParent().args, load_data("Module:parameters/data")["trans-bottom"])
	return "</table></div></div>"
end

-- Implements {{trans-see}} and part of {{trans-top-also}}.
local function see(args, see_text)
	local navhead = html_create("div")
		:addClass("NavHead")
		:css("text-align", "left")
		:wikitext(args[1] .. " ")
		:tag("span")
			:css("font-weight", "normal")
			:wikitext("— ")
			:tag("i")
				:wikitext(see_text)
		:allDone()
	local terms, id = args[2], args["id"]
	
	if #terms == 0 then
		terms[1] = args[1]
	end
	
	local plain_link = require("Module:links").plain_link
	for i = 1, #terms do
		local term_id = id[i] or id.default
		local data = {
			term = terms[i],
			id = term_id and "Translations-" .. term_id or "Translations",
		}
		terms[i] = plain_link(data)
	end
	
	return navhead:wikitext(concat(terms, ",&lrm; "))
end

-- Entry point for {{trans-see}}.
function export.see(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["trans-see"])
	local div = html_create("div")
		:addClass("pseudo")
		:addClass("NavFrame")
		:node(see(args, "see "))
	return tostring(add_id(div, args.id.default or args[1]))
end

-- Entry point for {{trans-top-also}}.
function export.top_also(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["trans-top-also"])
	local navhead = see(args, "see also ")
	local title = args[1]
	local id = args.id.default or title
	title = require("Module:links").remove_links(title)
	return top(args, title, id, navhead)
end

-- Implements {{translation subpage}}.
function export.subpage(frame)
	process_params(frame:getParent().args, load_data("Module:parameters/data")["translation subpage"])
	if not is_translation_subpage() then
		error("This template should only be used on translation subpages, which have titles that end with '/translations'.")
	end
	-- "Translation subpages" category is handled by {{trans-top}}.
	return ("''This page contains translations for %s. See the main entry for more information.''"):format(require("Module:links").full_link{
		lang = en,
		term = canonical_pagename(),
	})
end

-- Implements {{t-needed}}.
function export.needed(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["t-needed"])
	local lang, category = args[1], ""
	local span = html_create("span")
		:addClass("trreq")
		:attr("data-lang", lang:getCode())
		:tag("i")
			:wikitext("please add this translation if you can")
			:done()
		
	if not args["nocat"] then
		local type, sort = args[2], args["sort"]
		if type == "quote" then
			category = "Requests for translations of " .. lang:getCanonicalName() .. " quotations"
		elseif type == "usex" then
			category = "Requests for translations of " .. lang:getCanonicalName() .. " usage examples"
		else
			category = "Requests for translations into " .. lang:getCanonicalName()
			lang = en
		end
		category = format_categories({category}, lang, sort, not sort and canonical_pagename() or nil)
	end
		
	return tostring(span) .. category
end

-- Implements {{no equivalent translation}}.
function export.no_equivalent(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["no equivalent translation"])
	
	local text = "no equivalent term in " .. args[1]:getCanonicalName()
	if not args["noend"] then
		text = text .. ", but see"
	end
	
	return tostring(html_create("i"):wikitext(text))
end

-- Implements {{no attested translation}}.
function export.no_attested(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["no attested translation"])
	
	local langname = args[1]:getCanonicalName()
	local text = "no [[WT:ATTEST|attested]] term in " .. langname
	local category = ""
	
	if not args["noend"] then
		text = text .. ", but see"
		local sort = args["sort"]
		category = format_categories({langname .. " unattested translations"}, en, sort, not sort and canonical_pagename() or nil)
	end
	
	return tostring(html_create("i"):wikitext(text)) .. category
end

-- Implements {{not used}}.
function export.not_used(frame)
	local args = process_params(frame:getParent().args, load_data("Module:parameters/data")["not used"])
	return tostring(html_create("i"):wikitext((args[2] or "not used") .. " in " .. args[1]:getCanonicalName()))
end

return export