Module:Citation/CS1/Date validation: Difference between revisions
synch from sandbox;
m>Trappist the monk (Synch from sandbox;) |
m>Trappist the monk (synch from sandbox;) |
||
Line 6: | Line 6: | ||
]] | ]] | ||
local is_set, in_array; | local is_set, in_array; -- imported functions from selected Module:Citation/CS1/Utilities | ||
local cfg; -- table of tables imported from slected Module:Citation/CS1/Configuration | |||
--[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >---------------------------------------- | --[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >---------------------------------------- | ||
Line 58: | Line 58: | ||
local function get_month_number (month) | local function get_month_number (month) | ||
return cfg.date_names['local'].long[month] or cfg.date_names['local'].short[month] or -- look for local names first | |||
cfg.date_names['en'].long[month] or cfg.date_names['en'].short[month] or -- failing that, look for English names | |||
0; -- not a recognized month name | |||
end | end | ||
Line 88: | Line 86: | ||
returns a number according to the sequence of seasons in a year: 1 for Winter, etc. Capitalization and spelling must be correct. If not a valid season, returns 0 | returns a number according to the sequence of seasons in a year: 1 for Winter, etc. Capitalization and spelling must be correct. If not a valid season, returns 0 | ||
Uses ISO DIS 8601 2016 part 2 §4.7 Divisions of a year for hemishpere-independent seasons: | |||
21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere” | |||
These additional divisions not currently supported: | |||
25-28 = Spring - Northern Hemisphere, Summer- Northern Hemisphere, Autumn - Northern Hemisphere, Winter - Northern Hemisphere | |||
29-32 = Spring – Southern Hemisphere, Summer– Southern Hemisphere, Autumn – Southern Hemisphere, Winter - Southern Hemisphere | |||
33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each) | |||
37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each) | |||
40-41 = Semestral 1, Semestral-2 (6 months each) | |||
]] | ]] | ||
local function get_season_number (season) | local function get_season_number (season) | ||
return cfg.date_names['local'].season[season] or -- look for local names first | |||
cfg.date_names['en'].season[season] or -- failing that, look for English names | |||
0; -- not a recognized season name | |||
end | end | ||
Line 106: | Line 113: | ||
local function is_proper_name (name) | local function is_proper_name (name) | ||
return cfg.date_names['local'].named[name] or -- look for local names dates first | |||
local | cfg.date_names['en'].named[name] or -- failing that, look for English names | ||
0; -- not a recognized named date | |||
end | end | ||
Line 211: | Line 216: | ||
Month pairs are expected to be left to right, earliest to latest in time. | Month pairs are expected to be left to right, earliest to latest in time. | ||
All season ranges are accepted as valid because there are publishers out there who have published a Summer–Spring YYYY issue so ... ok | |||
]] | ]] | ||
Line 221: | Line 225: | ||
if 0 == range_start_number then -- is this a month range? | if 0 == range_start_number then -- is this a month range? | ||
range_start_number = get_season_number (range_start); -- not a month; is it a season? get start season number | |||
range_end_number = get_season_number (range_end); -- get end season number | range_end_number = get_season_number (range_end); -- get end season number | ||
if 0 ~= range_start_number then | if (0 ~= range_start_number) and (0 ~= range_end_number) then | ||
return true; -- any season pairing is accepted | |||
end | end | ||
return false; | return false; -- range_start and/or range_end is not a season | ||
end | end | ||
-- here when range_start is a month | |||
range_end_number = get_month_number (range_end); -- get end month number | range_end_number = get_month_number (range_end); -- get end month number | ||
if range_start_number < range_end_number then -- range_start is a month; does range_start precede range_end? | if range_start_number < range_end_number then -- range_start is a month; does range_start precede range_end? | ||
Line 366: | Line 365: | ||
if 12 < tonumber(month) or 1 > tonumber(month) or 1582 > tonumber(year) or 0 == tonumber(day) then return false; end -- month or day number not valid or not Gregorian calendar | if 12 < tonumber(month) or 1 > tonumber(month) or 1582 > tonumber(year) or 0 == tonumber(day) then return false; end -- month or day number not valid or not Gregorian calendar | ||
anchor_year = year; | anchor_year = year; | ||
elseif date_string:match("^%a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year | elseif date_string:match("^%a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year | ||
month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d?),%s*((%d%d%d%d)%a?)"); | month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d?),%s*((%d%d%d%d?)%a?)"); | ||
month = get_month_number (month); | month = get_month_number (month); | ||
if 0 == month then return false; end -- return false if month text isn't one of the twelve months | if 0 == month then return false; end -- return false if month text isn't one of the twelve months | ||
Line 381: | Line 379: | ||
elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year | elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year | ||
day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)"); | day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d?)%a?)"); | ||
month = get_month_number (month); | month = get_month_number (month); | ||
if 0 == month then return false; end -- return false if month text isn't one of the twelve months | if 0 == month then return false; end -- return false if month text isn't one of the twelve months | ||
Line 400: | Line 398: | ||
year2=year; | year2=year; | ||
elseif mw.ustring.match(date_string, "^%a+ +[1-9]%d? [%-–] %a+ +[1-9]%d?, +[1-9]%d%d%d | elseif mw.ustring.match(date_string, "^%a+ +[1-9]%d? [%-–] %a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month initial month-day-range: month day – month day, year; uses spaced endash | ||
month, day, month2, day2, anchor_year, year=mw.ustring.match(date_string, "(%a+) +(%d%d?) [%-–] (%a+) +(%d%d?), +((%d%d%d%d)%a?)"); | month, day, month2, day2, anchor_year, year=mw.ustring.match(date_string, "(%a+) +(%d%d?) [%-–] (%a+) +(%d%d?), +((%d%d%d%d)%a?)"); | ||
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end | if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end | ||
Line 408: | Line 406: | ||
elseif mw.ustring.match(date_string, "^[1-9]%d? +%a+ +[1-9]%d%d%d [%-–] [1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day initial month-day-year-range: day month year - day month year; uses spaced endash | elseif mw.ustring.match(date_string, "^[1-9]%d? +%a+ +[1-9]%d%d%d [%-–] [1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day initial month-day-year-range: day month year - day month year; uses spaced endash | ||
day, month, year, day2, month2, anchor_year, year2=mw.ustring.match(date_string, "(%d%d?) +(%a+) +(%d%d%d%d | day, month, year, day2, month2, anchor_year, year2=mw.ustring.match(date_string, "(%d%d?) +(%a+) +(%d%d%d%d) [%-–] (%d%d?) +(%a+) +((%d%d%d%d)%a?)"); | ||
if tonumber(year2) <= tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later | if tonumber(year2) <= tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later | ||
if not is_valid_year(year2) or not is_valid_month_range_style(month, month2) then return false; end -- year2 no more than one year in the future; months same style | if not is_valid_year(year2) or not is_valid_month_range_style(month, month2) then return false; end -- year2 no more than one year in the future; months same style | ||
Line 662: | Line 660: | ||
local source_patterns = { -- this table holds patterns that match allowed date formats used to extract date components | local source_patterns = { -- this table holds patterns that match allowed date formats used to extract date components | ||
['dmy'] = '(%d%d?)%s+(%a+)%s+(%d%d%d%d)', | ['dmy'] = '^(%d%d?)%s+(%a+)%s+(%d%d%d%d)$', | ||
['mdy'] = '(%a+)%s+(%d%d?),%s+(%d%d%d%d)', | ['mdy'] = '^(%a+)%s+(%d%d?),%s+(%d%d%d%d)$', | ||
['ymd'] = '(%d%d%d%d)%-(%d%d)-(%d%d)', | ['ymd'] = '^(%d%d%d%d)%-(%d%d)-(%d%d)$', | ||
} | } | ||
Line 723: | Line 721: | ||
Date ranges, season dates, proper name dates are not currently supported. | Date ranges, season dates, proper name dates are not currently supported. | ||
For i18n: This code works only at en.wiki because os.date() doesn't support any languages other than English. | |||
mw.getContentLanguage():formatDate() will work at non-English wikis only when the date format is yyyy-mm-dd. This is | |||
the same issue that plagues is_valid_accessdate() | |||
It is possible that a solution like that written for ht:Module:Citation/CS1/Date_validation date_name_xlate() could be applied to this problem | |||
]] | ]] | ||
Line 736: | Line 740: | ||
end | end | ||
for param_name, param_val in pairs(date_parameters_list) do | for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list | ||
if is_set(param_val) then -- if the parameter has a value | if is_set (param_val) then -- if the parameter has a value | ||
if not all and in_array (param_name, {'access-date', 'archive-date'}) then -- if access- or archive-date and format not xxx-all | if not all and in_array (param_name, {'access-date', 'archive-date'}) then -- if access- or archive-date and format not xxx-all | ||
param_val = ''; -- set to empty string so we don't process this date | param_val = ''; -- set to empty string so we don't process this date | ||
end | end | ||
for source, pattern in pairs(source_patterns) do | for source, pattern in pairs (source_patterns) do | ||
if param_val:match(pattern) then | if param_val:match (pattern) then | ||
if 'ymd' == source then | if 'ymd' == source then | ||
get_ymd_date_parts (param_val, source_date); -- get the date parts into the source_date table | get_ymd_date_parts (param_val, source_date); -- get the date parts into the source_date table | ||
Line 791: | Line 795: | ||
end | end | ||
end | end | ||
return result; -- so we know if | return result; -- so we know if any hyphens were replaced | ||
end | end | ||
--[[-------------------------< D A T E _ N A M E _ X L A T E >------------------------------------------------ | |||
Attempts to translate English month names to local-language month names using names supplied by MediaWiki's | |||
date parser function. This is simple name-for-name replacement and may not work for all languages. | |||
]] | |||
local function date_name_xlate (date_parameters_list) | |||
local xlate; | |||
local mode; -- long or short month names | |||
local modified = false; | |||
local date; | |||
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list | |||
if is_set(param_val) then -- if the parameter has a value | |||
date = param_val; | |||
for month in mw.ustring.gmatch (date, '%a+') do -- iterate through all dates in the date (single date or date range) | |||
if cfg.date_names.en.long[month] then | |||
mode = 'F'; -- English name is long so use long local name | |||
elseif cfg.date_names.en.short[month] then | |||
mode = 'M'; -- English name is short so use short local name | |||
else | |||
mode = nil; -- not an English month name; could be local language month name or an English season name | |||
end | |||
if mode then -- might be a season | |||
xlate = mw.getContentLanguage():formatDate(mode, '1' .. month); -- translate the month name to this local language | |||
date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation | |||
date_parameters_list[param_name] = date; -- save the translated date | |||
modified = true; | |||
end | |||
end | |||
end | |||
end | |||
return modified; | |||
end | |||
Line 801: | Line 845: | ||
]] | ]] | ||
local function set_selected_modules (utilities_page_ptr) | local function set_selected_modules (cfg_table_ptr, utilities_page_ptr) | ||
is_set = utilities_page_ptr.is_set; -- import functions from | is_set = utilities_page_ptr.is_set; -- import functions from selected Module:Citation/CS1/Utilities module | ||
in_array = utilities_page_ptr.in_array; | in_array = utilities_page_ptr.in_array; -- import functions from selected Module:Citation/CS1/Utilities module | ||
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration | |||
end | end | ||
Line 813: | Line 858: | ||
reformat_dates = reformat_dates, | reformat_dates = reformat_dates, | ||
date_hyphen_to_dash = date_hyphen_to_dash, | date_hyphen_to_dash = date_hyphen_to_dash, | ||
date_name_xlate = date_name_xlate, | |||
set_selected_modules = set_selected_modules | set_selected_modules = set_selected_modules | ||
} | } |