Module documentation
local insert = table.insert
local remove = table.remove
local myFrame = mw.getCurrentFrame()
local myLang = myFrame:callParserFunction('Int', 'Lang'):lower():gsub('_', '-')
local myLangObj = mw.language.new(myLang)
local myFallbacks = myLangObj:getFallbackLanguages()
for i, lang in ipairs(myFallbacks) do
    lang = lang:lower():gsub('_', '-')
    if lang == myLang then
        remove(myFallbacks, i)
        break
    end
end
insert(myFallbacks, 1, myLang)

local p = {}

function p.main(frame)
    local source, anchor
    local args = {}
    for k, v in pairs(frame:getParent().args) do
        if type(k) == 'string' and type(v) == 'string' then
            v = v:gsub('^%s+(.-)%s+$', '%1') -- Trim texts given in argument values.
            -- Split argument keys by language code (separated by any non-letter non-digit character);
            -- this allows setting the same value for multiple languages.
            for lang in k:lower():gsub('_', '-'):gfind('[-0-9a-z]+') do
                if lang == 'source' then
                    source = v
                elseif lang == 'anchor' then
                    anchor = v
                else -- if not args[lang] then
                    args[lang] = v
                end
            end
        end
    end
    for i, lang in ipairs(myFallbacks) do
        local result = args[lang]
        if result and result ~= '' then
            if lang == myLang then
                return result
            end
            return '<bdi style="background:#FCC;color:#222"' .. (anchor and (' id="' .. anchor .. '"') or '') ..
                ' lang="' .. frame:expandTemplate{title = 'Template:BCP47', args = {lang}} .. '">' .. result .. '</bdi>' ..
                (source and '<sup style="font-size:xx-small"><bdi lang="en" dir="ltr">[[:' .. source .. '|&#91;Translate this message&#93;]]</bdi></sup>' or '')
        end
    end
    return source and '<sup style="font-size:xx-small"><bdi lang="en" dir="ltr">[[:' .. source .. '|&#91;Translate this message&#93;]]</bdi></sup>' or ''
end

return p