Module:Citation/CS1: திருத்தங்களுக்கு இடையிலான வேறுபாடு
உள்ளடக்கம் நீக்கப்பட்டது உள்ளடக்கம் சேர்க்கப்பட்டது
ISSN error detection; Expand uncategorized namespaces; Reg/Sub required msg tweak; Trap coauthors without authors; Hide error messages; |
Synch from sandbox; Migrate cite thesis and cite techreport; ISBN & ISSN tweaks; Deprecated parameter tracking; Add date validation; |
||
வரிசை 6:
-- Include translation message hooks, ID and error handling configuration settings.
local cfg = mw.loadData( 'Module:Citation/CS1/Configuration/sandbox' );
-- Contains a list of all recognized parameters
local whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist/sandbox' );
-- Whether variable is set or not
வரிசை 37:
end
return false;
end
-- Add this page to the deprecated parameter tracking category
function deprecated_parameter()
if true ~= Page_in_deprecated_cat then -- if we haven't been here before then set a
Page_in_deprecated_cat=true; -- sticky flag so that if there are more than one deprecated parameter the category is added only once
table.insert( z.error_categories, "Pages containing cite templates with deprecated parameters" ); -- add page to category
end
end
வரி 307 ⟶ 315:
]]
function issn(id)
local issn_copy = id; -- save a copy of unadulterated issn; use this version for display if issn does not validate
local handler = cfg.id_handlers['ISSN'];
local text;
local valid_issn = true;
id=id:gsub( "[%s-–]", "" ); -- strip spaces, hyphens, and ndashes from the issn
if 8 ~= id:len() or nil == id:match( "^%d*X?$" ) then -- validate the issn: 8 didgits long, containing only 0-9 or X in the last position
valid_issn=false; -- wrong length or improper character
else
end
if true == valid_issn then
id =
else
id = issn_copy; -- if not valid, use the show the invalid issn with error message
வரி 347 ⟶ 344:
end
-- returns a number according to the month in a date 1 for January, etc. If not a valid month, returns 0
function get_month_number (month)
local long_months = {['january']=1, ['february']=2, ['march']=3, ['april']=4, ['may']=5, ['june']=6, ['july']=7, ['august']=8, ['september']=9, ['october']=10, ['november']=11, ['december']=12};
local short_months = {['jan']=1, ['feb']=2, ['mar']=3, ['apr']=4, ['may']=5, ['jun']=6, ['jul']=7, ['aug']=8, ['sep']=9, ['oct']=10, ['nov']=11, ['dec']=12};
local temp;
temp=long_months[month:lower()];
if temp then return temp; end -- if month is the long-form name
temp=short_months[month:lower()];
if temp then return temp; end -- if month is the short-form name
return 0; -- misspelled or not a month name
end
-- returns true if date has one of the five seasons. Else false.
function is_valid_season (season)
if inArray( season, {'winter', 'spring', 'summer', 'fall', 'autumn'} ) then
return true;
end
return false;
end
--[[
Returns true if day is less than or equal to the number of days in month; else returns false.
Assumes Julian calendar prior to year 1582 and Gregorian calendar thereafter. Accounts for Julian calendar leap years before 1582 and Gregorian leap years after 1582.
Where the two calendars overlap (1582 to approximately 1923) dates are assumed to be Gregorian.
]]
function is_valid_date (year, month, day)
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local month_length;
if (2==month) then -- if February
month_length = 28; -- then 28 days unless
if 1582 > tonumber(year) then -- Julian calendar
if 0==(year%4) then
month_length = 29;
end
else -- Gregorian calendar
if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- date specifies a leap year
month_length = 29; -- if leap year then 29 days in February
end
end
else
month_length=days_in_month[month];
end
if tonumber (day) > month_length then
return false;
end
return true;
end
--Check a pair of months or seasons to see if both are valid members of a month or season pair.
function is_valid_month_season_range(range_start, range_end)
if 0 == get_month_number (range_start:lower()) then -- is this a month range?
if true == is_valid_season (range_start:lower()) then -- not a month range, is this a season range?
return is_valid_season (range_end:lower()); -- range_start is season; return true if range_end also a season; else false
end
return false; -- range_start is not a month or a season
end
if 0 == get_month_number (range_end:lower()) then -- range_start is a month; is range_end also a month?
return false; -- not a month range
end
return true;
end
--[[
Check date format to see that it is one of the formats approved by MOS:DATE: MMMM D, YYYY; D MMMM YYYY; MMMM YYYY; YYYY-MM-DD; YYYY.
Additionally, check the date to see that it is a real date: no 31 in 30-day months; no 29 February when not a leap year. Months, both long-form and three
character abbreviations, and seasons must be spelled correctly.
If the date fails the fomat tests, this function returns false but does not return values for anchor_year and COinS_date. When this happens, the date parameter is
used in the COinS metadata and the CITEREF identifier gets its year from the year parameter if present.
Inputs:
date_string - date string from date-holding parameters (date, year, accessdate, embargo, archivedate, etc)
Returns:
false if date string is not a real date; else
true, anchor_year, COinS_date
anchor_year can be used in CITEREF anchors
COinS_date is date_string without anchor_year disambiguators if any
]]
function check_date (date_string)
local year;
local month;
local day;
local anchor_year;
local coins_date;
if date_string:match("^%d%d%d%d%-%d%d%-%d%d$") then -- Year-initial numerical year month day format
coins_date = date_string:match("%d%d%d%d%-%d%d%-%d%d");
year, month, day=string.match(date_string, "(%d%d%d%d)%-(%d%d)%-(%d%d)");
anchor_year = year;
month=tonumber(month);
if 12 < month or 1 > month then return false; end
elseif date_string:match("^%a+%s*%d%d*%s*,%s*%d%d%d%d%a?$") then -- month-initial: month day, year
coins_date = date_string:match("%a+%s*%d%d*%s*,%s*%d%d%d%d");
month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d*)%s*,%s*((%d%d%d%d)%a?)");
month = get_month_number (month:lower());
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
elseif date_string:match("^%d%d*%s*%a+%s*%d%d%d%d%a?$") then -- date-initial: day month year
coins_date = date_string:match("%d%d*%s*%a+%s*%d%d%d%d");
day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)");
month = get_month_number (month:lower());
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
elseif mw.ustring.match (date_string, "^%a+%s*[%s%-/–]%s*%a+%s*%d%d%d%d%a?$") then -- month/season range year
local month2
coins_date = mw.ustring.match (date_string, "%a+%s*[%s%-/–]%s*%a+%s*%d%d%d%d");
coins_date= mw.ustring.gsub( coins_date, "–", "-" ); -- replace ndash with hyphen
month, month2, anchor_year, year=mw.ustring.match (date_string, "(%a+)%s*[%s%-/–]%s*(%a+)%s*((%d%d%d%d)%a?)");
day=0; -- mark day as not used
if false == is_valid_month_season_range(month, month2) then
return false;
end
elseif date_string:match("^%a+%s*%d%d%d%d%a?$") then -- month/season year
coins_date = date_string:match("%a+%s*%d%d%d%d");
month, anchor_year, year=string.match(date_string, "(%a+)%s*((%d%d%d%d)%a?)");
day=0; -- mark day as not used
local season=month; -- copy
month = get_month_number (month:lower());
if month == 0 then -- if month text isn't one of the twelve months, might be a season
if false == is_valid_season (season:lower()) then
return false; -- return false not a month or one of the five seasons
end
end
elseif date_string:match("^%d%d%d%d?%a?$") then -- year; here accept either YYY or YYYY
coins_date = date_string:match("^%d%d%d%d?");
anchor_year, year=string.match(date_string, "((%d%d%d%d?)%a?)");
month, day = 0, 0; -- mark day and month as not used
else
return false; -- date format not one of the MOS:DATE approved formats
end
if 0~=month and 0~=day then -- check year month day dates for validity
if false==is_valid_date(year,month,day) then
return false; -- date string is not a real date return false; unset anchor_year and coins_date
end
end
return true, anchor_year, coins_date; -- format is good and date string represents a real date
end
--[[
Cycle the date-holding parameters in passed table date_parameters_list through check_date() to check compliance with MOS:DATE. For all valid dates, check_date() returns
true and values for anchor_year (used in CITEREF identifiers) and COinS_date (used in the COinS metadata). The |date= parameter test is unique. This function only
accepts anchor_year and COinS_date results from the |date= parameter test and |date= is the only date-holding parameter that is allowed to contain the no-date keywords
"n.d." or "nd" (without quotes).
Unlike most error messages created in this module, only one error message is created by this function. Because all of the date holding parameters are processed serially,
a single error message is created as the dates are tested.
]]
function dates(date_parameters_list)
local anchor_year; -- will return as nil if the date being tested is not |date=
local COinS_date; -- will return as nil if the date being tested is not |date=
local error_message ="";
local good_date=false;
for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set(v) then -- if the parameter has a value
if v:match("^c%.%s%d%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
if 'date'==k then
good_date, anchor_year, COinS_date = true, v:match("((c%.%s%d%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
elseif 'year'==k then
good_date = true;
end
elseif 'year'==k then -- if the parameter is |year= (but not c. year)
if v:match("^%d%d%d%d?%a?$") then -- year with or without CITEREF disambiguator
good_date = true;
end
elseif 'date'==k then -- if the parameter is |date=
if v:match("n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; -- no error when date parameter is set to no date
elseif v:match("nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; -- no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v); -- go test the date
end
else -- any other date-holding parameter
good_date = check_date (v); -- go test the date
end
if false==good_date then -- assemble one error message so we don't add the tracking category multiple times
if is_set(error_message) then -- once we've added the first portion of the error message ...
error_message=error_message .. ", "; -- ... add a comma space separator
end
error_message=error_message .. "|" .. k .. "="; -- add the failed parameter
end
end
end
if is_set(error_message) then
table.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } ); -- add this error message
end
return anchor_year, COinS_date; -- and done
end
--[[
வரி 365 ⟶ 563:
function cleanisbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
end
--[[
ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. If the number is valid the result will be 0.
Before calling this function, issbn/issn must be checked for length and stripped of dashes, spaces and other non-isxn characters.
]]
function is_valid_isxn (isxn_str, len)
local temp = 0;
isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
len = len+1; -- adjust to be a loop counter
for i, v in ipairs( isxn_str ) do -- loop through all of the byte an calculate the checksum
if v == string.byte( "X" ) then -- if checkdigit is X
temp = temp + 10*( len - i ); -- it represents 10 decimal
else
temp = temp + tonumber( string.char(v) )*(len-i);
end
end
return temp % 11 == 0; -- returns true if calculation result is zero
end
வரி 376 ⟶ 592:
end
if len == 10 then
if isbn_str:match( "^%d*X?$" ) == nil then return false; end
return
else
local temp = 0;
if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end -- isbn13 begins with 978 or 979
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
வரி 520 ⟶ 728:
Returns empty string if the argument can not be interpreted
as a year.
BUG: If editors set |date=n.d or |date=n.da then selectyear() returns the current year for use in CITEREF. These "dates" are caught by dates().
]]
function selectyear( str )
if good then return result; end
end
end
-- Attempts to convert names to initials.
வரி 898 ⟶ 1,085:
local TransChapter = A['TransChapter'];
local TitleType = A['TitleType'];
local Degree = A['Degree'];
local Docket = A['Docket'];
local ArchiveURL = A['ArchiveURL'];
local URL = A['URL']
வரி 967 ⟶ 1,156:
local DoiBroken = A['DoiBroken'];
-- Special case for cite techreport.
local ID = A['ID'];
if (config.CitationClass == "techreport") then -- special case for cite techreport
if is_set(Issue) then -- cite techreport uses 'number', which everything else aliases to 'issue'
if not is_set(ID) then -- can we use ID for the "number"?
ID = Issue; -- yes, use it
Issue = ""; -- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata
else -- can't use ID so emit error message
ID = ID .. " " .. seterror('redundant_parameters', '<code>|id=</code> and <code>|number=</code>');
end
end
end
local ASINTLD = A['ASINTLD'];
local IgnoreISBN = A['IgnoreISBN'];
வரி 997 ⟶ 1,199:
end
local anchor_year; -- used in the CITEREF identifier
local COinS_date; -- used in the COinS metadata
-- Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates.
-- TODO: 2013-10-27: AirDate is nil when dates() is called because it hasn't been set yet. Move the call to dates() or set AirDate earlier.
anchor_year, COinS_date = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
if not is_set(Year) then -- prevent Year from being set from DateIn TODO: eliminate the need for this?
if is_set(anchor_year) then
Year = anchor_year;
end
end
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.
-- Account for the oddity that is {{cite conference}}, before generation of COinS data.
வரி 1,044 ⟶ 1,260:
['Title'] = Title,
['PublicationPlace'] = PublicationPlace,
['Date'] = first_set(COinS_date, Date, Year, PublicationDate),
['Series'] = Series,
['Volume'] = Volume,
வரி 1,092 ⟶ 1,308:
control.lastauthoramp = nil;
control.maximum = #a + 1;
deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
end
வரி 1,099 ⟶ 1,316:
if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
table.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } ); -- emit error message
deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
end
வரி 1,146 ⟶ 1,364:
if is_set(Date) then
local Month = A['Month'];
if is_set(Month) then
deprecated_parameter(); -- |month= (and also |day=) is deprecated; add this page to deprecated parameter category
Date = Month .. " " .. Date;
local Day = A['Day']
வரி 1,394 ⟶ 1,613:
end
-- handle type parameter for those CS1 citations that have default values
if "pressrelease" == config.CitationClass then -- if this citation is cite press release
if not is_set (TitleType) then
TitleType = "Press release"; -- if type not specified, display the press release annotation
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
end
elseif "techreport" == config.CitationClass then -- if this citation is cite techreport
if not is_set (TitleType) then
TitleType = "Technical report"; -- if type not specified, display the techreport annotation
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed; |number=, if set, will be displayed
end
elseif "thesis" == config.CitationClass then -- if this citation is cite thesis
if not is_set (TitleType) then
if is_set(Degree) then -- if type not specified, display one of the thesis annotations
TitleType = Degree .. " thesis"; -- if a degree (masters, PhD, ...) is specified include it in the display
else
TitleType = "Thesis"; -- otherwise display the simple thesis annotation
end
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
end
end
if is_set(TitleType) then -- if type parameter is specified
TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
end
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
Edition = is_set(Edition) and (" " .. wrap( 'edition', Edition )) or "";
Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";
வரி 1,434 ⟶ 1,684:
if is_set(ID) then ID = sepc .." ".. ID; end
if "thesis" == config.CitationClass and is_set(Docket) then
ID = sepc .." Docket ".. Docket .. ID;
end
ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} );
வரி 1,680 ⟶ 1,934:
end
end
id = anchorid(names)
end
| |||