Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Formatnum: Difference between revisions

From Neodyland Wiki
mNo edit summary
m fix most of the many issues (missing locales, incorrectly truncated numbers, truncated exponent...); most completely rewritten without the tricky code; language:formatNum() is almost completely broken
Line 2: Line 2:
local p = {}
local p = {}


local digit = { -- substitution of decimal digits for languages not supported by Language:formatNum() in core Lua libraries for MediaWiki
local digit = { -- substitution of decimal digits for languages not supported by mw.language:formatNum() in core Lua libraries for MediaWiki
["ml-old"] = { '൦', '൧', '൨', '൩', '൪', '൫', '൬', '൭', '൮', '൯' },
    ["ml-old"] = { '൦', '൧', '൨', '൩', '൪', '൫', '൬', '൭', '൮', '൯' },
["mn"]    = { '᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙'},
    ["mn"]    = { '᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙'},
["te"]    = { '౦', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯'},
    ["ta"]    = { '௦', '௧', '௨', '௩', '௪', '௫', '௬', '௭', '௮', '௯'},
["th"]    = { '๐', '๑', '๒', '๓', '๔', '๕', '๖', '๗', '๘', '๙'}
    ["te"]    = { '౦', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯'},
    ["th"]    = { '๐', '๑', '๒', '๓', '๔', '๕', '๖', '๗',     '๘', '๙'}
}
}


function p.main(frame)
function p.main(frame)
local pframe = frame:getParent()
    local pframe = frame:getParent()
local config = frame.args
    local prec = pframe.args.prec or ''
local prec  = pframe.args.prec
    local compact = (pframe.args.sep ~= '')
local number = pframe.args[1]
    local number = pframe.args[1] or pframe.args.number or ''
local lang  = pframe.args[2]
    -- validate the language parameter within parent frame
local sep    = pframe.args.sep or ""
    local lang  = pframe.args[2] or pframe.args.lang or ''
if not lang or not mw.language.isSupportedLanguage(lang) then  
    if lang == "arabic-indic" then -- only for compatibility ("arabic-indic" is not a SupportedLanguage)
lang = frame:preprocess( "{{int:lang}}" )
        lang = "fa" -- better support than "ks"
end
    elseif lang == '' or not mw.language.isSupportedLanguage(lang) then
return p._main(number, lang, sep, prec, config)
        -- Note that 'SupportedLanguages' are not necessarily 'BuiltinValidCodes', and so they are not necessarily
end
        -- 'KnownLanguages' (with a language name defined at least in the default localisation of the local wiki).
        -- But they all are ValidLanguageCodes (suitable as Wiki subpages or identifiers: no slash, colon, HTML tags, or entities)
function p._main(number, lang, sep, prec, config)
        -- In addition, they do not contain any capital letter in order to be unique in page titles (restriction inexistant in BCP47),
-- Preprocessing prec
        -- but they may violate the standard format of BCP47 language tags for specific needs in MediaWiki.
local precNum = tonumber(prec)
        -- Empty/unspecified and unsupported languages are treated here in Commons using the user's language,
if precNum ~= nil and precNum > 0 and tonumber(number) ~= nil then
        -- instead of the local 'ContentLanguage' of the Wiki.
if string.find(tostring(number), "%.") ~= nil then
        lang = frame:preprocess("{{int:lang}}") or ''
if (string.len(number) - string.find(tostring(number), "%.")) < precNum then
    end
precnumber = "" .. number .. string.rep("0", precNum - (string.len(number) - string.find(tostring(number), "%.")))
    return p.formatNum(number, lang, prec, compact)
elseif (string.len(number) - string.find(tostring(number), "%.")) > precNum then
end
local proc = string.gsub(number, "0+$", "")
 
if (string.len(proc) - string.find(tostring(proc), "%.")) < precNum then
function p.formatNum(number, lang, prec, compact)
precnumber = proc .. string.rep("0", precNum - (string.len(proc) - string.find(tostring(proc), "%.")))
 
else
    -- Do not alter the specified value when it is not a valid number, return it as is
precnumber = proc
    local value = tonumber(number)
end
    if value == nil then
elseif (string.len(number) - string.find(tostring(number), "%.")) == precNum then
        return number
precnumber = number
    end
end
    -- Basic ASCII-only formatting (without paddings)
else
    number = tostring(value)
precnumber = "" .. number .. "." .. string.rep("0", prec)
 
end
    -- Check the presence of an exponent (incorrectly managed in mw.language:FormatNum() and even forgotten due to an internal bug, e.g. in Hindi)
number = precnumber .. "1"
    local pos = string.find(number, '[Ee]')
precA = "true"
    local exponent
end
    if pos ~= nil then
        exponent = string.sub(number, pos + 1, string.len(number))
if lang == "arabic-indic" then
        number = string.sub(number, 1, pos - 1)
lang = "ks"
    else
end
        exponent = ''
    end
-- Formatnum
 
if tonumber(number) ~= nil and mw.language.isKnownLanguageTag(lang) == true then
    -- Check the minimum precision requested
formatnum = mw.getLanguage( lang ):formatNum( tonumber(number) )
    prec = tonumber(prec) -- nil if not specified as a true number
else
    if prec ~= nil then
formatnum = number
        if prec < 0 or prec ~= math.floor(prec) then
formatA = "true"
            prec = nil -- discard an incorrect precision (not a positive integer)
end
        elseif prec > 14 then
            prec = 14 -- maximum precision supported by tostring(number)
-- Formatnum, special cases for substitution of digits
        end
local numsc = formatnum
    end
if digit[lang] then
 
for i, v in ipairs( digit[lang] ) do
    -- Preprocess the minimum precision in the ASCII string
numsc = mw.ustring.gsub(numsc, tostring(i-1), v)
    local dot
end
    if (prec or 0) > 0 then
end
        pos = string.find(number, '.', 1, true) -- plain search, no regexp
        if pos ~= nil then
--Postprocessing prec
            prec = pos + prec - string.len(number) -- effective number of trailing decimals to add or remove
if precA == "true" then
            dot = '' -- already present
postprec = mw.ustring.sub(numsc, 1, (mw.ustring.len(numsc) - 1))
        else
else
            dot = '.' -- must be added
postprec = numsc
        end
end
    else
        dot = '' -- don't add dot
-- separator
        prec = 0 -- don't alter the precision
if sep ~= "" and formatA ~= "true" then
    end
local replace = mw.ustring.gsub( "", "%%", "%%%%" )
 
local separator = mw.ustring.sub(mw.getLanguage(lang):formatNum(tonumber("10000")), 3, 3)
    if lang ~= nil and mw.language.isKnownLanguageTag(lang) == true then
if tostring(mw.ustring.find(separator, "%s")) == "1" then
        local language = mw.getLanguage(lang)
pattern = mw.ustring.format(separator, "%s")
        local zero = language:formatNum(tonumber("0"))
elseif tostring(mw.ustring.find(separator, "%p")) == "1" then
        local groupsep = mw.ustring.sub(language:formatNum(tonumber("10000")), 3, 3) -- FIXME: is it always the 3rd character of "10,000" in all locales?
pattern = mw.ustring.gsub(separator, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1")
        groupsep = mw.ustring.gsub(groupsep, '([$%%()*+%-.?%[%]^])', '%%%1') -- properly escape special characters in the separator string into a pattern
else
        -- Convert number to localized digits, decimal separator, and group separators
pattern = ""
        number = language:formatNum(tonumber(number)) -- caveat: can load localized resources for up to 20 languages
end
        if compact then
return tostring(mw.ustring.gsub( postprec, pattern, replace ))
            -- Remove grouping separators from number
else
            number = mw.ustring.gsub(number, groupsep, '')
return postprec
        end
end
 
        -- Postprocessing the precision
        if prec > 0 then
            number = number .. dot .. mw.ustring.rep(zero, prec)
        elseif prec < 0 then
            -- TODO: rounding of last decimal; here only truncate decimals in excess
            number = mw.ustring.sub(number, 1, mw.ustring.len(number) + prec)
        end
 
        -- Append the localized base-10 exponent without grouping separators (there's no reliable way to detect a localized leading symbol 'E')
        if exponent ~= '' then
            number = number .. 'e' .. mw.ustring.gsub(language:formatNum(tonumber(exponent)), groupsep, '')
        end
    else -- not localized, ASCII only
        -- Postprocessing the precision
        if prec > 0 then
            number = number .. dot .. mw.string.rep('0', prec)
        elseif prec < 0 then
            -- TODO: rounding of last decimal; here only truncate decimals in excess
            number = mw.string.sub(number, 1, mw.string.len(number) + prec)
        end
 
        -- Append the base-10 exponent
        if exponent ~= '' then
            number = number .. 'e' .. exponent
        end
    end
 
    -- Special cases for substitution of ASCII digits (missing support in Lua core libraries for some languages)
    if digit[lang] then
        for i, v in ipairs(digit[lang]) do
            number = mw.ustring.gsub(number, tostring(i - 1), v)
        end
    end
 
    return number
end
end


return p
return p

Revision as of 05:22, 8 April 2015

Module documentation[ create · purge ]
This documentation is transcluded from Module:Formatnum/doc.
-- This module is intended to replace the functionality of Template:Formatnum and related templates.
local p = {}

local digit = { -- substitution of decimal digits for languages not supported by mw.language:formatNum() in core Lua libraries for MediaWiki
    ["ml-old"] = { '൦', '൧', '൨', '൩', '൪', '൫', '൬', '൭', '൮', '൯' },
    ["mn"]     = { '᠐', '᠑', '᠒', '᠓', '᠔', '᠕', '᠖', '᠗', '᠘', '᠙'},
    ["ta"]     = { '௦', '௧', '௨', '௩', '௪', '௫', '௬', '௭', '௮', '௯'},
    ["te"]     = { '౦', '౧', '౨', '౩', '౪', '౫', '౬', '౭', '౮', '౯'},
    ["th"]     = { '๐', '๑', '๒', '๓', '๔', '๕', '๖', '๗',     '๘', '๙'}
}

function p.main(frame)
    local pframe = frame:getParent()
    local prec = pframe.args.prec or ''
    local compact = (pframe.args.sep ~= '')
    local number = pframe.args[1] or pframe.args.number or ''
    -- validate the language parameter within parent frame
    local lang   = pframe.args[2] or pframe.args.lang or ''
    if lang == "arabic-indic" then -- only for compatibility ("arabic-indic" is not a SupportedLanguage)
        lang = "fa" -- better support than "ks"
    elseif lang == '' or not mw.language.isSupportedLanguage(lang) then
        -- Note that 'SupportedLanguages' are not necessarily 'BuiltinValidCodes', and so they are not necessarily
        -- 'KnownLanguages' (with a language name defined at least in the default localisation of the local wiki).
        -- But they all are ValidLanguageCodes (suitable as Wiki subpages or identifiers: no slash, colon, HTML tags, or entities)
        -- In addition, they do not contain any capital letter in order to be unique in page titles (restriction inexistant in BCP47),
        -- but they may violate the standard format of BCP47 language tags for specific needs in MediaWiki.
        -- Empty/unspecified and unsupported languages are treated here in Commons using the user's language,
        -- instead of the local 'ContentLanguage' of the Wiki.
        lang = frame:preprocess("{{int:lang}}") or ''
    end
    return p.formatNum(number, lang, prec, compact)
end

function p.formatNum(number, lang, prec, compact)

    -- Do not alter the specified value when it is not a valid number, return it as is
    local value = tonumber(number)
    if value == nil then
        return number
    end
    -- Basic ASCII-only formatting (without paddings)
    number = tostring(value)

    -- Check the presence of an exponent (incorrectly managed in mw.language:FormatNum() and even forgotten due to an internal bug, e.g. in Hindi)
    local pos = string.find(number, '[Ee]')
    local exponent
    if pos ~= nil then
        exponent = string.sub(number, pos + 1, string.len(number))
        number = string.sub(number, 1, pos - 1)
    else
        exponent = ''
    end

    -- Check the minimum precision requested
    prec = tonumber(prec) -- nil if not specified as a true number
    if prec ~= nil then
        if prec < 0 or prec ~= math.floor(prec) then
            prec = nil -- discard an incorrect precision (not a positive integer)
        elseif prec > 14 then
            prec = 14 -- maximum precision supported by tostring(number)
        end
    end

    -- Preprocess the minimum precision in the ASCII string
    local dot
    if (prec or 0) > 0 then
        pos = string.find(number, '.', 1, true) -- plain search, no regexp
        if pos ~= nil then
            prec = pos + prec - string.len(number) -- effective number of trailing decimals to add or remove
            dot = '' -- already present
        else
            dot = '.' -- must be added
        end
    else
        dot = '' -- don't add dot
        prec = 0 -- don't alter the precision
    end

    if lang ~= nil and mw.language.isKnownLanguageTag(lang) == true then
        local language = mw.getLanguage(lang)
        local zero = language:formatNum(tonumber("0"))
        local groupsep = mw.ustring.sub(language:formatNum(tonumber("10000")), 3, 3) -- FIXME: is it always the 3rd character of "10,000" in all locales?
        groupsep = mw.ustring.gsub(groupsep, '([$%%()*+%-.?%[%]^])', '%%%1') -- properly escape special characters in the separator string into a pattern
        -- Convert number to localized digits, decimal separator, and group separators
        number = language:formatNum(tonumber(number)) -- caveat: can load localized resources for up to 20 languages
        if compact then
            -- Remove grouping separators from number
            number = mw.ustring.gsub(number, groupsep, '')
        end

        -- Postprocessing the precision
        if prec > 0 then
            number = number .. dot .. mw.ustring.rep(zero, prec)
        elseif prec < 0 then
            -- TODO: rounding of last decimal; here only truncate decimals in excess
            number = mw.ustring.sub(number, 1, mw.ustring.len(number) + prec)
        end

        -- Append the localized base-10 exponent without grouping separators (there's no reliable way to detect a localized leading symbol 'E')
        if exponent ~= '' then
            number = number .. 'e' .. mw.ustring.gsub(language:formatNum(tonumber(exponent)), groupsep, '')
        end
    else -- not localized, ASCII only
        -- Postprocessing the precision
        if prec > 0 then
            number = number .. dot .. mw.string.rep('0', prec)
        elseif prec < 0 then
            -- TODO: rounding of last decimal; here only truncate decimals in excess
            number = mw.string.sub(number, 1, mw.string.len(number) + prec)
        end

        -- Append the base-10 exponent
        if exponent ~= '' then
            number = number .. 'e' .. exponent
        end
    end

    -- Special cases for substitution of ASCII digits (missing support in Lua core libraries for some languages)
    if digit[lang] then
        for i, v in ipairs(digit[lang]) do
            number = mw.ustring.gsub(number, tostring(i - 1), v)
        end
    end

    return number
end

return p
Cookies help us deliver our services. By using our services, you agree to our use of cookies.