Module:Spoken Wikipedia

local getArgs = require('Module:Arguments').getArgs

local yesno = require('Module:Yesno')

local Date = require('Module:Date')._Date

local lang = mw.language.new('en')

local cfg = mw.loadData('Module:Spoken Wikipedia/configuration')

p = {}

local function wikiError(message)

local ret = mw.html.create('div')

:addClass(cfg.i18n.class.err)

:wikitext(message)

:done()

return tostring(ret)

end

local function category(c, nocat)

if nocat then

return ''

else

return c

end

end

local function formatPageText(page)

if page then

return '' .. page .. ''

end

if mw.title.getCurrentTitle().namespace == 0 then

return cfg.i18n.this_article

else

return cfg.i18n.this_page

end

end

local function formatFileLength(filenames)

local length = 0

for _, filename in ipairs(filenames) do

local fileTitle = mw.title.new(filename, 'Media')

if fileTitle and fileTitle.file and fileTitle.file.exists then

length = length + fileTitle.file.length

end

end

-- Add 30 to offset the rounding down

local intervals = lang:getDurationIntervals(length + 30, { 'hours', 'minutes' })

local ret = string.format(

'%s %s',

intervals.minutes or 0,

intervals.minutes == 1 and cfg.i18n.minute or cfg.i18n.minutes

)

if intervals.hours then

ret = string.format(

'%s %s and %s',

intervals.hours,

intervals.hours == 1 and cfg.i18n.hour or cfg.i18n.hours,

ret

)

end

return '' .. ret .. ''

end

local function formatHeader(filenames, page)

local listento = mw.html.create('span')

:addClass(cfg.i18n.class.listento)

:wikitext(string.format(

cfg.i18n.listento,

formatPageText(page)

))

:done()

local file_length

if #filenames > 1 then

file_length = string.format(

cfg.i18n.n_files_length,

tostring(#filenames),

formatFileLength(filenames)

)

else

file_length = string.format(

cfg.i18n.one_file_length,

formatFileLength(filenames)

)

end

return mw.html.create('div')

:addClass(cfg.i18n.class.header)

:node(listento)

:wikitext(file_length)

:done()

end

local function formatIcon()

return mw.html.create('div')

:addClass(cfg.i18n.class.icon)

:wikitext(cfg.i18n.icon)

:done()

end

local function formatFiles(filenames, nocat)

if #filenames == 0 then

return wikiError(cfg.i18n.err.no_filename) ..

category(cfg.i18n.cat.no_filename, nocat)

end

-- TODO: the else branch really wants to be a mw.html

    object rather than wikitext

    -- version of the same, so that we can style the numbers nicer

    local files = {}

    if #filenames == 1 then

    table.insert(files, string.format(cfg.i18n.one_file, filenames[1]))

    else

    for i, filename in ipairs(filenames) do

    table.insert(files, string.format(cfg.i18n.n_files, filename, i))

    end

    end

    return mw.html.create('div')

    :addClass(cfg.i18n.class.files)

    :wikitext(table.concat(files))

    :done()

    :newline()

    end

    local function formatDateText(frame, dateArg, nocat)

    local d = dateArg and Date(dateArg) or nil

    return d and frame:expandTemplate{

    title = 'Start date', args = {

    d.year,

    d.month,

    d.day,

    df='y'

    }

    } or (wikiError(cfg.i18n.err.no_date) .. category(cfg.i18n.cat.no_date, nocat))

    end

    local function formatDisclaimer(frame, filenames, page, dateArg, nocat)

    local thisFileText = ''

    local disclaimer

    if #filenames == 1 then

    thisFileText = filenames[1]

    disclaimer = cfg.i18n.one_file_disclaimer

    else

    disclaimer = cfg.i18n.n_files_disclaimer

    end

    return mw.html.create('div')

    :addClass(cfg.i18n.class.disclaimer)

    :wikitext(string.format(

    disclaimer,

    thisFileText,

    formatPageText(page),

    formatDateText(frame, dateArg, nocat)

    ))

    :done()

    end

    local function formatFooter()

    return mw.html.create('div')

    :addClass(cfg.i18n.class.footer)

    :wikitext(cfg.i18n.footer)

    :done()

    end

    local function formatTopicon(frame, filenames)

    local wikilink

    if #filenames > 0 then

    wikilink = 'File:' .. filenames[1]

    else

    wikilink = cfg.i18n.topicon_multiwikilink

    end

    return frame:expandTemplate{

    title = "Top icon",

    args = {

    imagename = 'Sound-icon.svg',

    wikilink = wikilink,

    text = 'Listen to this article',

    id = 'spoken-icon'

    }

    }

    end

    local function extractFilenames(args)

    local filenames = {}

    for key, rawValue in ipairs(args) do

    local value = mw.text.trim(rawValue)

    if type(key) == "number" and value ~= '' then

    table.insert(filenames, value)

    end

    end

    return filenames

    end

    local function sidebox(nodes)

    root = mw.html.create('div')

    :addClass(cfg.i18n.class.box)

    for _, node in ipairs(nodes) do

    root:node(node)

    end

    return root

    end

    function main(frame)

    local args = getArgs(frame)

    -- Mandatory parameters

    local filenames = extractFilenames(args)

    local dateArg = args['date']

    -- Optional parameters

    local page = args['page']

    local nocat = yesno(args['nocat'], false) or false

    local root = sidebox({

    formatHeader(filenames, page),

    formatFiles(filenames, nocat),

    formatIcon(),

    formatDisclaimer(frame, filenames, page, dateArg, nocat),

    formatFooter()

    })

    if mw.title.getCurrentTitle().namespace == 0 then

    root:wikitext(formatTopicon(frame, filenames))

    root:wikitext(category(cfg.i18n.cat.articles, nocat))

    end

    return frame:extensionTag{

    name = 'templatestyles', args = { src = cfg.templatestyles }

    } .. tostring(root)

    end

    p.main = main

    return p