"মডিউল:উদ্ধৃতি/খেলাঘর" পাতাটির দুইটি সংশোধিত সংস্করণের মধ্যে পার্থক্য

সংশোধন
(নতুন পৃষ্ঠা: local cs1 ={}; --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- ]] local dates, year_date_check,...)
ট্যাগ: মোবাইল সম্পাদনা মোবাইল ওয়েব সম্পাদনা উচ্চতর মোবাইল সম্পাদনা
 
(সংশোধন)
 
 
local cs1 ={};
 
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
 
local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist
 
--[[--------------------------< P A G E S C O P E V A R I A B L E S >--------------------------------------
 
--[[--------------------------< P A G E S C O P E V A R I A B L E S >--------------------------------------
 
delare variables here that have page-wide scope that are not brought in from other modules; thatare created here
 
local Frame; -- holds the module's frame table
 
 
--[[--------------------------< F I R S T _ S E T >------------------------------------------------------------
 
Locates and returns the first set value in a table of values where the order established in the table,
left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set.
 
This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs
version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate
the for-loop before it reached the actual end of the list.
 
end
end
 
 
--[[--------------------------< A D D _ P R O P _ C A T >--------------------------------------------------------
end
end
 
 
--[[--------------------------< A D D _ V A N C _ E R R O R >----------------------------------------------------
end
end
 
 
--[[--------------------------< I S _ S C H E M E >------------------------------------------------------------
 
does this thing that purports to be a uri scheme seem to be a valid scheme? The scheme is checked to see if it
is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says:
Scheme names consist of a sequence of characters beginning with a
return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern
end
 
 
--[=[-------------------------< I S _ D O M A I N _ N A M E >--------------------------------------------------
list of tlds: https://www.iana.org/domains/root/db
 
rfc952 (modified by rfc 1123) requires the first and last character of a hostname to be a letter or a digit. Between
the first and last characters the name may use letters, digits, and the hyphen.
 
Also allowed are IPv4 addresses. IPv6 not supported
 
domain is expected to be stripped of any path so that the last character in the last character of the tld. tld
is two or more alpha characters. Any preceding '//' (from splitting a url with a scheme) will be stripped
here. Perhaps not necessary but retained incase it is necessary for IPv4 dot decimal.
 
There are several tests:
return false; -- if not set, abandon
end
 
domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once
 
if not domain:match ('^[%a%d]') then -- first character must be letter or digit
return false;
end
end
 
 
--[[--------------------------< I S _ U R L >------------------------------------------------------------------
returns true if the scheme and domain parts of a url appear to be a valid url; else false.
 
This function is the last step in the validation process. This function is separate because there are cases that
are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external
wikilinks.
end
end
 
 
--[[--------------------------< S P L I T _ U R L >------------------------------------------------------------
If protocol relative url, return nil scheme and domain else return nil for both scheme and domain.
 
When not protocol relative, get scheme, authority indicator, and domain. If there is an authority indicator (one
or more '/' characters immediately following the scheme's colon), make sure that there are only 2.
 
local function split_url (url_str)
local scheme, authority, domain;
 
url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//')
 
domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present
end
 
return scheme, domain;
end
 
 
--[[--------------------------< L I N K _ P A R A M _ O K >---------------------------------------------------
end
 
scheme, domain = split_url (value); -- get scheme or nil and domain or nil from url;
return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid url
end
 
 
--[[--------------------------< L I N K _ T I T L E _ O K >---------------------------------------------------
Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value.
 
|<title>= may be wikilinked but not when |<param>-link= has a value. This function emits an error message when
that condition exists
 
end
end
 
 
--[[--------------------------< C H E C K _ U R L >------------------------------------------------------------
Determines whether a URL string appears to be valid.
 
First we test for space characters. If any are found, return false. Then split the url into scheme and domain
portions, or for protocol relative (//example.com) urls, just the domain. Use is_url() to validate the two
portions of the url. If both are valid, or for protocol relative if domain is valid, return true, else false.
 
Because it is different from a standard url, and because this module used external_link() to make external links
that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name
is at https://tools.ietf.org/html/rfc5536#section-3.1.4
 
 
scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from url;
 
if 'news:' == scheme then -- special case for newsgroups
return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$');
end
 
return is_url (scheme, domain); -- return true if value appears to be a valid url
end
 
 
--[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >----------------------------
 
Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first
non-space characters following the opening bracket appear to be a url. The test will also find external wikilinks
that use protocol relative urls. Also finds bare urls.
 
The frontier pattern prevents a match on interwiki links which are similar to scheme:path urls. The tests that
find bracketed urls are required because the parameters that call this test (currently |title=, |chapter=, |work=,
and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]]
return is_url (scheme, domain); -- return true if value appears to be a valid url
end
 
 
--[[-------------------------< C H E C K _ F O R _ U R L >-----------------------------------------------------
 
loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message.
 
]]
for k, v in pairs (parameter_list) do -- for each parameter in the list
if is_parameter_ext_wikilink (v) then -- look at the value; if there is a url add an error message
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 .. "&#124;" .. k .. "="; -- add the failed parameter
end
end
 
 
--[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------
 
local function safe_for_url( str )
if str:match( "%[%[.-%]%]" ) ~= nil then
table.insert( z.message_tail, { set_error( 'wikilink_in_url', {}, true ) } );
end
 
return str:gsub( '[%[%]\n]', {
['['] = '&#91;',
[']'] = '&#93;',
['\n'] = ' ' } );
end
 
 
--[[--------------------------< E X T E R N A L _ L I N K >----------------------------------------------------
local path;
local base_url;
 
if not is_set( label ) then
label = URL;
else
error( cfg.messages["bare_url_no_origin"] );
end
end
if not check_url( URL ) then
error_str = set_error( 'bad_url', {wrap_style ('parameter', source)}, false, " " ) .. error_str;
end
 
domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the url into scheme plus domain and path
if path then -- if there is a path portion
URL=domain..path; -- and reassemble
end
 
if is_set (access) then -- access level (subscription, registration, limited)
label = safe_for_url (label); -- replace square brackets and newlines
base_url = table.concat({ "[", URL, " ", safe_for_url( label ), "]" }); -- no signal markup
end
 
return table.concat({ base_url, error_str });
end
 
 
--[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >--------------------------------------
 
Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the
offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated
parameters in the citation.
 
end
end
 
 
--[=[-------------------------< K E R N _ Q U O T E S >--------------------------------------------------------
 
Replaces unicode quotemarks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter
quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks.
 
Call this function for chapter titles, for website titles, etc; not for book titles.
 
wl_type, label, link = is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]]
 
if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks
if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks
label = substitute (cfg.presentation['kern-left'], {cap, cap2});
end
 
cap, cap2 = mw.ustring.match (label, "^(.+[^\'])([\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup)
if is_set (cap) then
label = substitute (cfg.presentation['kern-right'], {cap, cap2});
end
 
if 2 == wl_type then
str = make_wikilink (link, label); -- reassemble the wikilink
return str;
end
 
 
--[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >----------------------------------------
 
|script-title= holds title parameters that are not written in Latin based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should
not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped
in italic markup.
 
Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate rtl languages from the English left to right.
 
|script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO639-1 language code and a colon:
|script-title=ja:*** *** (where * represents a Japanese character)
Spaces between the two-character code and the colon and the colon and the first script character are allowed:
Spaces preceding the prefix are allowed: |script-title = ja:*** ***
 
The prefix is checked for validity. If it is a valid ISO639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can
know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute
is not added. At this time there is no error message for this condition.
 
Supports |script-title= and |script-chapter=
return script_value;
end
 
 
--[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------
 
Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been
wrapped in <bdi> tags.
]]
return title;
end
 
 
--[[--------------------------< W R A P _ M S G >--------------------------------------------------------------
 
Applies additional message text to various parameter values. Supplied string is wrapped using a message_list
configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken
from citation_config.messages - the reason this function is similar to but separate from wrap_style().
 
]]
if true == lower then
local msg;
msg = cfg.messages[key]:lower(); -- set the message to lower case before
return substitute( msg, str ); -- including template text
else
return substitute( cfg.messages[key], str );
end
end
 
 
--[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------------------------------
local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access)
local chapter_error = '';
 
if not is_set (chapter) then
chapter = ''; -- to be safe for concatenation
transchapter = wrap_style ('trans-quoted-title', transchapter);
if is_set (chapter) then
chapter = chapter .. ' ' .. transchapter;
else -- here when transchapter without chapter or script-chapter
chapter = transchapter; --
chapter_error = ' ' .. set_error ('trans_missing_title', {'chapter'});
end
return chapter .. chapter_error;
end
 
 
--[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >----------------------------------------
 
This function searches a parameter's value for nonprintable or invisible characters. The search stops at the
first match.
 
This function will detect the visible replacement character when it is part of the wikisource.
 
Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref)
and identifies them with a slightly different error message. See also coins_cleanup().
 
Detects but ignores the character pattern that results from the transclusion of {{'}} templates.
local i=1;
local stripmarker, apostrophe;
 
capture = string.match (v, '[%w%p ]*'); -- Test for values that are simple ASCII text and bypass other tests if true
if capture == v then -- if same there are no unicode characters
local pattern=cfg.invisible_chars[i][2] -- the pattern used to find it
position, dummy, capture = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern
 
if position and (char == 'zero width joiner') then -- if we found a zero width joiner character
if mw.ustring.find (v, cfg.indic_script) then -- its ok if one of the indic scripts
end
end
 
if position then
if 'nowiki' == capture or 'math' == capture then -- nowiki, math stripmarker (not an error condition)
end
end
 
 
--[[--------------------------< A R G U M E N T _ W R A P P E R >----------------------------------------------
 
Argument wrapper. This function provides support for argument mapping defined in the configuration file so that
multiple names can be transparently aliased to single internal variable.
 
local function argument_wrapper( args )
local origin = {};
 
return setmetatable({
ORIGIN = function( self, k )
return nil;
end
 
local args, list, v = args, cfg.aliases[k];
 
if type( list ) == 'table' then
v, origin[k] = select_one( args, list, 'redundant_parameters' );
error( cfg.messages['unknown_argument_map'] );
end
 
-- Empty strings, not nil;
if v == nil then
origin[k] = '';
end
 
tbl = rawset( tbl, k, v );
return v;
});
end
 
 
--[[--------------------------< V A L I D A T E >--------------------------------------------------------------
 
Parameters in the whitelist can have three values:
true - active, supported parameters
false - deprecated, supported parameters
nil - unsupported parameters
 
]]
 
local name = tostring( name );
local state;
 
if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates
state = whitelist.limited_basic_arguments[ name ];
return false; -- not supported because not found or name is set to nil
end -- end limited parameter-set templates
 
state = whitelist.basic_arguments[ name ]; -- all other templates; all normal parameters allowed
 
if true == state then return true; end -- valid actively supported parameter
if false == state then
return true;
end
 
return false; -- not supported because not found or name is set to nil
end
 
 
--[[--------------------------< N O W R A P _ D A T E >--------------------------------------------------------
 
When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is
MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY
 
if date:match("^%d%d%d%d%-%d%d%-%d%d$") then
date = substitute (cfg.presentation['nowrap1'], date);
 
elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then
cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$");
date = substitute (cfg.presentation['nowrap2'], {cap, cap2});
end
 
return date;
end
 
 
--[[--------------------------< S E T _ T I T L E T Y P E >----------------------------------------------------
return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation
end
 
 
--[[--------------------------< H Y P H E N _ T O _ D A S H >--------------------------------------------------
if not is_set(str) or str:match( "[%[%]{}<>]" ) ~= nil then
return str;
end
return str:gsub( '-', '–' );
end
 
 
--[[--------------------------< S A F E _ J O I N >------------------------------------------------------------
for _, value in ipairs( tbl ) do
if value == nil then value = ''; end
 
if str == '' then -- if output string is empty
str = value; -- assign value to it (first time through the loop)
elseif value ~= '' then
if value:sub(1,1) == '<' then -- Special case of values enclosed in spans and other markup.
comp = value:gsub( "%b<>", "" ); -- remove html markup (<span>string</span> -> string)
else
comp = value;
-- typically duplicate_char is sepc
if f.sub(comp, 1,1) == duplicate_char then -- is first character same as duplicate_char? why test first character?
-- Because individual string segments often (always?) begin with terminal punct for the
-- preceding segment: 'First element' .. 'sepc next element' .. etc?
trim = false;
end_chr = f.sub(str, -1,-1); -- get the last character of the output string
str = f.sub(str, 1,-2); -- remove it
elseif end_chr == "'" then -- if it might be wikimarkup
if f.sub(str, -3,-1) == duplicate_char .. "''" then -- if last three chars of str are sepc''
str = f.sub(str, 1, -4) .. "''"; -- remove them and add back ''
elseif f.sub(str, -5,-1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]''
trim = true; -- why? why do this and next differently from previous?
elseif f.sub(str, -4,-1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]''
trim = true; -- same question
end
elseif end_chr == "]" then -- if it might be wikimarkup
if f.sub(str, -3,-1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink
trim = true;
elseif f.sub(str, -3,-1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link
trim = true;
elseif f.sub(str, -2,-1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link
trim = true;
elseif f.sub(str, -4,-1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title.
local dup2 = duplicate_char;
if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it
 
value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows html markup
else
return str;
end
 
 
--[[--------------------------< I S _ S U F F I X >------------------------------------------------------------
 
returns true is suffix is properly formed Jr, Sr, or ordinal in the range 2–9. Puncutation not allowed.
 
]]
return false;
end
 
 
--[[--------------------------< I S _ G O O D _ V A N C _ N A M E >--------------------------------------------
 
For Vancouver Style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name
uses characters that contain diacritical marks, those characters are to converted to the corresponding Latin character.
When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters.
return true;
end
 
 
--[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------
 
Attempts to convert names to initials in support of |name-list-format=vanc.
 
Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/.
 
Vancouver style requires family rank designations (Jr, II, III, etc) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/.
This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials.
 
end
end -- if here then name has 3 or more uppercase letters so treat them as a word
 
 
local initials, names = {}, {}; -- tables to hold name parts and initials
i = i+1; -- bump the counter
end
 
return table.concat(initials) -- Vancouver format does not include spaces.
end
 
--[[--------------------------< L I S T _ P E O P L E >-------------------------------------------------------
 
Formats a list of people (e.g. authors / editors)
--[[--------------------------< L I S T _ P E O P L E >-------------------------------------------------------
 
Formats a list of people (e.g. authors / editors)
 
]]
namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space>
end
 
if sep:sub(-1,-1) ~= " " then sep = sep .. " " end
if is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for authors
 
for i,person in ipairs(people) do
if is_set(person.last) then
local n = tonumber(mask)
if (n ~= nil) then
one = string.rep("&mdash;",n)
else
one = mask;
 
local count = #text / 2; -- (number of names + number of separators) divided by 2
if count > 0 then
if count > 1 and is_set(lastauthoramp) and not etal then
text[#text-2] = " & "; -- replace last separator with ampersand text
text[#text] = nil; -- erase the last separator
end
 
local result = table.concat(text) -- construct list
if etal and is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list
result = result .. sep .. ' ' .. cfg.messages['et al']; -- we've go a last-first list and etal so add et al.
end
 
return result, count
end
 
 
--[[--------------------------< A N C H O R _ I D >------------------------------------------------------------
 
Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string.
 
namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year.
 
]]
local names={}; -- a table for the one to four names and year
for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names
names[i] = v.last
if i == 4 then break end -- if four then done
end
end
end
 
 
--[[--------------------------< N A M E _ H A S _ E T A L >----------------------------------------------------
 
Evaluates the content of author and editor name parameters for variations on the theme of et al. If found,
the et al. is removed, a flag is set to true and the function returns the modified name and the flag.
 
local etal_pattern = "[;,]? *[\"']*%f[%a][Ee][Tt] *[Aa][Ll][%.\"']*$" -- variations on the 'et al' theme
local others_pattern = "[;,]? *%f[%a]and [Oo]thers"; -- and alternate to et al.
 
if name:match (etal_pattern) then -- variants on et al.
name = name:gsub (etal_pattern, ''); -- if found, remove
end
end
return name, etal; --
end
 
 
--[[--------------------------< N A M E _ H A S _ E D _ M A R K U P >------------------------------------------
 
Evaluates the content of author and editor parameters for extranious editor annotations: ed, ed., eds, (Ed.), etc.
These annotation do not belong in author parameters and are redundant in editor parameters. If found, the function
adds the editor markup maintenance category.
 
'%f[%(%[][%(%[]%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?%s*[%)%]]?$', -- (editor) or (editors): leading '(', case insensitive, optional '.' and/or ')'
'[,%.%s]%f[Ee][Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?$', -- editor or editors: without '('or ')'; case insensitive
 
-- these patterns match annotations at beginning of name
'^eds?[%.,;]', -- ed. or eds.: lower case only, optional 's', requires '.'
return name; -- and done
end
 
 
--[[--------------------------< N A M E _ H A S _ M U L T _ N A M E S >----------------------------------------
 
Evaluates the content of author and editor (surnames only) parameters for multiple names. Multiple names are
indicated if there is more than one comma and or semicolon. If found, the function adds the multiple name
(author or editor) maintenance category.
 
if is_set (name) then
_, count = name:gsub ('[;,]', ''); -- count the number of separator-like characters
 
if 1 < count then -- param could be |author= or |editor= so one separator character is acceptable
add_maint_cat ('mult_names', cfg.special_case_translation [list_name]); -- more than one separator indicates multiple names so add a maint cat for this template
return name; -- and done
end
 
 
--[[--------------------------< N A M E _ C H E C K S >--------------------------------------------------------
local function name_checks (last, first, list_name)
if is_set (last) then
if last:match ('^%(%(.*%)%)$') then -- if wrapped in doubled parentheses, accept as written
last = last:match ('^%(%((.*)%)%)$'); -- strip parens
else
end
if is_set (first) then
if first:match ('^%(%(.*%)%)$') then -- if wrapped in doubled parentheses, accept as written
first = first:match ('^%(%((.*)%)%)$'); -- strip parens
else
return last, first; -- done
end
 
 
--[[--------------------------< E X T R A C T _ N A M E S >----------------------------------------------------
find |last4= and |last5= then the search is done.
 
This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3=
are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=.
 
When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned
that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the
template's metadata. When this occurs, the page is added to a maintenance category.
 
]]
first, etal = name_has_etal (first, etal, false); -- find and remove variations on et al.
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks
 
if first and not last then -- if there is a firstn without a matching lastn
table.insert( z.message_tail, { set_error( 'first_missing_last', {err_msg_list_name, i}, true ) } ); -- add this error message
i = i + 1; -- point to next args location
end
 
return names, etal; -- all done, return our list of names
end
 
 
--[[--------------------------< G E T _ I S O 6 3 9 _ C O D E >------------------------------------------------
Validates language names provided in |language= parameter if not an ISO639-1 or 639-2 code.
 
Returns the language name and associated two- or three-character code. Because case of the source may be incorrect
or different from the case that WikiMedia uses, the name comparisons are done in lower case and when a match is
found, the Wikimedia version (assumed to be correct) is returned along with the code. When there is no match, we
return the original language name string.
 
mw.language.fetchLanguageNames(<local wiki language>, 'all') returns a list of languages that in some cases may include
extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support
code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a 'language' codes per se, rather they
are used as sub-domain names: cbk-zam.wikipedia.org. These names can be found (for the time being) at
https://phabricator.wikimedia.org/diffusion/ECLD/browse/master/LocalNames/LocalNamesEn.php
 
Names but that are included in the list will be found if that name is provided in the |language= parameter. For example,
if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found
and the associated code is not two or three characters, this function returns only the Wikimedia language name.
 
-- ('all' is required for North Ndebele, South Ndebele, and Ojibwa)
local langlc = mw.ustring.lower(lang); -- lower case version for comparisons
 
for code, name in pairs(languages) do -- scan the list to see if we can find our language
if langlc == mw.ustring.lower(name) then
return lang; -- not valid language; return language in original case and nil for the code
end
 
 
--[[--------------------------< L A N G U A G E _ P A R A M E T E R >------------------------------------------
 
Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki,
use the returned name; if not, then use the value that was provided with the language parameter.
 
When |language= contains a recognized language (either code or name), the page is assigned to the category for
that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned
to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources.
 
Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character
equivalents of two-character codes: code 'ar' is recognized bit code 'ara' is not.
 
end
end
 
if is_set (name) then -- if |language= specified a valid code
code = lang:lower(); -- save it
name, code = get_iso639_code (lang, this_wiki_code); -- attempt to get code from name (assign name here so that we are sure of proper capitalization)
end
 
if is_set (code) then -- only 2- or 3-character codes
name = cfg.lang_code_remap[code] or name; -- override wikimedia when they misuse language codes/names
add_maint_cat ('unknown_lang'); -- add maint category if not already added
end
 
table.insert (language_list, name);
name = ''; -- so we can reuse it
end
 
code = #language_list -- reuse code as number of languages in the list
if 2 >= code then
return ''; -- if one language and that language is this wiki's return an empty string (no annotation)
end
return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)'
--[[ TODO: should only return blank or name rather than full list
so we can clean up the bunched parenthetical elements Language, Type, Format
]]
end
 
 
--[[--------------------------< S E T _ C S 1 _ S T Y L E >----------------------------------------------------
return cfg.presentation['sep_cs1'], ps; -- element separator
end
 
 
--[[--------------------------< S E T _ C S 2 _ S T Y L E >----------------------------------------------------
Set style settings for CS2 citation templates. Returns separator, postscript, ref settings
At en.wiki, for cs2:
ps gets: '' (empty string - no terminal punctuation)
sep gets: ','
 
return cfg.presentation['sep_cs2'], ps, ref; -- element separator
end
 
 
--[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >----------------------
return sep, ps, ref -- return them all
end
 
 
--[[--------------------------< S E T _ S T Y L E >------------------------------------------------------------
 
Establish basic style settings to be used when rendering the citation. Uses |mode= if set and valid or uses
config.CitationClass from the template's #invoke: to establish style.
 
ps = ''; -- set to empty string
end
 
return sep, ps, ref
end
 
 
--[=[-------------------------< I S _ P D F >------------------------------------------------------------------
return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]');
end
 
 
--[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------
 
Applies css style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does
not have a matching url parameter. If the format parameter is not set and the url contains a file extension that
is recognized as a pdf document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with
the appropriate styling.
return format;
end
 
 
--[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------
 
When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the
number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of
the names in the name list followed by 'et al.'
 
end
end
 
return max, etal;
end
 
 
--[[--------------------------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >------------------------------
 
Adds page to Category:CS1 maint: extra text if |page= or |pages= has what appears to be some form of p. or pp.
abbreviation in the first characters of the parameter content.
 
local bad_pattern = '^[Pp]?[Pp]%.?[ %d]';
 
if not page:match (good_pattern) and (page:match (bad_pattern) or page:match ('^[Pp]ages?')) then
add_maint_cat ('extra_text');
end
end
 
 
--[=[-------------------------< G E T _ V _ N A M E _ T A B L E >----------------------------------------------
 
split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled
parentheses to also have commas; in the old version of the code, the doubled parnetheses were included in the
rendered citation and in the metadata. Individual author names may be wikilinked
 
|vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.))
local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas
local wl_type, label, link; -- wl_type not used here; just a place holder
 
local i = 1;
 
while name_table[i] do
if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parens
end
i = i+1;
end
return output_table;
end
 
 
--[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >--------------------------------
 
This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and
|xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does.
 
Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names
corporate = true; -- flag used in list_people()
elseif string.find(v_name, "%s") then
if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters;
add_vanc_error ('punctuation');
end
else
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor
last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this?
end
 
if is_set (first) then
if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else
return names, etal; -- all done, return our list of names
end
 
 
--[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------
select one of |editors=, |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list.
 
Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest and
similarly, |editorn= (and aliases) highest and |editors= lowest
 
When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second
test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better
way to do this, I just haven't discovered what that way is.
 
local function select_author_editor_source (vxxxxors, xxxxors, args, list_name)
local lastfirst = false;
if select_one( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice incase we have a |first1= without a |last1=; this ...
select_one( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors=
select_one( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or
select_one( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then
if is_set (vxxxxors) then return 2 end;
if is_set (xxxxors) then return 3 end;
return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last
end
 
 
--[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------
 
This function is used to validate a parameter's assigned value for those parameters that have only a limited number
of allowable values (yes, y, true, no, etc). When the parameter value has not been assigned a value (missing or empty
in the source template) the function returns true. If the parameter value is one of the list of allowed values returns
true; else, emits an error message and returns false.
 
end
end
 
 
--[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >----------------------------------------
This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space
when the last character is not a sepc character or when the last three characters are not sepc followed by two
closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a
single space character.
 
end
end
 
 
--[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------
 
]]
 
local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower)
if not is_set (volume) and not is_set (issue) then
return '';
end
 
if 'magazine' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then
if is_set (volume) and is_set (issue) then
 
local vol = '';
 
if is_set (volume) then
if (4 < mw.ustring.len(volume)) then
return vol;
end
 
 
--[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >-----------------------------------------
 
local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin);
 
if is_set (page) then
if is_journal then
end
end
 
return '', '', '', ''; -- return empty strings
end
 
 
--[=[-------------------------< A R C H I V E _ U R L _ C H E C K >--------------------------------------------
 
Check archive.org urls to make sure they at least look like they are pointing at valid archives and not to the
save snapshot url or to calendar pages. When the archive url is 'https://web.archive.org/save/' (or http://...)
archive.org saves a snapshot of the target page in the url. That is something that Wikipedia should not allow
unwitting readers to do.
 
When the archive.org url does not have a complete timestamp, archive.org chooses a snapshot according to its own
algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results.
 
This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and
//web.archive.org/web/<timestamp>... -- the new form
 
The old form does not support or map to the new form when it contains a display flag. There are four identified flags
('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore)
we don't check for these specific flags but we do check the form.
 
This function supports a preview mode. When the article is rendered in preview mode, this funct may return a modified
archive url:
for save command errors, return undated wildcard (/*/)
local err_msg = ''; -- start with the error message empty
local path, timestamp, flag; -- portions of the archive.or url
 
if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine url
return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate
end
 
if url:match('//web%.archive%.org/save/') then -- if a save command url, we don't want to allow saving of the target page
err_msg = 'save command';
url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL
else
path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the url parts for evaluation
 
if not is_set(timestamp) or 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here
err_msg = 'timestamp';
end
end
 
 
--[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------
 
Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal
sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a
parameter that is missing its pipe:
{{cite ... |title=Title access-date=2016-03-17}}
 
cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html
tags are removed before the search.
 
local function missing_pipe_check (value)
local capture;
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc
 
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes
end
end
 
 
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
 
local function citation0( config, args)
--[[
Load Input Parameters
The argument_wrapper facilitates the mapping of multiple aliases to single internal variable.
]]
local A = argument_wrapper( args );
local i
 
-- Pick out the relevant fields from the arguments. Different citation templates
-- define different field names for the same underlying things.
 
-- set default parameter values defined by |mode= parameter.
if in_array(config.CitationClass, {"book","citation"}) and not is_set(A['Periodical']) then -- |contributor= and |contribution= only supported in book cites
c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn=
 
if 0 < #c then
if not is_set (Contribution) then -- |contributor= requires |contribution=
 
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate'])
 
local DeadURL = A['DeadURL']
if not is_valid_parameter_value (DeadURL, 'dead-url', cfg.keywords ['deadurl']) then -- set in config.defaults to 'yes'
 
local Series = A['Series'];
 
local Volume;
local Issue;
if not in_array (config.CitationClass, cfg.templates_not_using_page) then
Page = A['Page'];
Pages = hyphen_to_dash( A['Pages'] );
At = A['At'];
end
local PublicationPlace = A['PublicationPlace']
local Place = A['Place'];
 
local PublisherName = A['PublisherName'];
local RegistrationRequired = A['RegistrationRequired'];
local Transcript = A['Transcript'];
local TranscriptFormat = A['TranscriptFormat'];
local TranscriptURL = A['TranscriptURL']
local TranscriptURLorigin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL
 
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category
 
local NoPP = A['NoPP']
if is_set (NoPP) and is_valid_parameter_value (NoPP, 'nopp', cfg.keywords ['yes_true_y']) then
NoPP = true;
end
extra_text_in_page_check (Pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp.
end
 
-- both |publication-place= and |place= (|location=) allowed if different
PublicationPlace = Place; -- promote |place= (|location=) to |publication-place
end
 
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same
 
--[[
Parameter remapping for cite encyclopedia:
|encyclopedia and |article then map |encyclopedia to |title
|encyclopedia then map |encyclopedia to |title
 
|trans-title maps to |trans-chapter when |title is re-mapped
|url maps to |chapterurl when |title is remapped
 
All other combinations of |encyclopedia, |title, and |article are not modified
 
]]
 
table.insert( z.message_tail, { set_error('redundant_parameters', {wrap_style ('parameter', 'id') .. ' and ' .. wrap_style ('parameter', 'number')}, true )});
end
end
end
 
ChapterURLorigin = A:ORIGIN('MapURL');
ChapterFormat = A['MapFormat'];
 
Cartography = A['Cartography'];
if is_set( Cartography ) then
Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase);
end
Scale = A['Scale'];
if is_set( Scale ) then
if is_set(Station) then table.insert(n, Station); end
ID = table.concat(n, sepc .. ' ');
 
if not is_set (Date) and is_set (AirDate) then -- promote airdate to date
Date = AirDate;
if is_set(Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end
Issue = ''; -- unset because this is not a unique parameter
 
Chapter = Title; -- promote title parameters to chapter
ScriptChapter = ScriptTitle;
ChapterUrlAccess = UrlAccess;
ChapterURLorigin = A:ORIGIN('URL');
 
Title = Series; -- promote series to title
TitleLink = SeriesLink;
TransTitle = '';
ScriptTitle = '';
 
else -- now oddities that are cite serial
Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial
end
Series = wrap_style ('italic-title', Series); -- series is italicized
end
end
-- end of {{cite episode}} stuff
table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message
end
 
if 'arxiv' == config.CitationClass then
Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string
Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where
we get the date used in the metadata.
 
Date validation supporting code is in Module:Citation/CS1/Date_validation
]]
-- end temporary Julian / Gregorian calendar uncertainty categorization
 
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed;
local mismatch = year_date_check (Year, Date)
if 0 == mismatch then -- |year= does not match a year-value in |date=
end
end
 
if not is_set(error_message) then -- error free dates only
local modified = false; -- flag
 
if is_set (DF) then -- if we need to reformat dates
modified = reformat_dates (date_parameters_list, DF, false); -- reformat to DF format, use long month names if appropriate
add_maint_cat ('date_format'); -- hyphens were converted so add maint category
end
 
-- for those wikis that can and want to have English date names translated to the local language,
-- uncomment these three lines. Not supported by en.wiki (for obvious reasons)
-- set date_name_xlate() second argument to true to translate English digits to local digits (will translate ymd dates)
if date_name_xlate (date_parameters_list, true) then
end -- end of do
 
-- Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set. Do this after date check but before COInS.
-- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date
Embargo = is_embargoed (Embargo);
end
 
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.
-- Test if citation has no title
if not is_set(Title) and
end
end
 
if 'none' == Title and in_array (config.CitationClass, {'journal', 'citation'}) and is_set (Periodical) and 'journal' == A:ORIGIN('Periodical') then -- special case for journal cites
Title = ''; -- set title to empty string
-- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that
-- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title
-- is the article title, and Chapter is a section within the article. So, we remap
 
local coins_chapter = Chapter; -- default assuming that remapping not required
local coins_title = Title; -- et tu
end
end
local coins_author = a; -- default for coins rft.au
if 0 < #c then -- but if contributor list
coins_author = c; -- use that instead
end
 
-- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text
if 'newsgroup' == config.CitationClass then
if is_set (PublisherName) then
end
end
 
 
 
-- Now perform various field substitutions.
do
local last_first_list;
local control = {
format = NameListFormat, -- empty string or 'vanc'
maximum = nil, -- as if display-authors or display-editors not set
end
 
if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then
EditorCount = 2; -- spoof to display (eds.) annotation
end
end
end -- end of do
 
if is_set (Authors) and is_set (Collaboration) then
Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al.
table.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } );
end
 
-- do we have |accessdate= without either |url= or |chapter-url=?
if is_set(AccessDate) and not is_set(ChapterURL)then -- ChapterURL may be set when URL is not set;
end
Chapter = Chapter.. sepc .. ' ';
elseif is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ...
Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it
end
end
 
-- Format main title.
if '...' == Title:sub (-3) then -- if elipsis is the last three characters of |title=
Title = mw.ustring.gsub (Title, '(%.%.%.)%.+$', '%1'); -- limit the number of dots to three
elseif not mw.ustring.find (Title, '%.%s*%a%.') then -- end of title is not a 'dot-(optional space-)letter-dot' initialism
end
end
 
if is_set(Title) then
if not is_set(TitleLink) and is_set(URL) then
 
Title = external_link( URL, Title, URLorigin, UrlAccess ) .. TransTitle .. TransError .. Format;
URL = ''; -- unset these because no longer needed
local Sections = A['Sections'];
local Inset = A['Inset'];
 
if is_set( Inset ) then
Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase);
end
 
if is_set( Sections ) then
Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase);
end
At = At .. Inset .. Section;
end
 
if is_set (Language) then
 
Others = is_set(Others) and (sepc .. " " .. Others) or "";
 
if is_set (Translators) then
Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc);
Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc);
end
 
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
if is_set (Edition) then
 
--[[
Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link
note is displayed. There are no error messages for this condition.
 
]]
if is_set (SubscriptionRequired) then
AccessDate = substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates
end
 
if is_set(ID) then ID = sepc .." ".. ID; end
if "thesis" == config.CitationClass and is_set(Docket) then
Quote = Quote:sub(2,-2); -- strip them off
end
Quote = sepc .." " .. wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags
PostScript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set
end
 
local Archived
if is_set(ArchiveURL) then
{ external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil ) .. ArchiveFormat, ArchiveDate } );
if not is_set(OriginalURL) then
Archived = Archived .. " " .. set_error('archive_missing_url');
end
elseif is_set(OriginalURL) then -- DeadURL is empty, 'yes', 'true', 'y', 'unfit', 'usurped'
Archived = sepc .. " " .. substitute( arch_text,
{ external_link( OriginalURL, cfg.messages['original'], OriginalURLorigin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled
end
else
local arch_text = cfg.messages['archived-missing'];
if sepc ~= "." then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( arch_text,
{ set_error('archive_missing_url'), ArchiveDate } );
end
Archived = ""
end
 
local Lay = '';
if is_set(LayURL) then
if is_set(LayDate) then LayDate = " (" .. LayDate .. ")" end
if is_set(LaySource) then
LaySource = " &ndash; ''" .. safe_for_italics(LaySource) .. "''";
else
LaySource = "";
else
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary']:lower(), A:ORIGIN('LayURL'), nil ) .. LayFormat .. LaySource .. LayDate
end
elseif is_set (LayFormat) then -- Test if |lay-format= is given without giving a |lay-url=
Lay = sepc .. LayFormat; -- if set and LayURL not set, then LayFormat has error message
Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate;
else
Publisher = sepc .. " " .. PublisherName .. PublicationDate;
end
elseif is_set(PublicationPlace) then
Publisher= sepc .. " " .. PublicationPlace .. PublicationDate;
else
Publisher = PublicationDate;
end
 
-- Several of the above rely upon detecting this as nil, so do it last.
if is_set(Periodical) then
if is_set(Title) or is_set(TitleNote) then
Periodical = sepc .. " " .. wrap_style ('italic-title', Periodical)
else
Periodical = wrap_style ('italic-title', Periodical)
end
 
--[[
Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that
the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided).
]]
if "speech" == config.CitationClass then -- cite speech only
TitleNote = " (Speech)"; -- annotate the citation
if is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter
if is_set (Conference) then -- and if |event= is set
Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering
end
 
-- Piece all bits together at last. Here, all should be non-nil.
-- We build things this way because it is more efficient in LUA
-- not to keep reassigning to the same string variable over and over.
local tcommon;
local tcommon2; -- used for book cite when |contributor= is set
 
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then
if is_set(Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here?
tcommon = safe_join( {Title, TitleType, Format, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc );
end
 
elseif 'episode' == config.CitationClass then -- special case for cite episode
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc );
 
else -- all other CS1 templates
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language,
Volume, Others, Edition, Publisher, Agency}, sepc );
end
 
if #ID_list > 0 then
ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc );
else
ID_list = ID;
end
 
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local text;
end
end
end
if is_set(Authors) then
if (not is_set (Date)) then -- when date is set it's in parentheses; no Authors termination
post_text = ", " .. cfg.messages['editors'];
end
end
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
end
end
end
 
if is_set(PostScript) and PostScript ~= sepc then
text = safe_join( {text, sepc}, sepc ); --Deals with italics, spaces, etc.
text = text:sub(1,-sepc:len()-1);
end
 
text = safe_join( {text, PostScript}, sepc );
 
-- Now enclose the whole thing in a <cite/> element
local options = {};
 
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then
options.class = config.CitationClass;
options.class = "citation";
end
 
if is_set(Ref) and Ref:lower() ~= "none" then -- set reference anchor if appropriate
local id = Ref
options.id = id;
end
 
if string.len(text:gsub("<span[^>/]*>(.-)</span>", "%1"):gsub("%b<>","")) <= 2 then -- remove <span> tags and other html-like markup; then get length of what remains
z.error_categories = {};
text = set_error('empty_citation');
z.message_tail = {};
end
 
local render = {}; -- here we collect the final bits for concatenation into the rendered citation
 
if is_set(options.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags
table.insert (render, substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options.id), mw.text.nowiki(options.class), text})); -- when |ref= is set
else
table.insert (render, substitute (cfg.presentation['cite'], {mw.text.nowiki(options.class), text})); -- all other cases
end
 
table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation
table.insert (render, '</span>');
end
 
no_tracking_cats = no_tracking_cats:lower();
if in_array(no_tracking_cats, {"", "no", "false", "n"}) then
end
 
return table.concat (render);
end
 
 
--[[--------------------------< C S 1 . C I T A T I O N >------------------------------------------------------
local pframe = frame:getParent()
local validation, utilities, identifiers, metadata;
 
if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version?
cfg = mw.loadData ('Module:Citation/CS1/Configuration'); -- load sandbox versions of support modules
identifiers = require ('Module:Citation/CS1/Identifiers');
metadata = require ('Module:Citation/CS1/COinS');
 
else -- otherwise
cfg = mw.loadData ('মডিউল:উদ্ধৃতি/রূপরেখা'); -- load live versions of support modules
is_embargoed = identifiers.is_embargoed;
extract_id_access_levels = identifiers.extract_id_access_levels;
 
make_coins_title = metadata.make_coins_title; -- imported functions from Module:Citation/CS1/COinS
get_coins_pages = metadata.get_coins_pages;
config[k] = v;
-- args[k] = v; -- debug tool that allows us to render a citation from module {{#invoke:}}
end
 
local capture; -- the single supported capture when matching unknown parameters using patterns
if v ~= '' then
k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9
if not validate( k, config.CitationClass ) then
error_text = "";
if type( k ) ~= 'string' then
error_text, error_state = set_error( 'text_ignored', {v}, true );
end
elseif validate( k:lower(), config.CitationClass ) then
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true );
else
for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter
capture = k:match (pattern); -- the whole match if no caputre in pattern else the capture if a match
if capture then -- if the pattern matches
param = substitute( param, capture ); -- add the capture to the suggested parameter (typically the enumerator)
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, param}, true ); -- set the error message
end
end
end
if error_text ~= '' then
table.insert( z.message_tail, {error_text, error_state} );
end
end
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe?
args[k] = v;
elseif args[k] ~= nil or (k == 'postscript') then -- here when v is empty string
args[k] = v; -- why do we do this? we don't support 'empty' parameters
end
end
 
for k, v in pairs( args ) do
end
end
 
if args.title or args.url then -- this code used at bn.wiki only; not maintained in en.wiki source
add_maint_cat ('bn.wiki_uses_en-lang_params'); -- add maint cat if English parameter name |title= or |url= is used in the template
end -- end bn.wiki only
 
return citation0( config, args)
end