Module:I18n

-- -- I18n storage module for FANDOM. -- @module     i18n -- @version    1.0.5 -- @usage      require("Dev:I18n") -- @author     KockaAdmiralac -- @author     Speedit -- @release    alpha; untested -- @todo       Fallbacks and unit testing.

-- Module package. local i18n = {} -- I18n datastore class. -- @classmod   i18nd local i18nd = {} -- Module variables. local title = mw.title.getCurrentTitle -- Module dependencies. local bool = require('Dev:Yesno') local fallbacks = require('Dev:Fallbacklist')

-- Datastore language setter to user language. -- @name       i18nd:useUserLang function i18nd.useUserLang(i18nd) i18nd.defaultLang = i18n.getLang or i18nd.defaultLang end

-- Datastore language setter to user language. -- @name       i18nd:useContentLang function i18nd.useContentLang(i18nd) i18nd.defaultLang = mw.language.getContentLanguage:getCode end

-- Datastore language setter to specificed language. -- @name       i18nd:useLang -- @param      {string} code Language code to use. function i18nd.useLang(i18nd, code) i18nd.defaultLang = type(code) == 'string' and mw.language.isValidCode(code) == true and code or       i18nd.defaultLang end

-- Datastore message utility. -- @name       i18nd:msg -- @param      {table} data Data table for i18n messages. -- @param      {string} key Message key to return. -- @return     {string} Message key or ' '. -- @todo       Better fallback system with Dev:Fallbacklist. function i18nd.msg(i18nd, key, ...) if i18nd and key then -- Frame object. local frame = mw.getCurrentFrame -- Language handling. local lang = i18nd.defaultLang local msg for _, messages in ipairs(i18nd._messages) do           -- Message data. local msg = (messages[lang] or {})[key] -- Fallback support (experimental). for i, l in ipairs((fallbacks[lang] or {})) do               if type(msg) == 'nil' then msg = (messages[l] or {})[key] end end -- Internal fallback to 'en'. msg = type(msg) ~= 'nil' and msg or messages.en[key] -- Handling argument substitution from Scribunto. if type((arg or {})[1]) == 'table' then arg  = arg[1] arg.n = select( '#', arg ) end -- Handling argument substitution from Lua. if msg and (arg.n or 0) > 0 then msg = handleArgs(msg, arg) end if msg then return frame and frame:preprocess(mw.text.trim(msg)) or mw.text.trim(msg) end end return mw.text.nowiki('<' .. key .. '>') else error('missing arguments in i18nd:msg') end end

-- Argument substitution as $n where n > 0. -- @param      {string} msg Message to substitute arguments into. -- @param      {table} arg Arguments table to substitute. -- @return     {string} Resulting message. function handleArgs(msg, arg) for i, a in ipairs(arg) do       local ptn = '%$' .. i       msg, _ = type(i) == 'number' and string.gsub(msg, ptn, a) or           msg, nil end return msg end

-- Language code function. -- @usage -- @return     {string} code Language code. function i18n.getLang -- Function variables. local code = 'en' -- default language local frame = mw.getCurrentFrame -- Language argument test. if (frame or {}).args and frame.args.lang and mw.language.isValidCode(frame.args.lang) == true then code = frame.args.lang elseif frame and (frame:getParent or {}).args and mw.language.isValidCode(frame:getParent.args.uselang) == true then code = frame:getParent.args.uselang -- Subpage language test. elseif title.isSubpage then local text = title.subpageText code = mw.language.isValidCode(text) and text or lang -- User language fallback. elseif frame then code = frame:preprocess('') -- Content language fallback. else code = mw.language.getContentLanguage:getCode end return code end

-- I18n message datastore loader. -- @param      {string} source ROOTPAGENAME/path of target i18n submodule. -- @usage      require('Dev:Install').loadMessages(source) -- @raise      'no source supplied to i18n.loadMessages' -- @return     {table} i18n I18n datastore instance. function i18n.loadMessages(...) local ds   local i = 0 for _, source in ipairs(arg) do       if type(source) == 'string' and source ~= '' then i = i + 1 if not ds then -- Instantiate datastore. ds = {} i18nd.__index = i18nd setmetatable(ds, i18nd) -- Set default language. ds.defaultLang = i18n.getLang ds._messages = {} end source = string.gsub(source, '^.', string.upper) source = mw.ustring.find(source, ':') and source or 'Dev:' .. source .. '/i18n' ds._messages[i] = mw.loadData(source) end end if not ds then error('no source supplied to i18n.loadMessages') else -- Return datastore instance. return ds   end end

-- I18n message function. -- @param      {table} frame Frame table from invocation. -- @param      {string} frame.args[1] ROOTPAGENAME of i18n submodule. -- @param      {string} frame.args[2] Key of i18n message. -- @param      {string} frame.args.lang Default language of message (optional). -- @usage -- @raise      'missing arguments in i18n.getMsg' -- @return     {string} msg I18n message in localised language. function i18n.getMsg(frame) if frame and frame.args and frame.args[1] and frame.args[2] then -- Read frame arguments. local source = frame.args[1] local key = frame.args[2] -- Pass through extra arguments. local repl = {} for i, a in ipairs(frame.args) do           if type(i) == 'number' and i >= 3 then repl[i-2] = a           end end -- Load message data. local i18nd = i18n.loadMessages(source) -- Return message. return i18nd:msg(key, repl) else error('missing arguments in i18n.getMsg') end end

return i18n