<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.scout.clutch.engineering/index.php?action=history&amp;feed=atom&amp;title=Module%3ALanguages</id>
	<title>Module:Languages - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.scout.clutch.engineering/index.php?action=history&amp;feed=atom&amp;title=Module%3ALanguages"/>
	<link rel="alternate" type="text/html" href="https://wiki.scout.clutch.engineering/index.php?title=Module:Languages&amp;action=history"/>
	<updated>2026-04-17T19:33:23Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.3</generator>
	<entry>
		<id>https://wiki.scout.clutch.engineering/index.php?title=Module:Languages&amp;diff=10&amp;oldid=prev</id>
		<title>Featherless: Created page with &quot;-- Ported from https://wiki.openstreetmap.org/wiki/Module:Languages on Sep 2, 2025.  local p = {} local config = mw.loadData(&quot;Module:Languages/config&quot;) 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(&quot;^(%w%w%w?):&quot;) or 		title.text:match(&quot;^(%w%w%w?%-%w%w%w?%w?...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.scout.clutch.engineering/index.php?title=Module:Languages&amp;diff=10&amp;oldid=prev"/>
		<updated>2025-09-02T15:10:13Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;-- Ported from https://wiki.openstreetmap.org/wiki/Module:Languages on Sep 2, 2025.  local p = {} local config = mw.loadData(&amp;quot;Module:Languages/config&amp;quot;) 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(&amp;quot;^(%w%w%w?):&amp;quot;) or 		title.text:match(&amp;quot;^(%w%w%w?%-%w%w%w?%w?...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Ported from https://wiki.openstreetmap.org/wiki/Module:Languages on Sep 2, 2025.&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local config = mw.loadData(&amp;quot;Module:Languages/config&amp;quot;)&lt;br /&gt;
local siteLanguage = mw.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
--- Returns the language pseudonamespace in the title of a page in the main&lt;br /&gt;
--- namespace, or nil if the title contains no pseudonamespace.&lt;br /&gt;
function p.pseudoNamespaceFromTitle(title)&lt;br /&gt;
	local pseudoNS = title.text:match(&amp;quot;^(%w%w%w?):&amp;quot;) or&lt;br /&gt;
		title.text:match(&amp;quot;^(%w%w%w?%-%w%w%w?%w?):&amp;quot;)&lt;br /&gt;
	-- A few pseudonamespaces indicate topics rather than languages.&lt;br /&gt;
	if pseudoNS and config.languageNamesByCode[pseudoNS:lower()] then&lt;br /&gt;
		return pseudoNS&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Infers and returns the given title’s page language, defaulting to the wiki’s&lt;br /&gt;
--- content language.&lt;br /&gt;
function p.languageFromTitle(title, fallback)&lt;br /&gt;
	-- Language-specific namespace&lt;br /&gt;
	local ns = title.subjectNsText&lt;br /&gt;
	if config.namespacesByLanguage[ns:lower()] then&lt;br /&gt;
		return ns:lower()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Pseudonamespace in the main namespace&lt;br /&gt;
	local pseudoNS = p.pseudoNamespaceFromTitle(title)&lt;br /&gt;
	return pseudoNS and pseudoNS:lower() or fallback or siteLanguage:getCode()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Guesses the source title from the given title, which may be the source or a&lt;br /&gt;
