Module:Dir: Difference between revisions
From Neodyland Wiki
More actions
create replacement for Template:Dir |
m 22 revisions imported |
||
| (21 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
-- This module implements [[Template:Dir]]. | --[==[ | ||
This module implements [[Template:Dir]]. | |||
Enter this to run tests in the Lua console: | |||
=getmetatable(p).quickTests() | |||
--]==] | |||
local rtlOverrides = require('Module:Dir/RTL overrides') | |||
local p = {} | local p = {} | ||
local function trim(s) | local function trim(s) | ||
if s and s ~= '' then s = tostring(s):match('^%s*(.-)%s*$') end | |||
if s == '' then return nil end | |||
return s | |||
end | end | ||
function p.rtlLangs(isRTL) | |||
if isRTL == nil then isRTL = true end | |||
return rtlOverrides[isRTL] or {} | |||
end | end | ||
function p.isRTL(code) | function p.isRTL(code) | ||
if type(code) ~= 'string' then return nil end | |||
local v = rtlOverrides[code] -- very fast and not limited in the number of supported languages | |||
if v ~= nil then return v end -- return it if mapped, otherwise use MediaWiki library: | |||
local success, ret = pcall(function () | |||
return mw.language.new(code):isRTL() -- expensive and limited to 20 languages per MediaWiki instance | |||
end) | |||
return success and ret | |||
end | end | ||
function p.select(code, rtl, ltr) | |||
if p.isRTL(code) then | |||
return rtl | |||
else | |||
return ltr | |||
end | |||
end | |||
-- The 3 parameters are automatically trimmed: | |||
-- Parameter 1 takes the default value from {{Int:Lang}} if it's empty or not specified. | |||
-- Parameter 2 can be named rtl, may be explicitly empty, otherwise takes the default value 'rtl' only if it's not specified. | |||
-- Parameter 3 can be named ltr, may be explicitly empty, otherwise takes the default value 'ltr' only if it's not specified. | |||
function p.main(frame) | function p.main(frame) | ||
local args = frame:getParent().args -- Parameters used to transclude Template:Dir | |||
local code = trim(args[1]) or frame:callParserFunction('Int', 'Lang') | |||
local rtl = trim(args.rtl or args[2] or 'rtl') | |||
local ltr = trim(args.ltr or args[3] or 'ltr') | |||
return p.select(code, rtl, ltr) | |||
end | end | ||
setmetatable(p, { quickTests = function () | |||
local rtlLangs = p.rtlLangs(true) | |||
local ltrLangs = p.rtlLangs(false) | |||
-- Basic check of data format | |||
local function checkLangs(name, langs) | |||
for k, lang in pairs(langs) do | |||
assert(type(k) == 'number' and k == math.floor(k) | |||
and type(lang) == 'string' and #lang >= 2 and #lang <= 16 | |||
and lang:find('^[a-z][%-0-9a-z]*[0-9a-z]$') == 1, | |||
": Invalid sequence of language codes, " .. name .. "['" .. k .. "'] = '" .. lang .. "'") | |||
end | |||
return true | |||
end | |||
local ok, msg | |||
ok, msg = pcall(checkLangs, 'rtlLangs', rtlLangs) | |||
if not ok then return false, msg end | |||
ok, msg = pcall(checkLangs, 'ltrLangs', ltrLangs) | |||
if not ok then return false, msg end | |||
-- Build inverse maps of languages having each direction | |||
local isrtl, isltr = {}, {} | |||
for _, lang in ipairs(rtlLangs) do isrtl[lang] = true end | |||
for _, lang in ipairs(ltrLangs) do isltr[lang] = true end | |||
-- Check conflicts using the two inverse maps | |||
for _, lang in ipairs(rtlLangs) do | |||
if isltr[lang] then return false, ": Direction conflict for '" .. lang .. "'" end | |||
end | |||
for _, lang in ipairs(ltrLangs) do | |||
if isrtl[lang] then return false, ": Direction conflict for '" .. lang .. "'" end | |||
end | |||
-- Log missing languages (allows filling the tables above) according to MediaWiki internal data | |||
local knownLangs, isKnownLang = mw.language.fetchLanguageNames(), {} | |||
for lang, _ in pairs(knownLangs) do | |||
isKnownLang[lang] = true | |||
if rtlOverrides[lang] == nil then -- only if we still don't have data for this language | |||
-- Note: we cannot check more than 20 languages at once, then MediaWiki raises an error. | |||
-- So this test only runs on the Lua console, where you can update the tables at top. | |||
-- This also means we cannot compare what MediaWiki returns with the direction we map here for all languages. | |||
ok, value = pcall(function() return tostring(mw.language.new(lang):isRTL()) end) | |||
mw.log("Warning: missing direction for language '" .. lang .. "', MediaWiki returns '" .. value .. "'") | |||
end | |||
end | |||
-- utility: reverse order iterator on sequences | |||
local function revipairs(t) | |||
return function(t, i) | |||
i = i - 1 | |||
local v = t[i] | |||
if v == nil then return nil end | |||
return i, v | |||
end, t, #t + 1 | |||
end | |||
-- Sort and deduplicate language code values (by scanning backward) for data cleanup | |||
-- Also log languages having a direction mapping in this module but still not known by MediaWiki | |||
table.sort(rtlLangs) | |||
table.sort(ltrLangs) | |||
for i, lang in revipairs(rtlLangs) do | |||
if rtlLangs[i - 1] == rtlLangs[i] then table.remove(rtlLangs, i) end | |||
if isKnownLang[lang] == nil then | |||
mw.log("RTL language '" .. lang .. "' still not known by Mediawiki (could be a missing alias or variant)") | |||
end | |||
end | |||
for i, lang in revipairs(ltrLangs) do | |||
if ltrLangs[i - 1] == ltrLangs[i] then table.remove(ltrLangs, i) end | |||
if isKnownLang[lang] == nil then | |||
mw.log("LTR language '" .. lang .. "' still not known by Mediawiki (could be a missing alias or variant)") | |||
end | |||
end | |||
-- Final presentation of current lists, sorted and deduplicated | |||
mw.log("----") | |||
mw.log("local rtlLangs = { '" .. table.concat(rtlLangs, "', '") .. "' }") | |||
mw.log("local ltrLangs = { '" .. table.concat(ltrLangs, "', '") .. "' }") | |||
return true | |||
end }) | |||
return p | return p | ||
Latest revision as of 06:04, 9 August 2026
This documentation is transcluded from Module:Dir/doc.
--[==[
This module implements [[Template:Dir]].
Enter this to run tests in the Lua console:
=getmetatable(p).quickTests()
--]==]
local rtlOverrides = require('Module:Dir/RTL overrides')
local p = {}
local function trim(s)
if s and s ~= '' then s = tostring(s):match('^%s*(.-)%s*$') end
if s == '' then return nil end
return s
end
function p.rtlLangs(isRTL)
if isRTL == nil then isRTL = true end
return rtlOverrides[isRTL] or {}
end
function p.isRTL(code)
if type(code) ~= 'string' then return nil end
local v = rtlOverrides[code] -- very fast and not limited in the number of supported languages
if v ~= nil then return v end -- return it if mapped, otherwise use MediaWiki library:
local success, ret = pcall(function ()
return mw.language.new(code):isRTL() -- expensive and limited to 20 languages per MediaWiki instance
end)
return success and ret
end
function p.select(code, rtl, ltr)
if p.isRTL(code) then
return rtl
else
return ltr
end
end
-- The 3 parameters are automatically trimmed:
-- Parameter 1 takes the default value from {{Int:Lang}} if it's empty or not specified.
-- Parameter 2 can be named rtl, may be explicitly empty, otherwise takes the default value 'rtl' only if it's not specified.
-- Parameter 3 can be named ltr, may be explicitly empty, otherwise takes the default value 'ltr' only if it's not specified.
function p.main(frame)
local args = frame:getParent().args -- Parameters used to transclude Template:Dir
local code = trim(args[1]) or frame:callParserFunction('Int', 'Lang')
local rtl = trim(args.rtl or args[2] or 'rtl')
local ltr = trim(args.ltr or args[3] or 'ltr')
return p.select(code, rtl, ltr)
end
setmetatable(p, { quickTests = function ()
local rtlLangs = p.rtlLangs(true)
local ltrLangs = p.rtlLangs(false)
-- Basic check of data format
local function checkLangs(name, langs)
for k, lang in pairs(langs) do
assert(type(k) == 'number' and k == math.floor(k)
and type(lang) == 'string' and #lang >= 2 and #lang <= 16
and lang:find('^[a-z][%-0-9a-z]*[0-9a-z]$') == 1,
": Invalid sequence of language codes, " .. name .. "['" .. k .. "'] = '" .. lang .. "'")
end
return true
end
local ok, msg
ok, msg = pcall(checkLangs, 'rtlLangs', rtlLangs)
if not ok then return false, msg end
ok, msg = pcall(checkLangs, 'ltrLangs', ltrLangs)
if not ok then return false, msg end
-- Build inverse maps of languages having each direction
local isrtl, isltr = {}, {}
for _, lang in ipairs(rtlLangs) do isrtl[lang] = true end
for _, lang in ipairs(ltrLangs) do isltr[lang] = true end
-- Check conflicts using the two inverse maps
for _, lang in ipairs(rtlLangs) do
if isltr[lang] then return false, ": Direction conflict for '" .. lang .. "'" end
end
for _, lang in ipairs(ltrLangs) do
if isrtl[lang] then return false, ": Direction conflict for '" .. lang .. "'" end
end
-- Log missing languages (allows filling the tables above) according to MediaWiki internal data
local knownLangs, isKnownLang = mw.language.fetchLanguageNames(), {}
for lang, _ in pairs(knownLangs) do
isKnownLang[lang] = true
if rtlOverrides[lang] == nil then -- only if we still don't have data for this language
-- Note: we cannot check more than 20 languages at once, then MediaWiki raises an error.
-- So this test only runs on the Lua console, where you can update the tables at top.
-- This also means we cannot compare what MediaWiki returns with the direction we map here for all languages.
ok, value = pcall(function() return tostring(mw.language.new(lang):isRTL()) end)
mw.log("Warning: missing direction for language '" .. lang .. "', MediaWiki returns '" .. value .. "'")
end
end
-- utility: reverse order iterator on sequences
local function revipairs(t)
return function(t, i)
i = i - 1
local v = t[i]
if v == nil then return nil end
return i, v
end, t, #t + 1
end
-- Sort and deduplicate language code values (by scanning backward) for data cleanup
-- Also log languages having a direction mapping in this module but still not known by MediaWiki
table.sort(rtlLangs)
table.sort(ltrLangs)
for i, lang in revipairs(rtlLangs) do
if rtlLangs[i - 1] == rtlLangs[i] then table.remove(rtlLangs, i) end
if isKnownLang[lang] == nil then
mw.log("RTL language '" .. lang .. "' still not known by Mediawiki (could be a missing alias or variant)")
end
end
for i, lang in revipairs(ltrLangs) do
if ltrLangs[i - 1] == ltrLangs[i] then table.remove(ltrLangs, i) end
if isKnownLang[lang] == nil then
mw.log("LTR language '" .. lang .. "' still not known by Mediawiki (could be a missing alias or variant)")
end
end
-- Final presentation of current lists, sorted and deduplicated
mw.log("----")
mw.log("local rtlLangs = { '" .. table.concat(rtlLangs, "', '") .. "' }")
mw.log("local ltrLangs = { '" .. table.concat(ltrLangs, "', '") .. "' }")
return true
end })
return p