پودمان:Year in other calendars

از ویکی‌پدیا، دانشنامهٔ آزاد
پرش به: ناوبری، جستجو

توضیحات این پودمان می‌تواند در پودمان:Year in other calendars/توضیحات قرار گیرد.

-- Load dependencies.
local htmlBuilder = require( 'Module:HtmlBuilder' )
local makeNavbar = require( 'Module:Navbar' ).navbar
local numToRoman = require( 'Module:Roman' ).main
local numToArmenian = require( 'Module:Armenian' ).main
local getRegnal = require( 'Module:British regnal year' ).main
local japaneseEra = require( 'Module:Japanese calendar' ).era
 
-- Define constants.
local lang = mw.language.getContentLanguage()
local currentYear = tonumber( lang:formatDate( 'Y' ) )
 
--------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------
 
local function isInteger( num )
    num = tonumber( num )
    if num and math.floor( num ) == num and num ~= math.huge then
        return num
    else
        return false
    end
end
 
-- Converts strings of the format "n BC" to their corresponding
-- numerical values.
local function BCToNum( s )
    if type( s ) ~= 'string' then
        return nil
    end
    s = mw.ustring.match( mw.ustring.upper( s ), '^([1-9]%d*)%s*BC$' )
    if not s then
        return nil
    end
    local num = tonumber( s )
    num = ( num - 1 ) * -1
    return num
end
 
-- For BC years, returns a string with the year name appended with " BC".
-- Otherwise returns nil.
local function numToBC( num )
    num = isInteger( num )
    if not num then return end
    if num <= 0 then
        return mw.ustring.format( '%d BC', 1 - num )
    end
end
 
--------------------------------------------------------------------
-- Calendar box class definition
--------------------------------------------------------------------
 
local calendarBox = {}
calendarBox.__index = calendarBox
 
function calendarBox:new( init )
    init = type( init ) == 'table' and init or {}
    local obj = {}
    local pagename = mw.title.getCurrentTitle().text
 
    -- Set the year. If the year is specified as an argument, use that.
    -- Otherwise, use the page name if it is valid. If the pagename isn't
    -- valid, use the current year.
    local yearNum = isInteger( init.year )
    if yearNum then -- First, see if the year parameter is a number.
        self.year = yearNum
    else
        local yearBC = BCToNum( init.year )
        if yearBC then -- Second, see if the year parameter is a "yyyy BC" string.
            self.year = yearBC
        else
            local pageNum = isInteger( pagename )
            if pageNum then -- Third, see if the pagename is an integer.
                self.year = pageNum
            else
                local pageBC = BCToNum( pagename )
                if pageBC then -- Fourth, see if the pagename is a "yyyy BC" string.
                    self.year = pageBC
                else
                    self.year = currentYear -- If none of the above apply, use the current year.
                end
            end
        end
    end
 
    -- Set year text values.
    self.BCYearName = numToBC( self.year )
    if self.BCYearName then
        self.yearText = self.BCYearName
    else
        self.yearText = tostring( self.year )
    end
 
    -- Set other fields.
    self.caption = self.yearText
    self.footnotes = init.footnotes
    self.navbar = init.navbar
 
    return setmetatable( obj, {
        __index = self
    })
end
 
-- Sets the calendar box caption.
function calendarBox:setCaption( s )
    if type( s ) ~= 'string' or s == '' then return end
    self.caption = s
end
 
-- Adds a calendar or a calendar group.
function calendarBox:addCalendar( obj )
    if type( obj ) ~= 'table' and type( obj.new ) ~= 'function' then return end -- Exit if the object is invalid.
    self.calendars = self.calendars or {}
    table.insert( self.calendars, obj )
end
 
-- Add an alias for adding calendar groups. The function is the same, but it might be confusing for users
-- to have to use the name "addCalendar" for a calendar group.
calendarBox.addCalendarGroup = calendarBox.addCalendar
 
