Redigerer
Modul:DateI18n
Hopp til navigering
Hopp til søk
Advarsel:
Du er ikke innlogget. IP-adressen din vil bli vist offentlig om du redigerer. Hvis du
logger inn
eller
oppretter en konto
vil redigeringene dine tilskrives brukernavnet ditt, og du vil få flere andre fordeler.
Antispamsjekk.
Ikke
fyll inn dette feltet!
--[[ __ __ _ _ ____ _ ___ _ ___ | \/ | ___ __| |_ _| | ___ _| _ \ __ _| |_ ___|_ _/ |( _ ) _ __ | |\/| |/ _ \ / _` | | | | |/ _ (_) | | |/ _` | __/ _ \| || |/ _ \| '_ \ | | | | (_) | (_| | |_| | | __/_| |_| | (_| | || __/| || | (_) | | | | |_| |_|\___/ \__,_|\__,_|_|\___(_)____/ \__,_|\__\___|___|_|\___/|_| |_| This module is intended for processing of date strings. Please do not modify this code without applying the changes first at Module:DateI18n/sandbox and testing at Module:DateI18n/sandbox/testcases and Module talk:DateI18n/sandbox/testcases. Authors and maintainers: * User:Parent5446 - original version of the function mimicking Template:ISOdate * User:Jarekt - original version of the functions mimicking Template:Date ]] -- ======================================= -- === Dependencies ====================== -- ======================================= require('strict') -- ======================================= -- === Local Functions =================== -- ======================================= ------------------------------------------------------------------------------ --[[ (copied from Module:Core) Function allowing for consistent treatment of boolean-like wikitext input. Inputs: 1) val - value to be evaluated, outputs as a function of values: true : true (boolean), 1 (number), or strings: "yes", "y", "true", "1" false : false (boolean), 0 (number), or strings: "no", "n", "false", "0" 2) default - value to return otherwise See Also: It works similarly to Module:Yesno ]] local function yesno(val, default) if type(val) == 'boolean' then return val elseif type(val) == 'number' then val = tostring(val) end if type(val) == 'string' then local LUT = { yes=true , y=true , ['true'] =true , t=true , ['1']=true , on =true, no =false, n=false, ['false']=false, f=false, ['0']=false, off=false } val = LUT[mw.ustring.lower(val)] -- put in lower case if (val~=nil) then return val end end return default end --------------------------------------------------------------------------------------- -- trim leading zeros in years prior to year 1000 -- INPUT: -- * datestr - translated date string -- * lang - language of translation -- OUTPUT: -- * datestr - updated date string local function trimYear(datestr, year, lang) local yearStr0, yearStr1, yearStr2, zeroStr yearStr0 = string.format('%04i', year ) -- 4 digit year in standard form "0123" yearStr1 = mw.language.new(lang):formatDate( 'Y', yearStr0) -- same as calling {{#time}} parser function --yearStr1 = mw.getCurrentFrame():callParserFunction( "#time", { 'Y', yearStr0, lang } ) -- translate to a language if yearStr0==yearStr1 then -- most of languages use standard form of year yearStr2 = tostring(year) else -- some languages use different characters for numbers yearStr2 = yearStr1 zeroStr = mw.ustring.sub(yearStr1,1,1) -- get "0" in whatever language for i=1,3 do -- trim leading zeros if mw.ustring.sub(yearStr2,1,1)==zeroStr then yearStr2 = mw.ustring.sub(yearStr2, 2, 5-i) else break end end end return string.gsub(datestr, yearStr1, yearStr2 ) -- in datestr replace long year with trimmed one end --------------------------------------------------------------------------------------- -- Look up proper format string to be passed to {{#time}} parser function -- INPUTS: -- * datecode: YMDhms, YMDhm, YMD, YM, Y, MDhms, MDhm, MD, or M -- * day : Number between 1 and 31 (not needed for most languages) -- * lang : language -- OUTPUT: -- * dFormat : input to {{#time}} function local function getDateFormat(datecode, day, lang) local function parseFormat(dFormat, day) if dFormat:find('default') and #dFormat>10 then -- Special (and messy) case of dFormat code depending on a day number, where data is a -- JSON-encoded table {”default”:”*”,”dDD”:”*”} including fields for specific 2-digit days. -- Change curly double quotes (possibly used for easier editing in tabular data) in dFormat -- to straight ASCII double quotes (required for parsing of this JSON-encoded table). local D = mw.text.jsonDecode(mw.ustring.gsub(dFormat, '[„“‟”]', '"')) --com = mw.dumpObject(D) -- If the desired day is not in that JSON table, then use its "default" case. dFormat = D[string.format('d%02i', day)] or D.default -- Change ASCII single quotes to ASCII double quotes used for {{#time}} marking. -- Apostrophes needed in plain-text must not use ASCII single quotes but curly apostrophe -- e.g. { ‟default”: ‟j”, ‟d01”: ‟j’'o'” }, not { ‟default”: ‟j”, ‟d01”: ‟j''o'” }. end dFormat = dFormat:gsub("'", '"') return dFormat end local T = {} local tab = mw.ext.data.get('DateI18n.tab', lang) for _, row in pairs(tab.data) do -- convert the output into a dictionary table local id, _, msg = unpack(row) T[id] = msg end -- Compatibility of legacy data using 'HMS' or 'HM', where 'M' is ambiguous T.YMDhms = T.YMDhms or T.YMDHMS T.YMDhm = T.YMDhm or T.YMDHM datecode = datecode == 'YMDHMS' and 'YMDhms' or datecode == 'YMDHM' and 'YMDhm' or datecode local dFormat = T[datecode] if dFormat == 'default' and (datecode == 'YMDhms' or datecode == 'YMDhm') then -- For most languages adding hour:minute:second is done by adding ", HH:ii:ss to the -- day precission date, those languages are skipped in DateI18n.tab and default to -- English which stores word "default" dFormat = parseFormat(T['YMD'], day).. ', H:i' if datecode == 'YMDhms' then dFormat = dFormat .. ':s' end else dFormat = parseFormat(dFormat, day) end return dFormat end --------------------------------------------------------------------------------------- -- Look up proper format string to be passed to {{#time}} parser function -- INPUTS: -- * month : month number -- * case : gramatic case abbriviation, like "ins", "loc" -- * lang : language -- OUTPUT: -- * dFormat : input to {{#time}} function local function MonthCase(month, case, lang) if month == nil or case == nil then return nil end local T = {{},{},{},{},{},{},{},{},{},{},{},{}} local tab = mw.ext.data.get('I18n/MonthCases.tab', lang) for _, row in pairs(tab.data) do local mth, cs, msg = unpack(row) T[mth][cs] = msg end return T[month][case] end -- ================================================== -- === External functions =========================== -- ================================================== local p = {} -- =========================================================================== -- === Functions accesible from the outside to allow unit-testing -- === Please do not use directly as they could change in the future -- =========================================================================== --------------------------------------------------------------------------------------- -- Single string replacement that ignores part of the string in "..." function p.strReplace(String, old, new) if String:find('"') then local T={} for i, str in ipairs(mw.text.split( String, '"', true )) do if i%2==1 then str = str:gsub(old, new, 1) end table.insert(T, str) end return table.concat(T,'"') else return String:gsub(old, new, 1) end end --------------------------------------------------------------------------------------- -- process datevec -- INPUT: -- * datevec - Array of {year,month,day,hour,minute,second, tzhour, tzmin} containing broken -- down date-time component strings or numbers -- OUTPUT: -- * datenum - same array but holding only numbers or nuls function p.clean_datevec(datevec) -- create datecode based on which variables are provided and check for out-of-bound values -- check special case of month provided as a name local month = datevec[2] if type(month) == 'string' and month ~= '' and not tonumber(month) then -- When the month is not a number, check if it's a month name in the project's language. datevec[2] = mw.getContentLanguage():formatDate('n', month) end -- check bounds local maxval = { 1/0, 12, 31, 23, 59, 59, 23, 59 } -- max values (or 1/0=+inf) for year, month, day, hour, minute, second, tzhour, tzmin local minval = { -1/0, 01, 01, 00, 00, 00, -23, 00 } -- min values (or -1/0=-inf) for year, month, ... local datenum = {} -- date-time encoded as a vector = [year, month, ... , second, tzhour, tzmin] for i = 1, 8 do local val = tonumber(datevec[i]) if val and val >= minval[i] and val <= maxval[i] then -- These tests work with infinite min/max values. datenum[i] = val end end -- leap second if tonumber(datevec[6]) == 60 then -- leap second '60' is valid only at end of 23:59 UTC, on 30 June or 31 December of specific years -- datenum[6] = 60 local MDhm = table.concat({unpack(datenum,2,5)}, ',') if (MDhm == table.concat({6, 30, 23, 59}, ',')) or (MDhm == table.concat({12, 31, 23, 59}, ',')) then datenum[6] = 60 end end return datenum end --------------------------------------------------------------------------------------- -- process datevec -- INPUT: -- * datenum - Array of {year,month,day,hour,minute,second, tzhour, tzmin} as numbers or nuls -- OUTPUT: -- * timeStamp - date string in the format taken by mw.language:formatDate lua function and {{#time}} parser function -- https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.language:formatDate -- https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time -- * datecode - a code specifying content of the array where Y' is year, 'M' is month, -- 'D' is day, 'h' is hour, 'm' minute, 's' is second. -- Output has to be one of YMDhms, YMDhm, YMD, YM, Y, MDhms, MDhm, MD, M. function p.getTimestamp(datenum) -- create datecode based on datenum local codes = { 'Y', 'M', 'D', 'h', 'm', 's'} local datecode = '' -- a string signifying which combination of variables was provided for i, c in ipairs(codes) do datecode = datecode .. (datenum[i] and c or '') -- if datenum[i] than append codes[i] to datecode end -- create timestamp string (for example 2000-02-20 02:20:20) based on which variables were provided local timeStamp -- date starting by a year if datecode == 'YMDhms' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5], datenum[6] ) elseif datecode == 'YMDhm' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5] ) elseif datecode:sub(1,3)=='YMD' then timeStamp = string.format('%04i-%02i-%02i', datenum[1], datenum[2], datenum[3] ) datecode = 'YMD' -- 'YMDhms', 'YMDhm' and 'YMD' are the only supported format starting with 'YMD'; all others will be converted to 'YMD'. elseif datecode:sub(1,2) == 'YM' then timeStamp = string.format('%04i-%02i', datenum[1], datenum[2] ) datecode = 'YM' elseif datecode:sub(1,1)=='Y' then timeStamp = string.format('%04i', datenum[1] ) datecode = 'Y' -- date starting by a month (the implied year is 2000) elseif datecode== 'MDhms' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i:%02i', 2000, datenum[2], datenum[3], datenum[4], datenum[5], datenum[6] ) elseif datecode == 'MDhm' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i', 2000, datenum[2], datenum[3], datenum[4], datenum[5] ) elseif datecode:sub(1,2) == 'MD' then timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], datenum[3] ) datecode = 'MD' -- 'MDhms', 'MDhm' and 'MD' are the only supported format starting with 'MD'; all others will be converted to 'MD' elseif datecode:sub(1,1) == 'M' then -- Ambiguous: could mean minutes, but here means month (when parsed as a name/abbrev, not as a number). timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], 1 ) datecode = 'M' -- other possible but unrecognized formats (e.g. 'DHis', 'DHi', 'D', 'His', 'Hi'); -- note that 'Dh', 'D', 'h', 's' may eventually work, but not 'm' for minute only, which is ambiguous with 'M' for month only. else timeStamp = nil -- format not supported end return timeStamp, datecode end local function isValidLangCode(lang) if not lang then return false end lang = mw.text.trim(lang) return lang ~= '' and lang ~= '⧼Lang⧽' and mw.language.isValidCode(lang) end -- =========================================================================== -- === Version of the function to be called from other LUA codes -- =========================================================================== --[[ ======================================================================================== Date This function is the core part of the ISOdate template. Usage: local Date = require('Module:DateI18n')._Date local dateStr = Date({2020, 12, 30, 12, 20, 11}, lang) Parameters: * {year,month,day,hour,minute,second, tzhour, tzmin}: broken down date-time component strings or numbers tzhour, tzmin are timezone offsets from UTC, hours and minutes * lang: The language to display it in * case: Language format (genitive, etc.) for some languages * class: CSS class for the <time> node, use "" for no metadata at all ]] function p._Date(datevec, lang, case, class, trim_year) -- make sure inputs are in the right format -- set language if not isValidLangCode(lang) then -- get user's chosen language -- equivalent to {{int:lang}} lang = mw.getCurrentFrame():callParserFunction("int", "lang") if not isValidLangCode(lang) then -- if that doesn't work, use the project language -- this is useful on projects which import this module from Commons lang = mw.language.getContentLanguage().code if not isValidLangCode(lang) then -- if that doesn't work, use English lang = "en" end end end if lang == 'be-tarask' then lang = 'be-x-old' end -- process datevec and extract timeStamp and datecode strings as well as numeric datenum array local datenum = p.clean_datevec(datevec) local year, month, day = datenum[1], datenum[2], datenum[3] local timeStamp, datecode = p.getTimestamp(datenum) if not timeStamp then -- something went wrong in parserDatevec return '' end -- Commons [[Data:DateI18n.tab]] page stores prefered formats for diferent -- languages and datecodes (specifying year-month-day or just year of month-day, etc) -- Look up country specific format input to {{#time}} function local dFormat = getDateFormat(datecode, day, lang) -- By default the gramatical case is not specified (case=='') allowing the format to be specified -- in [[Data:DateI18n.tab]]. You can overwrite the default grammatical case of the month by -- specifying "case" variable. This is needed mostly by Slavic languages to create more complex -- phrases as it is done in [[c:Module:Complex date]] case = case or '' if (lang=='qu' or lang=='qug') and case=='nom' then -- Special case related to Quechua and Kichwa languages. The form in the I18n is -- Genitive case with suffix "pi" added to month names provided by {#time}} -- in Nominative case that "pi" should be removed -- see https://commons.wikimedia.org/wiki/Template_talk:Date#Quechua from 2014 dFormat = dFormat:gsub('F"pi"', 'F') elseif case == 'gen' then dFormat = p.strReplace(dFormat, "F", "xg") elseif case == 'nom' then dFormat = p.strReplace(dFormat, "xg", "F") elseif case ~= '' and month ~= nil then -- see is page [[Data:I18n/MonthCases.tab]] on Commons have name of the month -- in specific gramatic case in desired language. If we have it than replace -- "F" and xg" in dFormat local monthMsg = MonthCase(month, case, lang) if monthMsg and monthMsg ~= '' then -- make sure it exists dFormat = p.strReplace(dFormat, 'F', '"'..monthMsg..'"') -- replace default month with month name we already looked up dFormat = p.strReplace(dFormat, 'xg', '"'..monthMsg..'"') end end -- Translate the date using specified format. -- See https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.language:formatDate and -- https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions##time for explanation of the format local langObj = mw.language.new(lang) local datestr = langObj:formatDate(dFormat, timeStamp) -- same as using {{#time}} parser function -- Special case related to Thai solar calendar: prior to 1940 new-year was at different time of year, -- so just year (datecode == 'Y') is ambiguous and is replaced by "YYYY or YYYY" phrase if lang=='th' and datecode=='Y' and year<=1940 then datestr = string.format('%04i หรือ %04i', year+542, year+543 ) end -- If year < 1000 than either keep the date padded to the length of 4 digits or trim it. -- Decide if the year will stay padded with zeros (for years in 0-999 range). if year and year < 1000 then trim_year = yesno(trim_year, trim_year or '100-999') if type(trim_year) == 'string' then -- If `trim_year` not a simple boolean, then it's a range of dates. -- For example '100-999' means to pad 1-or-2-digit years to be 4-digit long, while keeping 3-digit years as is. local YMin, YMax = trim_year:match( '(%d+)-(%d+)' ) trim_year = YMin and year >= tonumber(YMin) and year <= tonumber(YMax) end if trim_year then datestr = trimYear(datestr, year, lang) -- in datestr replace long year with trimmed one end end -- Append a timezone if present (after the hour and minute of the day). if datenum[7] and (datecode:sub(1, 5) == 'YMDhm' or datecode:sub(1, 4) == 'MDhm') then -- Use {{#time}} parser function to create timezone string, so that we use the correct character set. local sign = (datenum[7]<0) and '−' or '+' timeStamp = string.format("2000-01-01 %02i:%02i:00", math.abs(datenum[7]), datenum[8] or 0) local timezone = langObj:formatDate('H:i', timeStamp) -- same as using {{#time}} parser function datestr = string.format("%s %s%s", datestr, sign, timezone ) end -- HTML formating of date string and tagging for microformats (only for absolute dates with a year). if class and class ~= '' and class ~= '-' and datecode:sub(1,1) == 'Y' then local pat = '<time class="%s" datetime="%s" lang="%s" dir="%s" style="white-space:nowrap">%s</time>' datestr = pat:format(class, timeStamp, lang, langObj:getDir(), datestr) end return datestr end -- =========================================================================== -- === Version of the function to be called from template namespace -- =========================================================================== --[[ ======================================================================================== Date This function is the core part of the ISOdate template. Usage: {{#invoke:DateI18n|Date|year=|month=|day=|hour=|minute=|second=|tzhour=|tzmin=|lang=en}} Parameters: * year, month, day, hour, minute, second: broken down date-time component strings * tzhour, tzmin: timezone offset from UTC, hours and minutes * lang: The language to display it in * case: Language format (genitive, etc.) for some languages * class: CSS class for the <time> node, use "" for no metadata at all ]] function p.Date(frame) -- get args local args = {} for key, value in pairs(frame.args) do local trimmed_key = string.gsub(string.lower(mw.text.trim(key)), ' ', '_') local trimmed_value = mw.text.trim(value) if trimmed_key ~= 'class' and trimmed_value == '' then trimmed_value = nil end args[trimmed_key] = trimmed_value end -- default values -- Allows to set the html class of the time node where the date is included. This is useful for microformats. args.class = args.class or '-' if args.class == '' then args.class = 'dtstart' end -- By default, pad one- and two-digit years to be 4 digits long, while keeping three-digit years as-is. args.trim_year = args.trim_year or '100-999' return p._Date( {args.year, args.month, args.day, args.hour, args.minute, args.second, args.tzhour, args.tzmin}, args.lang, args.case, args.class, args.trim_year ) end return p
Redigeringsforklaring:
Merk at alle bidrag til Wikisida.no anses som frigitt under Creative Commons Navngivelse-DelPåSammeVilkår (se
Wikisida.no:Opphavsrett
for detaljer). Om du ikke vil at ditt materiale skal kunne redigeres og distribueres fritt må du ikke lagre det her.
Du lover oss også at du har skrevet teksten selv, eller kopiert den fra en kilde i offentlig eie eller en annen fri ressurs.
Ikke lagre opphavsrettsbeskyttet materiale uten tillatelse!
Avbryt
Redigeringshjelp
(åpnes i et nytt vindu)
Forhåndsvis en side som bruker denne malen
Mal som brukes på denne siden:
Modul:DateI18n/dok
(
rediger
)
Navigasjonsmeny
Personlige verktøy
Ikke logget inn
Brukerdiskusjon
Bidrag
Opprett konto
Logg inn
Navnerom
Modul
Diskusjon
English
Visninger
Les
Rediger kilde
Vis historikk
Mer
Navigasjon
Forside
Siste endringer
Tilfeldig side
Hjelp til MediaWiki
Verktøy
Lenker hit
Relaterte endringer
Spesialsider
Sideinformasjon