Module:Languages/sandbox

From OpenStreetMap Wiki
Jump to navigation Jump to search
local p = {}
local config = mw.loadData("Module:Languages/config/sandbox")
local siteLanguage = mw.getContentLanguage()

--- Returns the language pseudonamespace in the title of a page in the main
--- namespace, or nil if the title contains no pseudonamespace.
function p.pseudoNamespaceFromTitle(title)
	local pseudoNS = title.text:match("^(%w%w%w?):") or
		title.text:match("^(%w%w%w?%-%w%w%w?%w?):")
	-- A few pseudonamespaces indicate topics rather than languages.
	if pseudoNS and config.languageNamesByCode[pseudoNS:lower()] then
		return pseudoNS
	end
end

--- Infers and returns the given title’s page language, defaulting to the wiki’s
--- content language.
function p.languageFromTitle(title, fallback)
	-- Language-specific namespace
	local ns = title.subjectNsText
	if config.namespacesByLanguage[ns:lower()] then
		return ns:lower()
	end
	
	-- Pseudonamespace in the main namespace
	local pseudoNS = p.pseudoNamespaceFromTitle(title)
	return pseudoNS and pseudoNS:lower() or fallback or siteLanguage:getCode()
end

--- Guesses the source title from the given title, which may be the source or a
--- translation.
function p.sourceTitleFromTitle(title)
	local pseudoNS = p.pseudoNamespaceFromTitle(title)
	if pseudoNS then
		local sourcePageName = title.text:sub(#pseudoNS + 2)
		return mw.title.new(sourcePageName, title.nsText)
	elseif config.namespacesByLanguage[title.subjectNsText:lower()] then
		return mw.title.new(title.text, title.isTalkPage and 1 or 0)
	else
		return title
	end
end

--- Quickly uppercases the first character of the string, disregarding Unicode.
local function ucfirst(s)
	return s:sub(1, 1):upper() .. s:sub(2, -1)
end

--- Returns the page name of a translation in the given language.
--- If simulateLangNS is true and the page lies in a non-content namespace, the
--- pseudonamespace is capitalized to mimic a dedicated language namespace.
function p.translationPageName(languageCode, sourceTitle, simulateLangNS)
	local isInMainNS = #sourceTitle.subjectNsText == 0
	
	local pageNameParts = {
		sourceTitle.text,
	}
	
	if isInMainNS and config.namespacesByLanguage[languageCode] then
		local ns = config.namespacesByLanguage[languageCode]
		if sourceTitle.isTalkPage then
			ns = mw.site.namespaces[ns].talk.name
		end
		if #ns > 0 then
			table.insert(pageNameParts, 1, ns)
		end
	else
		local pseudoNS = ucfirst(languageCode)
		local langNS = config.namespacesByLanguage[languageCode]
		if langNS and (simulateLangNS or #langNS == 0) then
			pseudoNS = langNS
		end
		if #pseudoNS > 0 then
			table.insert(pageNameParts, 1, pseudoNS)
		end
		if #sourceTitle.nsText > 0 then
			table.insert(pageNameParts, 1, sourceTitle.nsText)
		end
	end
	
	return table.concat(pageNameParts, ":")
end

--- Returns a link to a wiki page.
local function listItem(languageCode, pageName, label)
	local link = "[[:" .. pageName .. "|" .. label .. "]]"
	
	-- By default, hlist inserts an interpunct as CSS generated content after
	-- each list item. [[MediaWiki:Common.css]] hides redlinks but not the
	-- interpuncts, which follow the redlinks visually but aren’t siblings.
	-- This module uses hlist-with-seps, so hlist-sep gets the interpunct
	-- instead of the list item. As a sibling of the redlink, hlist-sep gets
	-- hidden along with the redlink.
	local sep = mw.html.create("span")
	sep:addClass("hlist-sep")
	
	local li = mw.html.create("li")
	li:attr("lang", languageCode):wikitext(link):node(sep)
	return tostring(li)
end
p.listItem = listItem

--- Returns an unordered list of links to each possible translation page.
function p.languageList(currentTitle, sourceTitle)
	local currentLanguage = p.languageFromTitle(currentTitle)
	local isInMainNS = #sourceTitle.subjectNsText == 0
	
	local listItems = {}
	for i, code in ipairs(config.languageCodes) do
		-- Link to the translation.
		local pageName
		if code == currentLanguage then
			-- Translations’ page names may themselves be translated, so force
			-- the current page to ensure that the link is boldfaced.
			pageName = currentTitle.fullText
		else
			pageName = p.translationPageName(code, sourceTitle)
			
			-- Languages with their own namespaces either uppercase or titlecase
			-- pages in non-content namespaces.
			if not isInMainNS and config.namespacesByLanguage[code]
				and not mw.title.new(pageName, sourceTitle.nsText).exists then
				pageName = p.translationPageName(code, sourceTitle, true)
			end
		end
		local item = listItem(code, pageName, config.languageNamesByCode[code])
		
		-- Add the current page to a tracking category if a translation is
		-- unavailable in a language that has a dedicated namespace.
		if config.namespacesByLanguage[code] and
			not mw.title.new(pageName, sourceTitle.nsText).exists then
			local category = "Category:" ..
				config.unavailablePageCategoryNames[code]
			local sortingKey = currentLanguage .. currentTitle.text
			item = item .. "[[" .. category .. "|" .. sortingKey .. "]]"
		end
		
		table.insert(listItems, item)
	end
	
	return table.concat(listItems, "\n")
end

--- Returns the current page’s language based on either the page’s title or its
--- content language (specified by the pagelang argument).
function p.currentPageLanguage(frame)
	local currentTitle = mw.title.getCurrentTitle()
	return p.languageFromTitle(currentTitle, frame.args.pagelang)
end

--- Guesses the source title from the given title, which may be the source or a
--- translation.
function p.sourceTitle(frame)
	local currentTitle = mw.title.getCurrentTitle()
	
	local sourcePageName = #(frame.args[1] or "") > 0 and frame.args[1]
	return sourcePageName and mw.title.new(sourcePageName) or
		p.sourceTitleFromTitle(currentTitle)
end

--- Returns a flat list of links to translations of the current page, in
--- wikitext format.
function p.languages(frame)
	local currentTitle = mw.title.getCurrentTitle()
	local sourceTitle = p.sourceTitle(frame)
	
	local languageList = p.languageList(currentTitle, sourceTitle)
	local hlist = mw.html.create("div")
	hlist:addClass("hlist"):addClass("hlist-with-seps"):wikitext(languageList)
	
	local wikitext = tostring(hlist)
	
	-- By default, sort the page in categories by the title sans pseudotitle.
	if frame.args.defaultsort ~= "no" then
		local pseudoNS = p.pseudoNamespaceFromTitle(currentTitle)
		if pseudoNS then
			local sortingKey = currentTitle.text:sub(#pseudoNS + 2)
			-- If another DEFAULTSORT appeared earlier on the page, this
			-- DEFAULTSORT has no effect. If a different DEFAULTSORT appears
			-- later, it needs to specify “noerror” to suppress the error about
			-- conflicting DEFAULTSORTs.
			local defaultSort = frame:callParserFunction {
				name = "DEFAULTSORT",
				args = {
					sortingKey,
					"noreplace",
				}
			}
			wikitext = wikitext .. defaultSort
		end
	end
	
	return wikitext
end

return p