-- Outputs the calendar box wikitext.
function calendarBox:export()
    local root = htmlBuilder.create( 'table' )
    -- Export the calendar box headers.
    root
        .addClass( 'infobox' )
        .addClass( 'vevent' )
        .css( 'width', '22em' )
        .tag( 'caption' )
            .css( 'font-size', '125%' )
            .tag( 'span' )
                .addClass( 'summary' )
                .addClass( 'dtstart' )
                .wikitext( self.caption )
 
    -- Export the calendars and calendar groups. "calendar:export()" works for both kinds
    -- of objects. Some export functions can return nil, so we need to check for that.
    if type( self.calendars ) == 'table' then
        for i, calendar in ipairs( self.calendars ) do
            local calendarText = calendar:export()
            if type( calendarText ) == 'string' then
                root.wikitext( calendarText )
            end
        end
    end
 
    -- Add footnotes.
    if type( self.footnotes ) == 'string' and self.footnotes ~= '' then
        root
            .tag( 'tr' )
                .tag( 'td' )
                    .attr( 'colspan', '2' )
                    .wikitext( mw.ustring.format( '<small>%s</small>', self.footnotes ) )
    end
 
    -- Add navbar.
    if type( self.navbar ) == 'string' and self.navbar ~= '' then
        root
            .tag( 'tr' )
                .tag( 'td' )
                    .attr( 'colspan', '2' )
                    .css( 'text-align', 'center' )
                    .wikitext( makeNavbar{ self.navbar } )
    end
 
    return tostring( root )
end
 
--------------------------------------------------------------------
-- Calendar group class definition
--------------------------------------------------------------------
 
--  Calendar groups are used to group different calendars together. 
--  Previously, the template did this by including a table row with
--  no year value. By using objects we can do the same thing more
--  semantically.
 
local calendarGroup = {}
calendarGroup.__index = calendarGroup
 
function calendarGroup:new( init )
    init = type( init ) == 'table' and init or {}
    local obj = {}
 
    -- Get the heading and throw an error if it is invalid.
    obj.heading = init.heading
    if type( obj.heading ) ~= 'string' then
        error( 'calendarGroup: no heading detected' )
    end
 
    -- Set the metatable and return the object.
    self.__index = self
    return setmetatable( obj, {
        __index = self
    })
end
 
-- Adds a calendar object to the calendar group.
function calendarGroup:addCalendar( calendar )
    self.calendars = self.calendars or {}
    if type( calendar ) == 'table' and type( calendar.getLink ) == 'function' then
        table.insert( self.calendars, calendar )
    end
end
 
-- Exports the calendar group's wikitext.
function calendarGroup:export()
    -- Indent and italicise each calendar's link if it exists.
    for i, calendar in ipairs( self.calendars ) do
        local link = calendar:getLink()
        if type( link ) == 'string' then
            self.calendars[ i ]:setRawLink( mw.ustring.format( "&amp;nbsp;- ''%s''", link ) )
        end
    end
    -- Create the heading row html and export the calendar objects.
    local ret = htmlBuilder.create()
    ret
        .tag( 'tr' )
            .tag( 'td' )
                .wikitext( self.heading )
                .done()
            .tag( 'td' ) -- Use a blank tag to make the html look nice.
                .allDone()
    for i, calendar in ipairs( self.calendars ) do
        ret.wikitext( calendar:export() )
    end
    return tostring( ret )
end
 
--------------------------------------------------------------------
-- Calendar class definition
--------------------------------------------------------------------
 
local calendar = {}
calendar.__index = calendar
calendar.type = 'calendar'
 
function calendar:new()
    local obj = {}
    return setmetatable( obj, {
        __index = self
    })
end
 
-- Sets the calendar's wikilink, with optional display text and italics.
function calendar:setLink( link, display )
    if type( link ) ~= 'string' or link == '' then return end
    display = type( display ) == 'string' and display ~= '' and display
    if display then
        self.link = mw.ustring.format( '[[%s|%s]]', link, display )
    else
        self.link = mw.ustring.format( '[[%s]]', link )
    end
end
 
-- Sets the calendar's wikilink as raw wikitext.
function calendar:setRawLink( s )
    if type( s ) ~= 'string' or s == '' then return end
    self.link = s
