「モジュール:Complex date」の版間の差分
ナビゲーションに移動
検索に移動
細
Changed protection level for "Module:Complex date": downgraded protection level per consensus ([Move=Allow only template editors and administrators] (indefinite) [Edit=Allow only template editors and administrators]…
細 (1版) |
bsd>4nn1l2 細 (Changed protection level for "Module:Complex date": downgraded protection level per consensus ([Move=Allow only template editors and administrators] (indefinite) [Edit=Allow only template editors and administrators]…) |
||
1行目: | 1行目: | ||
--[[ | --[[ | ||
__ __ _ _ ____ _ _ _ | |||
| \/ | ___ __| |_ _| | ___ _ / ___|___ _ __ ___ _ __ | | _____ __ __| | __ _| |_ ___ | |||
| |\/| |/ _ \ / _` | | | | |/ _ (_) | / _ \| '_ ` _ \| '_ \| |/ _ \ \/ / / _` |/ _` | __/ _ \ | |||
| | | | (_) | (_| | |_| | | __/_| |__| (_) | | | | | | |_) | | __/> < | (_| | (_| | || __/ | |||
|_| |_|\___/ \__,_|\__,_|_|\___(_)\____\___/|_| |_| |_| .__/|_|\___/_/\_\ \__,_|\__,_|\__\___| | |||
|_| | |||
This module is intended for creation of complex date phrases in variety of languages. | This module is intended for creation of complex date phrases in variety of languages. | ||
14行目: | 20行目: | ||
-- List of external modules and functions | -- List of external modules and functions | ||
local p = {Error = nil} | local p = {Error = nil} | ||
local i18n = require('Module:i18n/complex date') | local i18n = require('Module:i18n/complex date') -- used for translations of date related phrases | ||
local ISOdate = require('Module:ISOdate')._ISOdate -- used for parsing dates in YYYY-MM-DD and related formats | |||
local ISOdate = require('Module:ISOdate')._ISOdate | local formatnum = require('Module:Formatnum').formatNum -- used for translation into other alphabets | ||
local Calendar = require('Module:Calendar') -- used for conversions between Julian and Gregorian calendar dates | |||
local formatnum = require('Module:Formatnum').formatNum | |||
local | |||
-- ================================================== | -- ================================================== | ||
25行目: | 29行目: | ||
-- ================================================== | -- ================================================== | ||
function formatnum1(numStr, lang) | local function langSwitch(list,lang) | ||
local langList = mw.language.getFallbacksFor(lang) | |||
table.insert(langList,1,lang) | |||
table.insert(langList,math.max(#langList,2),'default') | |||
for i,language in ipairs(langList) do | |||
if list[language] then | |||
return list[language] | |||
end | |||
end | |||
end | |||
-- ================================================== | |||
local function formatnum1(numStr, lang) | |||
-- mostly require('Module:Formatnum').formatNum function used to translate a number to use different numeral characters, | -- mostly require('Module:Formatnum').formatNum function used to translate a number to use different numeral characters, | ||
-- except that it it does not call that function unless the language is on the list "LList" | -- except that it it does not call that function unless the language is on the list "LList" | ||
35行目: | 51行目: | ||
end | end | ||
function getISODate(datestr, datetype, lang, num, case) | -- ================================================== | ||
local function getISODate(datestr, datetype, lang, num, case) | |||
-- translate dates in the format YYYY, YYYY-MM, and YYYY-MM-DD | -- translate dates in the format YYYY, YYYY-MM, and YYYY-MM-DD | ||
if not case and i18n.Translations[datetype] then | if not case and i18n.Translations[datetype] then | ||
47行目: | 64行目: | ||
end | end | ||
function translatePhrase(date1, date2, operation, lang, state) | -- ======================================================================= | ||
local function translatePhrase(date1, date2, operation, lang, state) | |||
-- use tables in Module:i18n/complex date to translate a phrase | -- use tables in Module:i18n/complex date to translate a phrase | ||
if not i18n.Translations[operation] then | if not i18n.Translations[operation] then | ||
58行目: | 76行目: | ||
end | end | ||
if type(dateStr)=='function' then | if type(dateStr)=='function' then | ||
local | local dateFunc = dateStr | ||
local nDates = i18n.Translations[operation]['nDates'] | local nDates = i18n.Translations[operation]['nDates'] | ||
if nDates==2 then -- 2 date phrase | if nDates==2 then -- 2 date phrase | ||
dateStr = dateFunc(date1, date2, state) | |||
else -- 1 date phrase | else -- 1 date phrase | ||
dateStr = dateFunc(date1, state) | |||
end | end | ||
end | end | ||
80行目: | 98行目: | ||
end | end | ||
function oneDatePhrase(dateStr, adj, era, units, lang, num, case, state) | -- ======================================================================= | ||
local function oneDatePhrase(dateStr, adj, era, units, lang, num, case, state) | |||
-- translate a single date phrase | -- translate a single date phrase | ||
if num==2 then | if num==2 then | ||
109行目: | 128行目: | ||
end | end | ||
function twoDatePhrase(date1, date2, state, lang) | -- ======================================================================= | ||
local function twoDatePhrase(date1, date2, state, lang) | |||
-- translate a double date phrase | -- translate a double date phrase | ||
local dateStr, case | local dateStr, case | ||
135行目: | 155行目: | ||
end | end | ||
function otherPhrases(date1, date2, operation, era, lang, state) | -- ======================================================================= | ||
local function otherPhrases(date1, date2, operation, era, lang, state) | |||
-- translate specialized phrases | -- translate specialized phrases | ||
local dateStr = '' | local dateStr = '' | ||
147行目: | 168行目: | ||
era = '' | era = '' | ||
elseif operation == 'julian' then | elseif operation == 'julian' then | ||
if not date2 and date1 then -- Convert from Julian to Gregorian calendar date | |||
local JDN = Calendar._date2jdn(date1, 0) | |||
if JDN then | |||
date2 = date1 -- first date is assumed to be Julian | |||
date1 = Calendar._jdn2date(JDN, 1) | |||
end | |||
end | |||
date1 = getISODate(date1, operation, lang, 1, nil) | date1 = getISODate(date1, operation, lang, 1, nil) | ||
date2 = getISODate(date2, operation, lang, 2, nil) | date2 = getISODate(date2, operation, lang, 2, nil) | ||
dateStr = translatePhrase(date1, date2, operation, lang, state) | dateStr = translatePhrase(date1, date2, operation, lang, state) | ||
dateStr = mw.ustring.gsub(mw.ustring.gsub(dateStr, '%( ', '('), ' %)', ')') -- in case date2 is empty | |||
elseif operation == 'turn of the year' or operation == 'turn of the decade' or operation == 'turn of the century' then | elseif operation == 'turn of the year' or operation == 'turn of the decade' or operation == 'turn of the century' then | ||
if operation == 'turn of the decade' then dt=10 | local dt = 1; | ||
if operation == 'turn of the decade' then dt=10 end | |||
if not date2 or date2=='' then date2=tostring(tonumber(date1)-dt) end | if not date2 or date2=='' then date2=tostring(tonumber(date1)-dt) end | ||
if era~='bp' and era~='bc' then date1, date2 = date2, date1 end | if era~='bp' and era~='bc' then date1, date2 = date2, date1 end | ||
163行目: | 193行目: | ||
dateStr = translatePhrase(date1, date2, operation, lang, state) | dateStr = translatePhrase(date1, date2, operation, lang, state) | ||
elseif operation == 'year unknown' then | elseif operation == 'year unknown' then | ||
dateStr = translatePhrase('', '', operation, lang, state) | dateStr = translatePhrase('', '', operation, lang, state) .. '<div style="display: none;">Unknown date</div>' | ||
elseif operation == 'unknown' then | elseif operation == 'unknown' then | ||
dateStr = tostring(mw.message.new( "exif-unknowndate" ):inLanguage( lang )) | dateStr = tostring(mw.message.new( "exif-unknowndate" ):inLanguage( lang )) .. '<div style="display: none;">Unknown date</div>' | ||
end | end | ||
175行目: | 205行目: | ||
end | end | ||
function checkAliases(str1, str2, sType) | -- ======================================================================= | ||
local function checkAliases(str1, str2, sType) | |||
-- some inputs have many aliases - reconcile them and ensure string is playing a proper role | -- some inputs have many aliases - reconcile them and ensure string is playing a proper role | ||
local out = '' | local out = '' | ||
if str1 and str1~='' then | if str1 and str1~='' then | ||
a = i18n.Synonyms[str1] -- look up synonyms of "str1" | local a = i18n.Synonyms[str1] -- look up synonyms of "str1" | ||
if a then | if a then | ||
out = a[1] | out = a[1] | ||
186行目: | 217行目: | ||
end | end | ||
elseif str2 and str2~='' then -- if "str1" of type "sType" is empty than maybe ... | elseif str2 and str2~='' then -- if "str1" of type "sType" is empty than maybe ... | ||
a = i18n.Synonyms[str2] -- ..."str2" is of the same type and is not empty | local a = i18n.Synonyms[str2] -- ..."str2" is of the same type and is not empty | ||
if a and a[2]==sType then | if a and a[2]==sType then | ||
out = a[1] | out = a[1] | ||
195行目: | 226行目: | ||
end | end | ||
function datePrecision(dateStr, units) | -- ======================================================================= | ||
local function datePrecision(dateStr, units) | |||
-- "in this module "Units" is a string like millennium, century, or decade | -- "in this module "Units" is a string like millennium, century, or decade | ||
-- "precision" is wikibase compatible date precision number: 6=millennium, 7=century, 8=decade, 9=year, 10=month, 11=day | -- "precision" is wikibase compatible date precision number: 6=millennium, 7=century, 8=decade, 9=year, 10=month, 11=day | ||
-- based on string or numeric input calculate "Units" and "precision" | -- based on string or numeric input calculate "Units" and "precision" | ||
local precision | |||
local dateNum = tonumber(dateStr); | local dateNum = tonumber(dateStr); | ||
if type(units)=='number' then | if type(units)=='number' then | ||
233行目: | 266行目: | ||
end | end | ||
-- ================================================== | -- ======================================================================= | ||
-- === | local function isodate2timestamp(dateStr, precision, era) | ||
-- convert date string to timestamps used by Quick Statements | |||
local tStamp = nil | |||
if era == 'ah' or precision<6 then | |||
return nil | |||
elseif era ~= '' then | |||
local eraLUT = {ad='+', bc='-', bp='-' } | |||
era = eraLUT[era] | |||
else | |||
era='+' | |||
end | |||
-- convert isodate to timestamp used by quick statements | |||
if precision>=9 then | |||
if string.match(dateStr,"^%d%d%d%d$") then -- if YYYY format | |||
tStamp = era .. dateStr .. '-00-00T00:00:00Z/9' | |||
elseif string.match(dateStr,"^%d%d%d%d%-%d%d$") then -- if YYYY-MM format | |||
tStamp = era .. dateStr .. '-00T00:00:00Z/10' | |||
elseif string.match(dateStr,"^%d%d%d%d%-%d%d%-%d%d$") then -- if YYYY-MM-DD format | |||
tStamp = era .. dateStr .. 'T00:00:00Z/11' | |||
end | |||
elseif precision==8 then -- decade | |||
tStamp = era .. dateStr .. '-00-00T00:00:00Z/8' | |||
elseif precision==7 then -- century | |||
local d = tostring(tonumber(dateStr)-1) | |||
tStamp = era .. d .. '50-00-00T00:00:00Z/7' | |||
elseif precision==6 then | |||
local d = tostring(tonumber(dateStr)-1) | |||
tStamp = era .. d .. '500-00-00T00:00:00Z/6' | |||
end | |||
return tStamp | |||
end | |||
-- ======================================================================= | |||
local function oneDateQScode(dateStr, adj, era, precision) | |||
-- create QuickStatements string for "one date" dates | |||
local outputStr = '' | |||
local d = isodate2timestamp(dateStr, precision, era) | |||
if not d then | |||
return '' | |||
local | |||
if | |||
end | end | ||
local rLUT = { early='Q40719727' , mid='Q40719748', late='Q40719766', | |||
['1quarter']='Q40690303' , ['2quarter']='Q40719649' , ['3quarter']='Q40719662', ['4quarter']='Q40719674', | |||
spring='Q40720559' , summer='Q40720564' , autumn='Q40720568' , winter='Q40720553', | |||
firsthalf='Q40719687', secondhalf='Q40719707' } | |||
local qLUT = {['from']='P580', ['until']='P582', ['after']='P1319', ['before']='P1326', ['by']='P1326'} | |||
local refine = rLUT[adj] | |||
local qualitier = qLUT[adj] | |||
if adj=='' then | |||
outputStr = d | |||
elseif adj=='circa' then | |||
outputStr = d..",P1480,Q5727902" | |||
elseif refine then | |||
outputStr = d..",P4241,"..refine | |||
elseif precision>7 and qualitier then | |||
local century = string.gsub(d, 'Z%/%d+', 'Z/7') | |||
outputStr = century ..",".. qualitier ..","..d | |||
end | end | ||
return | return outputStr | ||
end | end | ||
function | -- ======================================================================= | ||
local function twoDateQScode(date1, date2, state) | |||
-- create QuickStatements string for "two date" dates | |||
if state.adj1~='' or state.adj2~='' or state.era1~=state.era2 then | |||
return '' -- QuickStatements string are not generated for two date phrases with adjectives | |||
local | end | ||
local | local outputStr = '' | ||
local | local d1 = isodate2timestamp(date1, state.precision1, state.era1) | ||
local | local d2 = isodate2timestamp(date2, state.precision2, state.era2) | ||
local | if (not d1) or (not d2) then | ||
local | return '' | ||
end | |||
-- find date with lower precision in common to both dates | |||
local | local cd | ||
local year1 = tonumber(string.sub(d1,2,5)) | |||
local year2 = tonumber(string.sub(d2,2,5)) | |||
local k = 0 | |||
for i = 1,10,1 do | |||
if string.sub(d1,1,i)==string.sub(d2,1,i) then | |||
k = i -- find last matching letter | |||
end | |||
end | |||
if k>=9 then -- same month, since "+YYYY-MM-" is in common | |||
cd = isodate2timestamp(string.sub(d1,2,8), 10, state.era1) | |||
elseif k>=6 and k<9 then -- same year, since "+YYYY-" is in common | |||
cd = isodate2timestamp(tostring(year1), 9, state.era1) | |||
elseif k==4 then -- same decade(k=4, precision=8), since "+YYY" is in common | |||
cd = isodate2timestamp(tostring(year1), 8, state.era1) | |||
elseif k==3 then -- same century(k=3, precision=7) since "+YY" is in common | |||
local d = tostring(math.floor(year1/100) +1) -- convert 1999 -> 20 | |||
cd = isodate2timestamp( d, 7, state.era1) | |||
elseif k==2 then -- same millennium (k=2, precision=6), since "+Y" is in common | |||
local d = tostring(math.floor(year1/1000) +1) -- convert 1999 -> 2 | |||
cd = isodate2timestamp( d, 6, state.era1) | |||
end | |||
if not cd then | |||
return '' | |||
end | end | ||
--if not cd then | |||
-- return ' <br/>error: ' .. d1.." / " .. d2.." / ".. (cd or '') .." / ".. string.sub(d1,2,5).." / " .. string.sub(d2,2,5).." / " .. tostring(k) | |||
--end | |||
-- | |||
if (state.conj=='from-until') or (state.conj=='and' and year1==year2-1) then | |||
outputStr = cd ..",P580,".. d1 ..",P582,".. d2 | |||
elseif (state.conj=='between') or (state.conj=='or' and year1==year2-1) then | |||
outputStr = cd ..",P1319,".. d1 ..",P1326,".. d2 | |||
elseif state.conj=='circa2' then | |||
outputStr = cd ..",P1319,".. d1 ..",P1326,".. d2 ..",P1480,Q5727902" | |||
end | end | ||
return | |||
return outputStr | |||
end | end | ||
-- ======================================================================= | |||
local state = {} | local function processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) | ||
-- process inputs and save date in state array | |||
local state = {} | |||
state.conj = string.lower(conj or '') | state.conj = string.lower(conj or '') | ||
state.adj1 = string.lower(adj1 or '') | state.adj1 = string.lower(adj1 or '') | ||
348行目: | 454行目: | ||
state.units2 = '' | state.units2 = '' | ||
end | end | ||
end | |||
state.adj, state.era, state.units, state.precision = state.adj1, state.era1, state.units1, state.precision1 | |||
return date1, date2, state | |||
end | |||
-- ================================================== | |||
-- === External functions =========================== | |||
-- ================================================== | |||
function p.Era(frame) | |||
-- process inputs | |||
local dateStr | |||
local args = frame.args | |||
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then | |||
args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language | |||
end | |||
local lang = args['lang'] | |||
local dateStr = args['date'] or '' | |||
local eraType = string.lower(args['era'] or '') | |||
dateStr = ISOdate(dateStr, lang, '', '', 1) | |||
if eraType then | |||
eraType = checkAliases(eraType ,'','e') | |||
dateStr = translatePhrase(dateStr, '', eraType, lang, {}) | |||
end | |||
return dateStr | |||
end | |||
-- ======================================================================= | |||
function p._complex_date(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) | |||
local Output='' | |||
local state | |||
-- process inputs and save date in state array | |||
date1, date2, state = processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) | |||
if p.Error~=nil then | |||
return nil | |||
end | end | ||
354行目: | 498行目: | ||
state.conj, state.adj1, state.era1, state.units1, state.precision1, | state.conj, state.adj1, state.era1, state.units1, state.precision1, | ||
state.adj2, state.era2, state.units2, state.precision2, state.special) | state.adj2, state.era2, state.units2, state.precision2, state.special) | ||
-- call specialized functions | -- call specialized functions | ||
local QScode = '' | |||
if state.special~='' then | if state.special~='' then | ||
Output = otherPhrases(date1, date2, state.special, state.era1, lang, state) | Output = otherPhrases(date1, date2, state.special, state.era1, lang, state) | ||
elseif state.conj~='' then | elseif state.conj~='' then | ||
QScode = twoDateQScode(date1, date2, state) | |||
Output = twoDatePhrase(date1, date2, state, lang) | Output = twoDatePhrase(date1, date2, state, lang) | ||
elseif state.adj1~='' or state.era1~='' or state.units1~='' then | elseif state.adj1~='' or state.era1~='' or state.units1~='' then | ||
Output = oneDatePhrase(date1, state.adj1, state.era1, state.units1, lang, 1, nil, state) | Output = oneDatePhrase(date1, state.adj1, state.era1, state.units1, lang, 1, nil, state) | ||
QScode = oneDateQScode(date1, state.adj1, state.era1, state.precision1) | |||
elseif date1~='' then | elseif date1~='' then | ||
Output = ISOdate(date1, lang, '', 'dtstart', '100-999') | Output = ISOdate(date1, lang, '', 'dtstart', '100-999') | ||
373行目: | 519行目: | ||
if mw.ustring.find(Output, '{') then | if mw.ustring.find(Output, '{') then | ||
Output = mw.getCurrentFrame():preprocess(Output) | Output = mw.getCurrentFrame():preprocess(Output) | ||
end | |||
if QScode and #QScode>0 then | |||
QScode = ' <div style="display: none;">date QS:P,' .. QScode .. '</div>' | |||
end | end | ||
return Output | return Output .. QScode | ||
end | end | ||
-- ======================================================================= | |||
function p._complex_date_cer(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, certainty, lang) | |||
-- same as p._complex_date but with extra parameter for certainty: probably, possibly, presumably, etc. | |||
local dateStr = p._complex_date(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, 1) | |||
certainty = checkAliases(certainty, conj, 'r') | |||
local LUT = {probably='Q56644435', presumably='Q18122778', possibly='Q30230067', circa='Q5727902' } | |||
if certainty and LUT[certainty] then | |||
local state = {} | |||
date1, date2, state = processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, 1) | |||
dateStr = translatePhrase(dateStr, '', certainty, lang, state) | |||
dateStr = string.gsub(dateStr, '(%<div style="display: none;"%>date QS:P,[^%<]+)(%</div%>)', '%1,P1480,' .. LUT[certainty] .. '%2' ) | |||
end | |||
return dateStr | |||
end | |||
-- ======================================================================= | |||
function p.complex_date(frame) | |||
-- process inputs | |||
local dateStr, Error | |||
local args = frame.args | |||
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then | |||
args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language | |||
end | |||
local date1 = args['date1'] or args['2'] or args['date'] or '' | |||
local date2 = args['date2'] or args['3'] or '' | |||
local conj = args['conj'] or args['1'] or '' | |||
local adj1 = args['adj1'] or args['adj'] or '' | |||
local adj2 = args['adj2'] or '' | |||
local units1 = args['precision1'] or args['precision'] or '' | |||
local units2 = args['precision2'] or args['precision'] or '' | |||
local era1 = args['era1'] or args['era'] or '' | |||
local era2 = args['era2'] or args['era'] or '' | |||
local certainty = args['certainty'] | |||
local lang = args['lang'] | |||
dateStr = p._complex_date_cer(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, certainty, lang) | |||
if p.Error~=nil then | |||
dateStr = p.Error .. '[[Category:Pages using Complex date template with incorrect parameter]]' | |||
end | |||
return dateStr | |||
end | |||
return p | return p |