Module:Dir
This module provides functions for determining whether a given language code is LTR or RTL.
- It uses the RTL or LTR status of languages defined in the data returned by Module:Dir/RTL overrides.
- Otherwise, if a language code is not mapped, it uses the language direction provided by the MediaWiki language library (but this only works for a limited number of distinct languages in the same viewed page, as the MediaWiki library sets a quota on the number of languages for which it can load localized data). For this reason, if a page uses lots of languages (for example with Template:Multilingual description) the data should be as somplete as possible to avoid reaching this quota.
This module includes a quick test function whose status is displayed at top of its description page: this status is OK if there are no errors in the data, i.e. only valid or known language codes are mapped.
Usage
From wikitext
From wikitext this module must be used through a template, Template:Dir. Please see the template page for documentation.
From Lua
From Lua you can use the module's isRTL
function. First, load the module:
<source lang="lua"> local dir = require('Module:Dir') </source>
Then you can use the function like this:
<source lang="lua"> dir.isRTL(lang) -- returns false or true </source>
- The lang variable is the language code string. The function returns true if the language for the code is detected as RTL, and it returns false if it is LTR or if the code is absent or invalid.
<source lang="lua"> dir.select(lang, rtl, ltr) -- returns either the rtl or ltr parameter values </source>
- Same thing except that you can define the value to return for each case.
In the Lua console, you can run the included quick test to scan the data defined in Module:Dir/RTL overrides: it provides a detailed report of invalid language codes, missing languages known by MediaWiki, and helps maintaining this data.
-- This module implements [[Template:Dir]]. -- local rtlOverrides = mw.loadData('Module:Dir/RTL overrides') -- !!! mw.loadData() is currently broken, it does NOT load anything 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 -- Used via a template {{Dir|language-code|wikitext if rtl|wikitext if ltr}} -- which just calls {{#invoke:Dir|main}}, the 3 parameters are automatically trimmed function p.main(frame) local args = frame:getParent().args -- Parameters used to transclude Template:Dir local code = trim(args[1]) local rtl = trim(args[2]) or 'rtl' local ltr = trim(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) -- 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 -- 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 = mw.language.fetchLanguageNames() for lang, _ in pairs(knownLangs) do 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. ok, value = pcall(function() return tostring(mw.language.new(lang):isRTL()) end) mw.log("Missing direction for language '" .. lang .. "', MediaWiki returns '" .. value .. "'") end end -- Sort and deduplicate language code values (by scanning backward) for data cleanup 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 end for i, lang in revipairs(ltrLangs) do if ltrLangs[i - 1] == ltrLangs[i] then table.remove(ltrLangs, i) end end -- Final presentation of current lists, sorted and deduplicated mw.log("local rtlLangs = { '" .. table.concat(rtlLangs, "', '") .. "' }") mw.log("local ltrLangs = { '" .. table.concat(ltrLangs, "', '") .. "' }") return true end }) --[==[ Enter this to run tests in the Lua console: =setmetatable(p).quickTests() --]==] return p