end
 
-- Returns the calendar's link value.
function calendar:getLink()
    return self.link
end
 
-- Sets a single year. Can be passed either a string or a number.
function calendar:setYear( year )
    if type( year ) == 'number' then
        self.year = tostring( year )
    elseif type( year ) == 'string' then
        self.year = year
    end
end
 
-- Sets a year range. Must be passed two numbers.
function calendar:setYearRange( year1, year2 )
    if type( year1 ) == 'number' and type( year2 ) == 'number' then
        if year1 < 0 or year2 < 0 then -- Leave a gap for negative years to avoid having a minus sign and a dash right next to each other.
            self.year = mw.ustring.format( '%d – %d', year1, year2 )
        else
            self.year = mw.ustring.format( '%d–%d', year1, year2 )
        end
    end
end
 
-- Outputs the calendar wikitext.
function calendar:export()
    -- Exit if no link has been specified.
    local link = self.link
    if type( link ) ~= 'string' or link == '' then return end
 
    -- If no year has been specified, set the year value to N/A.
    local year = self.year
    if type( year ) ~= 'string' or year == '' then
        year = "''N/A''"
    end
 
    -- Build the table row.
    local ret = htmlBuilder.create()
    ret
        .tag( 'tr' )
            .tag( 'td' )
                .wikitext( link )
                .done()
            .tag( 'td' )
                .wikitext( year )
                .allDone()
    return tostring( ret )
end
 
--------------------------------------------------------------------
-- Build the box
--------------------------------------------------------------------
 