--- translation.&lt;br /&gt;
function p.sourceTitleFromTitle(title)&lt;br /&gt;
	local pseudoNS = p.pseudoNamespaceFromTitle(title)&lt;br /&gt;
	if pseudoNS then&lt;br /&gt;
		local sourcePageName = title.text:sub(#pseudoNS + 2)&lt;br /&gt;
		return mw.title.new(sourcePageName, title.nsText)&lt;br /&gt;
	elseif config.namespacesByLanguage[title.subjectNsText:lower()] then&lt;br /&gt;
		return mw.title.new(title.text, title.isTalkPage and 1 or 0)&lt;br /&gt;
	else&lt;br /&gt;
		return title&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Quickly uppercases the first character of the string, disregarding Unicode.&lt;br /&gt;
local function ucfirst(s)&lt;br /&gt;
	return s:sub(1, 1):upper() .. s:sub(2, -1)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Returns the page name of a translation in the given language.&lt;br /&gt;
--- If simulateLangNS is true and the page lies in a non-content namespace, the&lt;br /&gt;
--- pseudonamespace is capitalized to mimic a dedicated language namespace.&lt;br /&gt;
function p.translationPageName(languageCode, sourceTitle, simulateLangNS)&lt;br /&gt;
	local isInMainNS = sourceTitle.exists and #sourceTitle.subjectNsText == 0&lt;br /&gt;
	&lt;br /&gt;
	local pageNameParts = {&lt;br /&gt;
		sourceTitle.text,&lt;br /&gt;
	}&lt;br /&gt;
	if not sourceTitle.exists then&lt;br /&gt;
		return table.concat(pageNameParts, &amp;quot;:&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if isInMainNS and config.namespacesByLanguage[languageCode] then&lt;br /&gt;
		local ns = config.namespacesByLanguage[languageCode]&lt;br /&gt;
		if sourceTitle.isTalkPage then&lt;br /&gt;
			ns = mw.site.namespaces[ns].talk.name&lt;br /&gt;
		end&lt;br /&gt;
		if #ns &amp;gt; 0 then&lt;br /&gt;
			table.insert(pageNameParts, 1, ns)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		local pseudoNS = ucfirst(languageCode)&lt;br /&gt;
		local langNS = config.namespacesByLanguage[languageCode]&lt;br /&gt;
		if langNS and (simulateLangNS or #langNS == 0) then&lt;br /&gt;
			pseudoNS = langNS&lt;br /&gt;
		end&lt;br /&gt;
		if #pseudoNS &amp;gt; 0 then&lt;br /&gt;
			table.insert(pageNameParts, 1, pseudoNS)&lt;br /&gt;
		end&lt;br /&gt;
		if #sourceTitle.nsText &amp;gt; 0 then&lt;br /&gt;
			table.insert(pageNameParts, 1, sourceTitle.nsText)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return table.concat(pageNameParts, &amp;quot;:&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Returns a link to a wiki page.&lt;br /&gt;
local function listItem(languageCode, pageName, label)&lt;br /&gt;
	local link = &amp;quot;&amp;lt;span dir=\&amp;quot;auto\&amp;quot; lang=\&amp;quot;&amp;quot; .. languageCode .. &amp;quot;\&amp;quot;&amp;gt;[[:&amp;quot; .. pageName .. &amp;quot;|&amp;amp;nbsp;&amp;quot; .. label .. &amp;quot;&amp;amp;nbsp;]]&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- By default, hlist inserts an interpunct as CSS generated content after&lt;br /&gt;
	-- each list item. [[MediaWiki:Common.css]] hides redlinks but not the&lt;br /&gt;
	-- interpuncts, which follow the redlinks visually but aren’t siblings.&lt;br /&gt;
	-- This module uses hlist-with-seps, so hlist-sep gets the interpunct&lt;br /&gt;
	-- instead of the list item. As a sibling of the redlink, hlist-sep gets&lt;br /&gt;
	-- hidden along with the redlink.&lt;br /&gt;
	local sep = mw.html.create(&amp;quot;span&amp;quot;)&lt;br /&gt;
	sep:addClass(&amp;quot;hlist-sep&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local li = mw.html.create(&amp;quot;li&amp;quot;)&lt;br /&gt;
	li:wikitext(link)&lt;br /&gt;
	return tostring(li)&lt;br /&gt;
end&lt;br /&gt;
p.listItem = listItem&lt;br /&gt;
&lt;br /&gt;
--- Returns an unordered list of links to each possible translation page.&lt;br /&gt;
function p.languageList(currentTitle, sourceTitle)&lt;br /&gt;
	local currentLanguage = p.languageFromTitle(currentTitle)&lt;br /&gt;
	local isInMainNS = #sourceTitle.subjectNsText == 0&lt;br /&gt;
	&lt;br /&gt;
	local listItems = {}&lt;br /&gt;
	for i, code in ipairs(config.languageCodes) do&lt;br /&gt;
		-- Link to the translation.&lt;br /&gt;
		local pageName&lt;br /&gt;
		if code == currentLanguage then&lt;br /&gt;
			-- Translations’ page names may themselves be translated, so force&lt;br /&gt;
			-- the current page to ensure that the link is boldfaced.&lt;br /&gt;
			pageName = currentTitle.fullText&lt;br /&gt;
		else&lt;br /&gt;
			pageName = p.translationPageName(code, sourceTitle)&lt;br /&gt;
			&lt;br /&gt;
			-- Languages with their own namespaces either uppercase or titlecase&lt;br /&gt;
			-- pages in non-content namespaces.&lt;br /&gt;
			if not isInMainNS and config.namespacesByLanguage[code]&lt;br /&gt;
				and not mw.title.new(pageName, sourceTitle.nsText).exists then&lt;br /&gt;
				pageName = p.translationPageName(code, sourceTitle, true)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local item = listItem(code, pageName, config.languageNamesByCode[code])&lt;br /&gt;
		&lt;br /&gt;
		-- Add the current page to a tracking category if a translation is&lt;br /&gt;
		-- unavailable in a language that has a dedicated namespace.&lt;br /&gt;
		if config.namespacesByLanguage[code] and&lt;br /&gt;
			not mw.title.new(pageName, sourceTitle.nsText).exists then&lt;br /&gt;
			local category = &amp;quot;Category:&amp;quot; ..&lt;br /&gt;
				config.unavailablePageCategoryNames[code]&lt;br /&gt;
			local sortingKey = currentLanguage .. currentTitle.text&lt;br /&gt;
			item = item .. &amp;quot;[[&amp;quot; .. category .. &amp;quot;|&amp;quot; .. sortingKey .. &amp;quot;]]&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		table.insert(listItems, item)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return table.concat(listItems, &amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Returns the current page’s language based on either the page’s title or its&lt;br /&gt;
--- content language (specified by the pagelang argument).&lt;br /&gt;
function p.currentPageLanguage(frame)&lt;br /&gt;
	local currentTitle = mw.title.getCurrentTitle()&lt;br /&gt;
	return p.languageFromTitle(currentTitle, frame.args.pagelang)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Guesses the source title from the given title, which may be the source or a&lt;br /&gt;
--- translation.&lt;br /&gt;
function p.sourceTitle(frame)&lt;br /&gt;
	local currentTitle = mw.title.getCurrentTitle()&lt;br /&gt;
	&lt;br /&gt;
	local sourcePageName = #(frame.args[1] or &amp;quot;&amp;quot;) &amp;gt; 0 and frame.args[1]&lt;br /&gt;
	return sourcePageName and mw.title.new(sourcePageName) or&lt;br /&gt;
		p.sourceTitleFromTitle(currentTitle)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Returns a flat list of links to translations of the current page, in&lt;br /&gt;
--- wikitext format.&lt;br /&gt;
function p.languages(frame)&lt;br /&gt;
	local currentTitle = mw.title.getCurrentTitle()&lt;br /&gt;
	local sourceTitle = p.sourceTitle(frame)&lt;br /&gt;
	&lt;br /&gt;
	local languageList = p.languageList(currentTitle, sourceTitle)&lt;br /&gt;
	local hlist = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
	hlist:addClass(&amp;quot;hlist&amp;quot;):addClass(&amp;quot;hlist-with-seps&amp;quot;):wikitext(languageList)&lt;br /&gt;
	&lt;br /&gt;
	local wikitext = tostring(hlist)&lt;br /&gt;
	&lt;br /&gt;
	-- By default, sort the page in categories by the title sans pseudotitle.&lt;br /&gt;
	if frame.args.defaultsort ~= &amp;quot;no&amp;quot; then&lt;br /&gt;
		local pseudoNS = p.pseudoNamespaceFromTitle(currentTitle)&lt;br /&gt;
		if pseudoNS then&lt;br /&gt;
			local sortingKey = currentTitle.text:sub(#pseudoNS + 2)&lt;br /&gt;
			-- If another DEFAULTSORT appeared earlier on the page, this&lt;br /&gt;
			-- DEFAULTSORT has no effect. If a different DEFAULTSORT appears&lt;br /&gt;
			-- later, it needs to specify “noerror” to suppress the error about&lt;br /&gt;
			-- conflicting DEFAULTSORTs.&lt;br /&gt;
			local defaultSort = frame:callParserFunction {&lt;br /&gt;
				name = &amp;quot;DEFAULTSORT&amp;quot;,&lt;br /&gt;
				args = {&lt;br /&gt;
					sortingKey,&lt;br /&gt;
					&amp;quot;noreplace&amp;quot;,&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			wikitext = wikitext .. defaultSort&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Featherless</name></author>
	</entry>
</feed>