Module:Languages

local p = {} local config = mw.loadData("Module:Languages/config") 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 = "" .. 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 .. "" .. 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