local function makeCalendarBox( args )
    -- Initiate the box and get the year values.
    local init = args
    init.navbar = 'Year in other calendars'
    local box = calendarBox:new( init )
    local year = box.year
    local yearText = box.yearText
 
    -- Set the caption.
    box:setCaption( box.caption .. ' in other calendars' )
 
    ----------------------------------------------------------------------
    -- Gregorian calendar
    ----------------------------------------------------------------------
 
    local gregorian = calendar:new()
    gregorian:setLink( 'Gregorian calendar' )
    -- Get the year link.
    local gregcal = args.gregcal
    if type( gregcal ) == 'string' and gregcal ~= '' then
        gregorian.yearLink = mw.ustring.format( '[[%s|%s]]', gregcal, yearText )
    else
        gregorian.yearLink = yearText
    end
    -- Set the year.
    gregorian.romanYear = numToRoman{ year }
    if gregorian.romanYear then
        gregorian:setYear( mw.ustring.format(
            [[%s<br /><span style="font-family: serif;">''%s''</span>]],
            gregorian.yearLink, gregorian.romanYear
        ) )
    else
        gregorian:setYear( gregorian.yearLink )
    end
    box:addCalendar( gregorian ) 
 
    ----------------------------------------------------------------------
    -- Ab urbe condita
    ----------------------------------------------------------------------
 
    local abUrbe = calendar:new()
    abUrbe:setLink( 'Ab urbe condita' )
    abUrbe:setYear( year + 753 )
    box:addCalendar( abUrbe )
 
    ----------------------------------------------------------------------
    -- Armenian calendar
    ----------------------------------------------------------------------
 
    local armenian = calendar:new()
    armenian:setLink( 'Armenian calendar' )
    if year > 551 then
        local armenianYear = year - 551
        armenian:setYear( mw.ustring.format( '%s<br />ԹՎ %s', armenianYear, numToArmenian( armenianYear ) ) )
    end
    box:addCalendar( armenian )
 
    ----------------------------------------------------------------------
    -- Assyrian calendar
    ----------------------------------------------------------------------
 
    local assyrian = calendar:new()
    assyrian:setLink( 'Assyrian calendar' )
    assyrian:setYear( year + 4750 )
    box:addCalendar( assyrian )
 
    ----------------------------------------------------------------------
    -- Bahá'í calendar
    ----------------------------------------------------------------------
 
    local bahai = calendar:new()
    bahai:setLink( "Bahá'í calendar" )
    bahai:setYearRange( year - 1844, year - 1843 )
    box:addCalendar( bahai )
 
    ----------------------------------------------------------------------
    -- Bengali calendar
    ----------------------------------------------------------------------
 
    local bengali = calendar:new()
    bengali:setLink( 'Bengali calendar' )
    bengali:setYear( year - 593 )
    box:addCalendar( bengali )
 
    ----------------------------------------------------------------------
    -- Berber calendar
    ----------------------------------------------------------------------
 
    local berber = calendar:new()
    berber:setLink( 'Berber calendar' )
    berber:setYear( year + 950 )
    box:addCalendar( berber )
 
    ----------------------------------------------------------------------
    -- Regnal year
    ----------------------------------------------------------------------
 
    local regnal = calendar:new()
    local regnalName
    if year > 1706 then
        regnalName = 'British'
    else
        regnalName = 'English'
    end
    regnal:setLink( 'Regnal years of English monarchs', regnalName .. ' Regnal year' )
    regnal:setYear( getRegnal( year ) )
    box:addCalendar( regnal )
 
    ----------------------------------------------------------------------
    -- Buddhist calendar
    ----------------------------------------------------------------------
 
    local buddhist = calendar:new()
    buddhist:setLink( 'Buddhist calendar' )
    buddhist:setYear( year + 544 )
    box:addCalendar( buddhist )
 
    ----------------------------------------------------------------------
    -- Burmese calendar
    ----------------------------------------------------------------------
 
    local burmese = calendar:new()
    burmese:setLink( 'Traditional Burmese calendar', 'Burmese calendar' )
    burmese:setYear( year - 638 )
    box:addCalendar( burmese )
 
    ----------------------------------------------------------------------
    -- Byzantine calendar
    ----------------------------------------------------------------------
 
    local byzantine = calendar:new()
    byzantine:setLink( 'Byzantine calendar' )
    byzantine:setYearRange( year + 5508, year + 5509 )
    box:addCalendar( byzantine )
 
    ----------------------------------------------------------------------
    -- Chinese calendar
    ----------------------------------------------------------------------
 
    local chinese = calendar:new()
    chinese:setLink( 'Chinese calendar' )
 
    -- Define the information for the "heavenly stems" and "earthly branches" year cycles.
    -- See [[Chinese calendar#Cycle of years]] for information.
 
    local heavenlyStems = {
        { '甲', 'Wood' },   -- 1
        { '乙', 'Wood' },   -- 2
        { '丙', 'Fire' },   -- 3
        { '丁', 'Fire' },   -- 4
        { '戊', 'Earth' },  -- 5
        { '己', 'Earth' },  -- 6
        { '庚', 'Metal' },  -- 7
        { '辛', 'Metal' },  -- 8
        { '壬', 'Water' },  -- 9
        { '癸', 'Water' }   -- 10
    }
 
    local earthlyBranches = {
        { '子', '[[Rat (zodiac)|Rat]]' },           -- 1
        { '丑', '[[Ox (zodiac)|Ox]]' },             -- 2
        { '寅', '[[Tiger (zodiac)|Tiger]]' },       -- 3
        { '卯', '[[Rabbit (zodiac)|Rabbit]]' },     -- 4
        { '辰', '[[Dragon (zodiac)|Dragon]]' },     -- 5
        { '巳', '[[Snake (zodiac)|Snake]]' },       -- 6
        { '午', '[[Horse (zodiac)|Horse]]' },       -- 7
        { '未', '[[Goat (zodiac)|Goat]]' },         -- 8
        { '申', '[[Monkey (zodiac)|Monkey]]' },     -- 9
        { '酉', '[[Rooster (zodiac)|Rooster]]' },   -- 10
        { '戌', '[[Dog (zodiac)|Dog]]' },           -- 11
        { '亥', '[[Pig (zodiac)|Pig]]' }            -- 12
    }
 
    -- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the ''previous'' year's entry
    -- in [[Chinese calendar correspondence table]], as the Chinese New Year doesn't happen until Jan/Feb in
    -- Gregorian years.
    local sexagenaryYear1 = ( year - 4 ) % 60
    local sexagenaryYear2 = ( year - 3 ) % 60
    local heavenlyNum1 = sexagenaryYear1 % 10
    local heavenlyNum2 = sexagenaryYear2 % 10
    local earthlyNum1 = sexagenaryYear1 % 12
    local earthlyNum2 = sexagenaryYear2 % 12
 
    -- If the value is 0 increase it by one cycle so that we can use it with Lua arrays.
    if heavenlyNum1 == 0 then
        heavenlyNum1 = 10
    end
    if heavenlyNum2 == 0 then
        heavenlyNum2 = 10
    end
    if earthlyNum1 == 0 then
        earthlyNum1 = 12
    end
    if earthlyNum2 == 0 then
        earthlyNum2 = 12
    end
 
    -- Get the data tables for each permutation.
    local heavenlyTable1 = heavenlyStems[ heavenlyNum1 ]
    local heavenlyTable2 = heavenlyStems[ heavenlyNum2 ]
    local earthlyTable1 = earthlyBranches[ earthlyNum1 ]
    local earthlyTable2 = earthlyBranches[ earthlyNum2 ]
 
    -- Work out the continously-numbered year. (See [[Chinese calendar#Continuously numbered years]].)
    local year1 = year + 2696
    local year2 = year + 2697
    local year1Alt = year1 - 60
    local year2Alt = year2 - 60
 
    -- Return all of that data in a (hopefully) reader-friendly format.
    chinese:setYear( mw.ustring.format(
        [=[[[Sexagenary cycle|%s%s]]年 <small>(%s&amp;nbsp;%s)</small><br />%d or %d<br />&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;''—&amp;nbsp;to&amp;nbsp;—''<br />%s%s年 <small>(%s&amp;nbsp;%s)</small><br />%d or %d]=],
        heavenlyTable1[ 1 ],
        earthlyTable1[ 1 ],
        heavenlyTable1[ 2 ],
        earthlyTable1[ 2 ],
        year1,
        year1Alt,
        heavenlyTable2[ 1 ],
        earthlyTable2[ 1 ],
        heavenlyTable2[ 2 ],
        earthlyTable2[ 2 ],
        year2,
        year2Alt
    ) )
 
    box:addCalendar( chinese )
 
    ----------------------------------------------------------------------
    -- Coptic calendar
    ----------------------------------------------------------------------
 
    local coptic = calendar:new()
    coptic:setLink( 'Coptic calendar' )
    coptic:setYearRange( year - 284, year - 283 )
    box:addCalendar( coptic )
 
    ----------------------------------------------------------------------
    -- Ethiopian calendar
    ----------------------------------------------------------------------
 
    local ethiopian = calendar:new()
    ethiopian:setLink( 'Ethiopian calendar' )
    ethiopian:setYearRange( year - 8, year - 7 )
    box:addCalendar( ethiopian )
 
    ----------------------------------------------------------------------
    -- Hebrew calendar
    ----------------------------------------------------------------------
 
    local hebrew = calendar:new()
    hebrew:setLink( 'Hebrew calendar' )
    hebrew:setYearRange( year + 3760, year + 3761 )
    box:addCalendar( hebrew )
 
    ----------------------------------------------------------------------
    -- Hindu calendars
    ----------------------------------------------------------------------
 
    local hindu = calendarGroup:new{ heading = '[[Hindu calendar]]s' }
 
    -- Vikram Samvat
 
    local vikramSamvat = calendar:new()
    vikramSamvat:setLink( 'Vikram Samvat' )
    vikramSamvat:setYearRange( year + 56, year + 57 )
    hindu:addCalendar( vikramSamvat )
 
    -- Shaka Samvat
 
    local shakaSamvat = calendar:new()
    shakaSamvat:setLink( 'Indian national calendar', 'Shaka Samvat' )
    if year - 76 > 0 then
        shakaSamvat:setYearRange( year - 78, year - 77 )
    end
    hindu:addCalendar( shakaSamvat )
 
    -- Kali Yuga
 
    local kaliYuga = calendar:new()
    kaliYuga:setLink( 'Kali Yuga' ) -- use italics
    kaliYuga:setYearRange( year + 3101, year + 3102 )
    hindu:addCalendar( kaliYuga )
 
    box:addCalendarGroup( hindu )
 
    ----------------------------------------------------------------------
    -- Holocene calendar
    ----------------------------------------------------------------------
 
    local holocene = calendar:new()
    holocene:setLink( 'Human Era', 'Holocene calendar' )
    holocene:setYear( year + 10000 )
    box:addCalendar( holocene )
 
    ----------------------------------------------------------------------
    -- Igbo calendar
    ----------------------------------------------------------------------
 
    -- In the old template this was a calendar group with just one calendar; intentionally adding this as a single
    -- calendar here, as the previous behaviour looked like a mistake.
    local igbo = calendar:new()
    igbo:setLink( 'Igbo calendar' )
    igbo:setYearRange( year - 1000, year - 999 )
    box:addCalendar( igbo )
 
    ----------------------------------------------------------------------
    -- Iranian calendar
    ----------------------------------------------------------------------
 
    local iranian = calendar:new()
    iranian:setLink( 'Iranian calendars', 'Iranian calendar' )
    if year - 621 > 0 then
        iranian:setYearRange( year - 622, year - 621 )
    else
        iranian:setYear( mw.ustring.format( '%d BP&amp;nbsp;– %d BP', 622 - year, 621 - year ) )
    end
    box:addCalendar( iranian )
 
    ----------------------------------------------------------------------
    -- Islamic calendar
    ----------------------------------------------------------------------
 
    local islamic = calendar:new()
    islamic:setLink( 'Islamic calendar' )
    local islamicMult = 1.030684 -- the factor to multiply by
    local islamicSub = 621.5643 -- the factor to subtract by
    if year - 621 > 0 then
        local year1 = math.floor( islamicMult * ( year - islamicSub ) )
        local year2 = math.floor( islamicMult * ( year - islamicSub + 1 ) )
        islamic:setYearRange( year1, year2 )
    else
        local year1 = math.ceil( -islamicMult * ( year - islamicSub ) )
        local year2 = math.ceil( -islamicMult * ( year - islamicSub + 1 ) )
        islamic:setYear( mw.ustring.format( '%d BH&amp;nbsp;– %d BH', year1, year2 ) )
    end
    box:addCalendar( islamic )
 
    ----------------------------------------------------------------------
    -- Japanese calendar
    ----------------------------------------------------------------------
 
    local japanese = calendar:new()
    japanese:setLink( 'Japanese calendar' )
 
    japanese.thisEra = japaneseEra:new{ year = year }
    if japanese.thisEra then
        local japaneseYearText = {}
        japanese.oldEra = japanese.thisEra:getOldEra()
        if japanese.oldEra and japanese.oldEra.eraYear and japanese.thisEra.article ~= japanese.oldEra.article then
            japanese.oldText = mw.ustring.format( '%s %d', japanese.oldEra.link, japanese.oldEra.eraYear )
            table.insert( japaneseYearText, japanese.oldText )
            table.insert( japaneseYearText, ' / ' )
        end
        if japanese.thisEra.eraYear then
            table.insert( japaneseYearText, mw.ustring.format( '%s %d', japanese.thisEra.link, japanese.thisEra.eraYear ) )
        end
        table.insert( japaneseYearText, mw.ustring.format( '<br /><small>(%s%s年)</small>', japanese.thisEra.kanji, japanese.thisEra.eraYearKanji ) )
        japanese:setYear( table.concat( japaneseYearText ) )
    end
 
    box:addCalendar( japanese )
 
    ----------------------------------------------------------------------
    -- Juche calendar
    ----------------------------------------------------------------------
 
    local juche = calendar:new()
    juche:setLink( 'North Korean calendar', 'Juche calendar' )
    if year > 1911 then
        juche:setYear( year - 1911 )
    end
    box:addCalendar( juche )
 
    ----------------------------------------------------------------------
    -- Julian calendar
    ----------------------------------------------------------------------
 
    local julian = calendar:new()
    julian:setLink( 'Julian calendar' )
 
    julian.yearVals = {
        { 1901, 'Gregorian minus 13 days' },
        { 1900, 'Gregorian minus 12 or 13 days'},
        { 1801, 'Gregorian minus 12 days' },
        { 1800, 'Gregorian minus 11 or 12 days' },
        { 1701, 'Gregorian minus 11 days' },
        { 1700, 'Gregorian minus 10 or 11 days' },
        { 1582, 'Gregorian minus 10 days' },
        { -45, gregorian.year }
    }
 
    for i, t in ipairs( julian.yearVals ) do
        if year >= t[ 1 ] then
            julian:setYear( t[ 2 ] )
            break
        end
    end
 
    box:addCalendar( julian )
 
    ----------------------------------------------------------------------
    -- Korean calendar
    ----------------------------------------------------------------------
 
    local korean = calendar:new()
    korean:setLink( 'Korean calendar' )
    korean:setYear( year + 2333 )
    box:addCalendar( korean )
 
    ----------------------------------------------------------------------
    -- Minguo calendar
    ----------------------------------------------------------------------
 
    local minguo = calendar:new()
    minguo:setLink( 'Minguo calendar' )
    if year > 1911 then
        local minguoYear = year - 1911
        minguo:setYear( mw.ustring.format( '[[Taiwan|ROC]] %d<br /><small>民國%d年</small>', minguoYear, minguoYear ) )
    else
        local minguoYear = 1911 - year + 1
        minguo:setYear( mw.ustring.format( '%d before [[Republic of China|ROC]]<br /><small>民前%d年</small>', minguoYear, minguoYear ) )
    end
    box:addCalendar( minguo )
 
    ----------------------------------------------------------------------
    -- Thai solar calendar
    ----------------------------------------------------------------------
 
    local thai = calendar:new()
    thai:setLink( 'Thai solar calendar' )
    thai:setYear( year + 543 )
    box:addCalendar( thai )
 
    ----------------------------------------------------------------------
    -- Unix time
    ----------------------------------------------------------------------
 
    local unix = calendar:new()
 
    local function getUnixTime( year )
        if year < 1970 then return end
        local noError, unixTime = pcall( lang.formatDate, lang, 'U', '1 Jan ' .. tostring( year ) )
        if not noError or noError and not unixTime then return end
        unixTime = tonumber( unixTime )
        if unixTime and unixTime >= 0 then
            return unixTime
        end
    end
 
    unix.thisYear = getUnixTime( year )
    unix.nextYear = getUnixTime( year + 1 )
    if unix.thisYear and unix.nextYear then
        unix:setLink( 'Unix time' )
        unix:setYearRange( unix.thisYear, unix.nextYear - 1 )
    end
 
    box:addCalendar( unix )
 
    return box:export()
end
 
--------------------------------------------------------------------
-- Define functions and objects to make available externally
--------------------------------------------------------------------
 
local p = {}
 
-- Process the arguments and pass them to the box-building function.
function p.main( frame )
    -- If called via #invoke, use the args passed into the invoking
    -- template, or the args passed to #invoke if any exist. Otherwise
    -- assume args are being passed directly in from the debug console
    -- or from another Lua module.
    local origArgs
    if frame == mw.getCurrentFrame() then
        origArgs = frame:getParent().args
        for k, v in pairs( frame.args ) do
            origArgs = frame.args
            break
        end
    else
        origArgs = frame
    end
 
    -- Trim whitespace and remove blank arguments.
    local args = {}
    for k, v in pairs( origArgs ) do
        if type( v ) == 'string' then
            v = mw.text.trim( v )
        end
        if v ~= '' then
            args[k] = v
        end
    end
    return makeCalendarBox( args )
end
 
p.calendarBox = calendarBox
p.calendarGroup = calendarGroup
p.calendar = calendar
 
return p