「モジュール:DateI18n」の版間の差分
ナビゲーションに移動
検索に移動
細
incorrect language code
細 (1版 をインポートしました) |
bsd>Verdy p 細 (incorrect language code) |
||
27行目: | 27行目: | ||
return val | return val | ||
elseif type(val) == 'number' then | elseif type(val) == 'number' then | ||
if val==1 then | if val == 1 then | ||
return true | return true | ||
elseif val==0 then | elseif val == 0 then | ||
return false | return false | ||
end | end | ||
elseif type(val) == 'string' then | elseif type(val) == 'string' then | ||
val = | val = string.lower(val) -- put in lower case | ||
if val == 'no' or val == 'n' or val == 'false' or tonumber(val) == 0 then | if val == 'no' or val == 'n' or val == 'false' or tonumber(val) == 0 then | ||
return false | return false | ||
66行目: | 66行目: | ||
-- down date-time component strings or numbers | -- down date-time component strings or numbers | ||
-- OUTPUT: | -- OUTPUT: | ||
-- * datecode - a code specifying content of the array where Y' is year, 'M' is month, | -- * 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 | |||
-- * datenum - same array but holding only numbers or nuls | -- * datenum - same array but holding only numbers or nuls | ||
local function parserDatevec(datevec) | local function parserDatevec(datevec) | ||
-- create datecode based on which variables are provided and check for out-of-bound values | -- create datecode based on which variables are provided and check for out-of-bound values | ||
local maxval = { | local maxval = { 1/0, 12, 31, 23, 59, 60, 23, 59 } -- max values (or 1/0=+inf) for year, month, day, hour, minute, second, tzhour, tzmin | ||
local minval = { | local minval = { -1/0, 01, 01, 00, 00, 00, -23, 00 } -- min values (or -1/0=-inf) for year, month, ... | ||
local | local codes = { 'Y', 'M', 'D', 'h', 'm', 's', '', '' } -- WARNING: 'M' alone would be ambiguous if it does not follow 'Y' or 'h' | ||
local datecode = '' -- a string signifying which combination of variables was provided | local datecode = '' -- a string signifying which combination of variables was provided | ||
local datenum = {} | local datenum = {} -- date-time encoded as a vector = [year, month, ... , second, tzhour, tzmin] | ||
for i = 1,8 do | for i = 1, 8 do | ||
local c, val = codes[i], datevec[i] | |||
if c == 'M' and type(val) == 'string' and val ~= '' and not tonumber(val) then | |||
datecode = datecode .. c[i] | -- When the month is not a number, check if it's a month name in the project's language. | ||
val = mw.getContentLanguage():formatDate('n', val) | |||
end | |||
val = tonumber(val) | |||
if val and val >= minval[i] and val <= maxval[i] then -- These tests work with infinite min/max values. | |||
if c == 'm' then -- Field for minute accepted only if it follows another valid 'M', 'D' or 'h' field. | |||
if not string.find('MDh', datecode:sub(-1)) then | |||
c = ''; val = nil -- field for minute is invalid | |||
end | |||
elseif c == 's' then -- Field for leap second '60' is valid only at end of 23:59 UTC, on 30 June or 31 December of specific years. | |||
if val == 60 and not( -- Leap second are are added (or dropped) on specific dates planned only some months before. | |||
datenum[1] and -- A year is specified (to check it would require constantly maintaining a table of dates). | |||
(datenum[2] == 6 and datenum[3] == 30 or datenum[2] == 12 and datenum[3] == 31) and | |||
datenum[4] == 23 and datenum[5] == 59 | |||
) then | |||
c = ''; val = nil -- Field for second is invalid in this case, don't add the field. | |||
end | |||
end | |||
datecode = datecode .. c | |||
datenum[i] = val | |||
end | end | ||
end | end | ||
94行目: | 107行目: | ||
-- process datevec | -- process datevec | ||
-- INPUT: | -- INPUT: | ||
-- * datecode - a code specifying content of the array where Y' is year, 'M' is month, | -- * datecode - a code specifying content of the array where Y' is year, 'M' is month, | ||
-- 'D' is day, 'H' is hour, ' | -- 'D' is day, 'H' is hour, 'i' minute, 's' is second. | ||
-- Output has to be one of YMDhms, YMDhm, YMD, YM, Y, MDhms, MDhm, MD, M. | |||
-- * datenum - Array of {year,month,day,hour,minute,second, tzhour, tzmin} as numbers or nuls | -- * datenum - Array of {year,month,day,hour,minute,second, tzhour, tzmin} as numbers or nuls | ||
-- OUTPUT: | -- OUTPUT: | ||
-- * timeStamp - date string in the format taken by mw.language:formatDate lua function and {{#time}} | -- * 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/Extension:Scribunto/Lua_reference_manual#mw.language:formatDate | ||
-- https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time | -- https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time | ||
-- * datecode - with possible corrections | -- * datecode - with possible corrections | ||
local function getTimestamp(datecode, datenum) | local function getTimestamp(datecode, datenum) | ||
-- create | -- create timestamp string (for example 2000-02-20 02:20:20) based on which variables were provided | ||
local timeStamp | local timeStamp | ||
if datecode == ' | -- 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] ) | timeStamp = string.format('%04i-%02i-%02i %02i:%02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5], datenum[6] ) | ||
elseif datecode == ' | elseif datecode == 'YMDhm' then | ||
timeStamp = string.format('%04i-%02i-%02i %02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5] ) | 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 | elseif datecode:sub(1,3)=='YMD' then | ||
timeStamp = string.format('%04i-%02i-%02i', datenum[1], datenum[2], datenum[3] ) | timeStamp = string.format('%04i-%02i-%02i', datenum[1], datenum[2], datenum[3] ) | ||
datecode = 'YMD' -- ' | datecode = 'YMD' -- 'YMDhms', 'YMDhm' and 'YMD' are the only supported format starting with 'YMD'; all others will be converted to 'YMD'. | ||
elseif datecode == 'YM' then | elseif datecode:sub(1,2) == 'YM' then | ||
timeStamp = string.format('%04i-%02i', datenum[1], datenum[2] ) | timeStamp = string.format('%04i-%02i', datenum[1], datenum[2] ) | ||
elseif datecode:sub(1,1)=='Y' then | elseif datecode:sub(1,1)=='Y' then | ||
timeStamp = string.format('%04i', datenum[1] ) | timeStamp = string.format('%04i', datenum[1] ) | ||
datecode = 'Y' | datecode = 'Y' | ||
elseif datecode == 'M' then | -- 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 ) | timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], 1 ) | ||
-- 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 | else | ||
timeStamp = nil -- format not supported | timeStamp = nil -- format not supported | ||
159行目: | 182行目: | ||
-- Look up proper format string to be passed to {{#time}} parser function | -- Look up proper format string to be passed to {{#time}} parser function | ||
-- INPUTS: | -- INPUTS: | ||
-- * datecode: | -- * datecode: YMDhms, YMDhm, YMD, YM, Y, MDhms, MDhm, MD, or M | ||
-- * day : Number between 1 and 31 (not needed for most languages) | -- * day : Number between 1 and 31 (not needed for most languages) | ||
-- * lang : language | -- * lang : language | ||
167行目: | 190行目: | ||
local function parseFormat(dFormat, day) | local function parseFormat(dFormat, day) | ||
if dFormat:find('default') and #dFormat>10 then | 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( dFormat ) | local D = mw.text.jsonDecode(mw.ustring.gsub(dFormat, '[„“‟”]', '"')) --com = mw.dumpObject(D) | ||
day = string.format('d%02i',day) | -- 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 | end | ||
dFormat = dFormat:gsub("'", '"') | |||
return dFormat | return dFormat | ||
end | end | ||
185行目: | 211行目: | ||
T[id] = msg | T[id] = msg | ||
end | 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] | local dFormat = T[datecode] | ||
if dFormat=='default' and (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 | -- day precission date, those languages are skipped in DateI18n.tab and default to | ||
-- English which stores word "default" | -- English which stores word "default" | ||
dFormat = parseFormat(T['YMD'], day).. ', H:i' | dFormat = parseFormat(T['YMD'], day).. ', H:i' | ||
if datecode==' | if datecode == 'YMDhms' then | ||
dFormat = dFormat .. ':s' | dFormat = dFormat .. ':s' | ||
end | end | ||
244行目: | 275行目: | ||
lang = mw.getCurrentFrame():callParserFunction( "int", "lang" ) -- get user's chosen language | lang = mw.getCurrentFrame():callParserFunction( "int", "lang" ) -- get user's chosen language | ||
end | end | ||
if lang == 'be- | if lang == 'be-tarask' then | ||
lang = 'be-x-old' | lang = 'be-x-old' | ||
end | end | ||
265行目: | 296行目: | ||
-- phrases as it is done in [[c:Module:Complex date]] | -- phrases as it is done in [[c:Module:Complex date]] | ||
case = case or '' | case = case or '' | ||
if (lang=='qu' or lang=='qug') and | if (lang=='qu' or lang=='qug') and case=='nom' then | ||
-- Special case related to Quechua and Kichwa languages. The form in the I18n is | -- 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}} | -- Genitive case with suffix "pi" added to month names provided by {#time}} | ||
271行目: | 302行目: | ||
-- see https://commons.wikimedia.org/wiki/Template_talk:Date#Quechua from 2014 | -- see https://commons.wikimedia.org/wiki/Template_talk:Date#Quechua from 2014 | ||
dFormat = dFormat:gsub('F"pi"', 'F') | dFormat = dFormat:gsub('F"pi"', 'F') | ||
elseif | elseif case == 'gen' then | ||
dFormat = strReplace(dFormat, "F", "xg") | dFormat = strReplace(dFormat, "F", "xg") | ||
elseif | elseif case == 'nom' then | ||
dFormat = strReplace(dFormat, "xg", "F") | dFormat = strReplace(dFormat, "xg", "F") | ||
elseif | elseif case ~= '' then | ||
-- see is page [[Data:I18n/MonthCases.tab]] on Commons have name of the month | -- 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 | -- in specific gramatic case in desired language. If we have it than replace | ||
286行目: | 317行目: | ||
end | end | ||
-- Translate the date using specified format | -- Translate the date using specified format. | ||
-- See https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.language:formatDate and | -- 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 | -- https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions##time for explanation of the format | ||
local | 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 | -- 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 | if lang=='th' and datecode=='Y' and year<=1940 then | ||
datestr = string.format('%04i หรือ %04i', year+542, year+543 ) | datestr = string.format('%04i หรือ %04i', year+542, year+543 ) | ||
end | end | ||
-- If year<1000 than either keep the date padded to the length of 4 digits or trim it | -- 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 | if year and year < 1000 then | ||
trim_year = yesno(trim_year, '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. | |||
if | |||
-- | |||
-- | |||
local YMin, YMax = trim_year:match( '(%d+)-(%d+)' ) | local YMin, YMax = trim_year:match( '(%d+)-(%d+)' ) | ||
trim_year = YMin and year >= tonumber(YMin) and year <= tonumber(YMax) | |||
end | end | ||
if | if trim_year then | ||
datestr = trimYear(datestr, year, lang) -- in datestr replace long year with trimmed one | datestr = trimYear(datestr, year, lang) -- in datestr replace long year with trimmed one | ||
end | end | ||
end | end | ||
-- | -- Append a timezone if present (after the hour and minute of the day). | ||
if datenum[7] and (datecode == ' | 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 '+' | local sign = (datenum[7]<0) and '−' or '+' | ||
timeStamp = string.format("2000-01-01 %02i:%02i:00", math.abs(datenum[7]), datenum[8] or 0) | timeStamp = string.format("2000-01-01 %02i:%02i:00", math.abs(datenum[7]), datenum[8] or 0) | ||
local timezone = | local timezone = langObj:formatDate('H:i', timeStamp) -- same as using {{#time}} parser function | ||
datestr = string.format("%s %s%s", datestr, sign, timezone ) | datestr = string.format("%s %s%s", datestr, sign, timezone ) | ||
end | end | ||
-- | -- HTML formating of date string and tagging for microformats (only for absolute dates with a year). | ||
if class and class ~= '' and datecode | if class and class ~= '' and datecode.sub(1,1) == 'Y' then -- | ||
datestr = | |||
('<time class="%s" datetime="%s" lang="%s" dir="%s" style="white-space:nowrap">%s</time>') | |||
:format(class, timeStamp, lang, langObj:getDir(), datestr) | |||
end | end | ||
return datestr | return datestr |