Module:LangSwitcher: Difference between revisions
From Heroes of Might and Magic: Olden Era Official Wiki
Created page with "-- Module:LangSwitcher -- Language subpage switcher for self-hosted MediaWiki -- Usage: -- {{#invoke:LangSwitcher|render -- | langs = en,sv,da,fi -- | labels = en=English,sv=Svenska,da=Dansk,fi=Suomi -- | icon = 🌐 -- | class = hh-lang-switcher -- }} -- -- Behavior: -- * Determines base page and current language from title/subpage -- * Scans configured langs and checks if base/xx exists -- * Includes the base page itself as the "default" languag..." |
mNo edit summary |
||
| Line 28: | Line 28: | ||
end | end | ||
for part in s:gmatch("([^,]+)") do | for part in s:gmatch("([^,]+)") do | ||
table.insert(t, | local v = trim(part) | ||
if v ~= "" then | |||
table.insert(t, v) -- append | |||
end | |||
end | end | ||
return t | return t | ||
| Line 52: | Line 55: | ||
local full = title.fullText | local full = title.fullText | ||
local base, lang = full, nil | local base, lang = full, nil | ||
-- | -- Accept language subpages like Base/xx or Base/pt-br (2–10 letters/hyphens) | ||
local b, l = full:match("^(.-)/([A-Za-z%-][A-Za-z%-][A-Za-z%-]*)$") | local b, l = full:match("^(.-)/([A-Za-z%-][A-Za-z%-][A-Za-z%-]*)$") | ||
if b and l then | if b and l then | ||
| Line 83: | Line 85: | ||
local icon = args.icon or "" | local icon = args.icon or "" | ||
local base, currentLang = getTitleParts() | |||
local base, currentLang | |||
local defaultLang = trim(args.default or (langs[1] or "en")):lower() | local defaultLang = trim(args.default or (langs[1] or "en")):lower() | ||
local function labelFor(code) | local function labelFor(code) | ||
return labels[code] or code | return labels[code] or code | ||
end | end | ||
-- | -- Build ordered list, starting with defaultLang | ||
local seen = {} | local seen = {} | ||
local ordered = {} | local ordered = {} | ||
local function add(code) | |||
if not code or code == "" then | |||
return | |||
end | |||
local lc = code:lower() | local lc = code:lower() | ||
if not seen[lc] then | if not seen[lc] then | ||
| Line 114: | Line 108: | ||
end | end | ||
add(defaultLang) | |||
for _, code in ipairs(langs) do | |||
add(code) | |||
end | |||
local items = {} | |||
for _, code in ipairs(ordered) do | for _, code in ipairs(ordered) do | ||
local target = (code == defaultLang) and base or (base .. "/" .. code) | local target = (code == defaultLang) and base or (base .. "/" .. code) | ||
| Line 124: | Line 124: | ||
isActive = (currentLang == code) | isActive = (currentLang == code) | ||
else | else | ||
isActive = (code == defaultLang) | isActive = (code == defaultLang) | ||
end | end | ||
| Line 138: | Line 137: | ||
content = makeLink(target, label) | content = makeLink(target, label) | ||
else | else | ||
content = makeLink(target, label) -- redlink | content = makeLink(target, label) -- redlink | ||
end | end | ||
Revision as of 13:02, 30 October 2025
Documentation for this module may be created at Module:LangSwitcher/doc
-- Module:LangSwitcher
-- Language subpage switcher for self-hosted MediaWiki
-- Usage:
-- {{#invoke:LangSwitcher|render
-- | langs = en,sv,da,fi
-- | labels = en=English,sv=Svenska,da=Dansk,fi=Suomi
-- | icon = 🌐
-- | class = hh-lang-switcher
-- }}
--
-- Behavior:
-- * Determines base page and current language from title/subpage
-- * Scans configured langs and checks if base/xx exists
-- * Includes the base page itself as the "default" language (first in langs or 'en')
-- * Marks current selection with class "active"
-- * Skips links for languages without existing pages (optional flag to show “redlinks”)
local p = {}
local function trim(s)
return (s or ""):gsub("^%s+", ""):gsub("%s+$", "")
end
local function splitCSV(s)
local t = {}
if not s or s == "" then
return t
end
for part in s:gmatch("([^,]+)") do
local v = trim(part)
if v ~= "" then
table.insert(t, v) -- append
end
end
return t
end
local function parseKVList(s)
-- Parse "en=English,sv=Svenska"
local out = {}
if not s or s == "" then
return out
end
for pair in s:gmatch("([^,]+)") do
local k, v = pair:match("^%s*([^=]+)%s*=%s*(.-)%s*$")
if k and v then
out[trim(k)] = trim(v)
end
end
return out
end
local function getTitleParts()
local title = mw.title.getCurrentTitle()
local full = title.fullText
local base, lang = full, nil
-- Accept language subpages like Base/xx or Base/pt-br (2–10 letters/hyphens)
local b, l = full:match("^(.-)/([A-Za-z%-][A-Za-z%-][A-Za-z%-]*)$")
if b and l then
base, lang = b, l:lower()
end
return base, lang, title
end
local function exists(page)
local t = mw.title.new(page)
return t and t.exists
end
local function makeLink(page, label)
return string.format('[[%s|%s]]', page, label)
end
local function escapeHtml(s)
return mw.text.nowiki(s or "")
end
function p.render(frame)
local args = frame:getParent() and frame:getParent().args or frame.args
local langs = splitCSV(args.langs or args.languages or "en")
local labels = parseKVList(args.labels or "")
local showMissing = (args.show_missing or ""):lower() == "yes"
local wrapperClass = trim(args.class or "lang-switcher")
local icon = args.icon or ""
local base, currentLang = getTitleParts()
local defaultLang = trim(args.default or (langs[1] or "en")):lower()
local function labelFor(code)
return labels[code] or code
end
-- Build ordered list, starting with defaultLang
local seen = {}
local ordered = {}
local function add(code)
if not code or code == "" then
return
end
local lc = code:lower()
if not seen[lc] then
table.insert(ordered, lc)
seen[lc] = true
end
end
add(defaultLang)
for _, code in ipairs(langs) do
add(code)
end
local items = {}
for _, code in ipairs(ordered) do
local target = (code == defaultLang) and base or (base .. "/" .. code)
local pageExists = exists(target)
if pageExists or showMissing then
local isActive
if currentLang then
isActive = (currentLang == code)
else
isActive = (code == defaultLang)
end
local liClass = "lang-item lang-" .. code
if isActive then
liClass = liClass .. " active"
end
local label = labelFor(code)
local content
if pageExists then
content = makeLink(target, label)
else
content = makeLink(target, label) -- redlink
end
table.insert(items, string.format('<li class="%s">%s</li>', liClass, content))
end
end
if #items == 0 then
return ""
end
local iconHtml = icon ~= "" and string.format('<span class="lang-icon">%s</span>', escapeHtml(icon)) or ""
local html = {}
table.insert(html, string.format('<nav class="%s" role="navigation" aria-label="Languages">', wrapperClass))
table.insert(html, iconHtml)
table.insert(html, '<ul class="lang-list">')
table.insert(html, table.concat(items))
table.insert(html, '</ul>')
table.insert(html, '</nav>')
return table.concat(html)
end
return p


