ဝီကီးပီးဒီးယား
rkiwiki
https://rki.wikipedia.org/wiki/%E1%80%A1%E1%80%93%E1%80%AD%E1%80%80%E1%80%85%E1%80%AC%E1%80%99%E1%80%BB%E1%80%80%E1%80%BA%E1%80%94%E1%80%BE%E1%80%AC
MediaWiki 1.46.0-wmf.21
first-letter
မီဒီယာ
အထူး
ဆွီးနွီးချက်
အသုံးပြုလူ
အသုံးပြုလူ ဆွီးနွီးချက်
ဝီကီးပီးဒီးယား
ဝီကီးပီးဒီးယား ဆွီးနွီးချက်
ဖိုင်
ဖိုင် ဆွီးနွီးချက်
မီဒီယာဝီကီ
မီဒီယာဝီကီ ဆွီးနွီးချက်
တမ်းပလိတ်
တမ်းပလိတ် ဆွီးနွီးချက်
အကူအညီ
အကူအညီ ဆွီးနွီးချက်
ကဏ္ဍ
ကဏ္ဍ ဆွီးနွီးချက်
TimedText
TimedText talk
Module
Module talk
Event
Event talk
Module:Citation/CS1/Date validation
828
1069
17613
3607
2026-03-29T16:36:41Z
YaThaWinTha
42
17613
Scribunto
text/plain
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
local add_prop_cat, is_set, in_array, wrap_style; -- imported functions from selected Module:Citation/CS1/Utilities
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
--[[--------------------------< F I L E - S C O P E D E C L A R A T I O N S >--------------------------------
File-scope variables are declared here
]]
local lang_object = mw.getContentLanguage(); -- used by is_valid_accessdate(), is_valid_year(), date_name_xlate(); TODO: move to ~/Configuration?
local year_limit; -- used by is_valid_year()
--[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >----------------------------------------
returns true if:
Wikipedia start date <= accessdate < today + 2 days
Wikipedia start date is 2001-01-15T00:00:00 UTC which is 979516800 seconds after 1970-01-01T00:00:00 UTC (the start of Unix time)
accessdate is the date provided in |access-date= at time 00:00:00 UTC
today is the current date at time 00:00:00 UTC plus 48 hours
if today is 2015-01-01T00:00:00 then
adding 24 hours gives 2015-01-02T00:00:00 – one second more than today
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow
This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
apparently doesn't understand non-English date month names. This function will always return false when the date
contains a non-English month name because good1 is false after the call to lang.formatDate(). To get around that
call this function with YYYY-MM-DD format dates.
]=]
local function is_valid_accessdate (accessdate)
local good1, good2;
local access_ts, tomorrow_ts; -- to hold Unix time stamps representing the dates
good1, access_ts = pcall (lang_object.formatDate, lang_object, 'U', accessdate ); -- convert accessdate value to Unix timestamp
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which which tonumber() may not understand
access_ts = tonumber (access_ts) or lang_object:parseFormattedNumber (access_ts); -- convert to numbers for the comparison;
tomorrow_ts = tonumber (tomorrow_ts) or lang_object:parseFormattedNumber (tomorrow_ts);
else
return false; -- one or both failed to convert to Unix time stamp
end
if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date
return true;
else
return false; -- accessdate out of range
end
end
--[[--------------------------< I S _ V A L I D _ E M B A R G O _ D A T E >------------------------------------
returns true and date value if that value has proper dmy, mdy, ymd format.
returns false and 9999 (embargoed forever) when date value is not proper format; assumes that when |pmc-embargo-date= is
set, the editor intended to embargo a PMC but |pmc-embargo-date= does not hold a single date.
]]
local function is_valid_embargo_date (v)
if v:match ('^%d%d%d%d%-%d%d%-%d%d$') or -- ymd
v:match ('^%d%d?%s+%a+%s+%d%d%d%d$') or -- dmy
v:match ('^%a+%s+%d%d?%s*,%s*%d%d%d%d$') then -- mdy
return true, v;
end
return false, '9999'; -- if here not good date so return false and set embargo date to long time in future
end
--[[--------------------------< G E T _ M O N T H _ N U M B E R >----------------------------------------------
returns a number according to the month in a date: 1 for January, etc. Capitalization and spelling must be correct.
If not a valid month, returns 0
]]
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
--[[--------------------------< G E T _ S E A S O N _ N U M B E R >--------------------------------------------
returns a number according to the sequence of seasons in a year: 21 for Spring, etc. Capitalization and spelling
must be correct. If not a valid season, returns 0.
21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere”
returns 0 when <param> is not |date=
Season numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons. EDTF does support the distinction between north and south
hemispere seasons but cs1|2 has no way to make that distinction.
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, param)
if 'date' ~= param then
return 0; -- season dates only supported by |date=
end
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
--[[--------------------------< G E T _ Q U A R T E R _ N U M B E R >------------------------------------------
returns a number according to the sequence of quarters in a year: 33 for first quarter, etc. Capitalization and spelling
must be correct. If not a valid quarter, returns 0.
33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each)
returns 0 when <param> is not |date=
Quarter numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons and quarters.
These additional divisions not currently supported:
37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each)
40-41 = Semestral 1, Semestral-2 (6 months each)
]]
local function get_quarter_number (quarter, param)
if 'date' ~= param then
return 0; -- quarter dates only supported by |date=
end
quarter = mw.ustring.gsub (quarter, ' +', ' '); -- special case replace multiple space chars with a single space char
return cfg.date_names['local'].quarter[quarter] or -- look for local names first
cfg.date_names['en'].quarter[quarter] or -- failing that, look for English names
0; -- not a recognized quarter name
end
--[[--------------------------< G E T _ P R O P E R _ N A M E _ N U M B E R >----------------------------------
returns a non-zero number if date contains a recognized proper-name. Capitalization and spelling must be correct.
returns 0 when <param> is not |date=
]]
local function get_proper_name_number (name, param)
if 'date' ~= param then
return 0; -- proper-name dates only supported by |date=
end
return cfg.date_names['local'].named[name] or -- look for local names dates first
cfg.date_names['en'].named[name] or -- failing that, look for English names
0; -- not a recognized named date
end
--[[--------------------------< G E T _ E L E M E N T _ N U M B E R <------------------------------------------
returns true if month or season or quarter or proper name is valid (properly spelled, capitalized, abbreviated)
]]
local function get_element_number (element, param)
local num;
local funcs = {get_month_number, get_season_number, get_quarter_number, get_proper_name_number}; -- list of functions to execute in order
for _, func in ipairs (funcs) do -- spin through the function list
num = func (element, param); -- call the function and get the returned number
if 0 ~= num then -- non-zero when valid month season quarter
return num; -- return that number
end
end
return nil; -- not valid
end
--[[--------------------------< I S _ V A L I D _ Y E A R >----------------------------------------------------
Function gets current year from the server and compares it to year from a citation parameter. Years more than one
year in the future are not acceptable.
]]
local function is_valid_year (year)
if not is_set(year_limit) then
year_limit = tonumber(os.date("%Y"))+1; -- global variable so we only have to fetch it once
end
year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to numbers for the comparison;
return year and (year <= year_limit) or false;
end
--[[--------------------------< I S _ V A L I D _ D A T E >----------------------------------------------------
Returns true if day is less than or equal to the number of days in month and year is no farther into the future
than next year; 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.
]]
local 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 not is_valid_year(year) then -- no farther into the future than next year
return false;
end
month = tonumber(month); -- required for YYYY-MM-DD dates
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 -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
else -- Gregorian calendar
if (0 == (year%4) and (0 ~= (year%100) or 0 == (year%400))) then -- is 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
--[[--------------------------< I S _ V A L I D _ M O N T H _ R A N G E _ S T Y L E >--------------------------
Months in a range are expected to have the same style: Jan–Mar or October–December but not February–Mar or Jul–August.
There is a special test for May because it can be either short or long form.
Returns true when style for both months is the same
]]
local function is_valid_month_range_style (month1, month2)
local len1 = month1:len();
local len2 = month2:len();
if len1 == len2 then
return true; -- both months are short form so return true
elseif 'May' == month1 or 'May'== month2 then -- ToDo: I18N
return true; -- both months are long form so return true
elseif 3 == len1 or 3 == len2 then
return false; -- months are mixed form so return false
else
return true; -- both months are long form so return true
end
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ S E A S O N _ R A N G E >------------------------
Check a pair of months or seasons to see if both are valid members of a month or season pair.
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, hence treat as ok
]]
local function is_valid_month_season_range(range_start, range_end, param)
local range_start_number = get_month_number (range_start);
local range_end_number;
if 0 == range_start_number then -- is this a month range?
range_start_number = get_season_number (range_start, param); -- not a month; is it a season? get start season number
range_end_number = get_season_number (range_end, param); -- get end season number
if (0 ~= range_start_number) and (0 ~= range_end_number) and (range_start_number ~= range_end_number) then
return true; -- any season pairing is accepted except when both are the same
end
return false; -- range_start and/or range_end is not a season
end
-- here when range_start is a month
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 is_valid_month_range_style (range_start, range_end) then -- do months have the same style?
return true; -- proper order and same style
end
end
return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month
end
--[[--------------------------< M A K E _ C O I N S _ D A T E >------------------------------------------------
This function receives a table of date parts for one or two dates and an empty table reference declared in
Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is
determined to be a valid date format. The question of what to do with invalid date formats is not answered here.
The date parts in the input table are converted to an ISO 8601 conforming date string:
single whole dates: yyyy-mm-dd
month and year dates: yyyy-mm
year dates: yyyy
ranges: yyyy-mm-dd/yyyy-mm-dd
yyyy-mm/yyyy-mm
yyyy/yyyy
Dates in the Julian calendar are reduced to year or year/year so that we don't have to do calendar conversion from
Julian to Proleptic Gregorian.
The input table has:
year, year2 – always present; if before 1582, ignore months and days if present
month, month2 – 0 if not provided, 1-12 for months, 21-24 for seasons; 99 Christmas
day, day2 – 0 if not provided, 1-31 for days
the output table receives:
rftdate: an ISO 8601 formatted date
rftchron: a free-form version of the date, usually without year which is in rftdate (season ranges and proper-name dates)
rftssn: one of four season keywords: winter, spring, summer, fall (lowercase)
rftquarter: one of four values: 1, 2, 3, 4
]]
local function make_COinS_date (input, tCOinS_date)
local date; -- one date or first date in a range
local date2 = ''; -- end of range date
-- start temporary Julian / Gregorian calendar uncertainty detection
local year = tonumber(input.year); -- this temporary code to determine the extent of sources dated to the Julian/Gregorian
local month = tonumber(input.month); -- interstice 1 October 1582 – 1 January 1926
local day = tonumber (input.day);
if (0 ~= day) and -- day must have a value for this to be a whole date
(((1582 == year) and (10 <= month) and (12 >= month)) or -- any whole 1582 date from 1 October to 31 December or
((1926 == year) and (1 == month) and (1 == input.day)) or -- 1 January 1926 or
((1582 < year) and (1925 >= year))) then -- any date 1 January 1583 – 31 December 1925
tCOinS_date.inter_cal_cat = true; -- set category flag true
end
-- end temporary Julian / Gregorian calendar uncertainty detection
if 1582 > tonumber(input.year) or 20 < tonumber(input.month) then -- Julian calendar or season so &rft.date gets year only
date = input.year;
if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year
date = string.format ('%.4d/%.4d', tonumber(input.year), tonumber(input.year2)) -- assemble the date range
end
if 20 < tonumber(input.month) then -- if season or proper-name date
local season = {[24] = 'winter', [21] = 'spring', [22] = 'summer', [23] = 'fall', [33] = '1', [34] = '2', [35] = '3', [36] = '4', [98] = 'Easter', [99] = 'Christmas'}; -- seasons lowercase, no autumn; proper-names use title case
if 0 == input.month2 then -- single season date
if 40 < tonumber(input.month) then
tCOinS_date.rftchron = season[input.month]; -- proper-name dates
elseif 30 < tonumber(input.month) then
tCOinS_date.rftquarter = season[input.month]; -- quarters
else
tCOinS_date.rftssn = season[input.month]; -- seasons
end
else -- season range with a second season specified
if input.year ~= input.year2 then -- season year – season year range or season year–year
tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
if 0~= input.month2 then
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2);
end
else -- season–season year range
tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range
end
end
end
tCOinS_date.rftdate = date;
return; -- done
end
if 0 ~= input.day then
date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date
elseif 0 ~= input.month then
date = string.format ('%s-%.2d', input.year, tonumber(input.month)); -- year and month
else
date = string.format ('%s', input.year); -- just year
end
if 0 ~= input.year2 then
if 0 ~= input.day2 then
date2 = string.format ('/%s-%.2d-%.2d', input.year2, tonumber(input.month2), tonumber(input.day2)); -- whole date
elseif 0 ~= input.month2 then
date2 = string.format ('/%s-%.2d', input.year2, tonumber(input.month2)); -- year and month
else
date2 = string.format ('/%s', input.year2); -- just year
end
end
tCOinS_date.rftdate = date .. date2; -- date2 has the '/' separator
return;
end
--[[--------------------------< P A T T E R N S >--------------------------------------------------------------
this is the list of patterns for date formats that this module recognizes. Approximately the first half of these
patterns represent formats that might be reformatted into another format. Those that might be reformatted have
'indicator' letters that identify the content of the matching capture: 'd' (day), 'm' (month), 'a' (anchor year),
'y' (year); second day, month, year have a '2' suffix.
These patterns are used for both date validation and for reformatting. This table should not be moved to ~/Configuration
because changes to this table require changes to check_date() and to reformatter() and reformat_date()
]]
local patterns = {
-- year-initial numerical year-month-day
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'},
-- month-initial: month day, year
['Mdy'] = {'^(%D-) +([1-9]%d?), +((%d%d%d%d?)%a?)$', 'm', 'd', 'a', 'y'},
-- month-initial day range: month day–day, year; days are separated by endash
['Md-dy'] = {'^(%D-) +([1-9]%d?)[%-–]([1-9]%d?), +((%d%d%d%d)%a?)$', 'm', 'd', 'd2', 'a', 'y'},
-- day-initial: day month year
['dMy'] = {'^([1-9]%d?) +(%D-) +((%d%d%d%d?)%a?)$', 'd', 'm', 'a', 'y'},
-- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed; not supported at en.wiki
-- ['yMd'] = {'^((%d%d%d%d?)%a?) +(%D-) +(%d%d?)$', 'a', 'y', 'm', 'd'},
-- day-range-initial: day–day month year; days are separated by endash
['d-dMy'] = {'^([1-9]%d?)[%-–]([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'd2', 'm', 'a', 'y'},
-- day initial month-day-range: day month - day month year; uses spaced endash
['dM-dMy'] = {'^([1-9]%d?) +(%D-) +[%-–] +([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'm', 'd2', 'm2', 'a', 'y'},
-- month initial month-day-range: month day – month day, year; uses spaced endash
['Md-Mdy'] = {'^(%D-) +([1-9]%d?) +[%-–] +(%D-) +([1-9]%d?), +((%d%d%d%d)%a?)$','m', 'd', 'm2', 'd2', 'a', 'y'},
-- day initial month-day-year-range: day month year - day month year; uses spaced endash
['dMy-dMy'] = {'^([1-9]%d?) +(%D-) +(%d%d%d%d) +[%-–] +([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'm', 'y', 'd2', 'm2', 'a', 'y2'},
-- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
['Mdy-Mdy'] = {'^(%D-) +([1-9]%d?), +(%d%d%d%d) +[%-–] +(%D-) +([1-9]%d?), +((%d%d%d%d)%a?)$', 'm', 'd', 'y', 'm2', 'd2', 'a', 'y2'},
-- these date formats cannot be converted, per se, but month name can be rendered short or long
-- month/season year - month/season year; separated by spaced endash
['My-My'] = {'^(%D-) +(%d%d%d%d) +[%-–] +(%D-) +((%d%d%d%d)%a?)$', 'm', 'y', 'm2', 'a', 'y2'},
-- month/season range year; months separated by endash
['M-My'] = {'^(%D-)[%-–](%D-) +((%d%d%d%d)%a?)$', 'm', 'm2', 'a', 'y'},
-- month/season year or proper-name year; quarter year when First Quarter YYYY etc.
['My'] = {'^([^%d–]-) +((%d%d%d%d)%a?)$', 'm', 'a', 'y'}, -- this way because endash is a member of %D; %D- will match January–March 2019 when it shouldn't
-- these date formats cannot be converted
['Sy4-y2'] = {'^(%D-) +((%d%d)%d%d)[%-–]((%d%d)%a?)$'}, -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
['Sy-y'] = {'^(%D-) +(%d%d%d%d)[%-–]((%d%d%d%d)%a?)$'}, -- special case Winter/Summer year-year; year separated with unspaced endash
['y-y'] = {'^(%d%d%d%d?)[%-–]((%d%d%d%d?)%a?)$'}, -- year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
['y4-y2'] = {'^((%d%d)%d%d)[%-–]((%d%d)%a?)$'}, -- year range: YYYY–YY; separated by unspaced endash
['y'] = {'^((%d%d%d%d?)%a?)$'}, -- year; here accept either YYY or YYYY
}
--[[--------------------------< C H E C K _ D A T E >----------------------------------------------------------
Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only
allowed range separator is endash. 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. Future years beyond next year are not allowed.
If the date fails the format tests, this function returns false and does not return values for anchor_year and
COinS_date. When this happens, the date parameter is (DEBUG: not?) used in the COinS metadata and the CITEREF identifier gets
its year from the year parameter if present otherwise CITEREF does not get a date value.
Inputs:
date_string - date string from date-holding parameters (date, year, publication-date, access-date, pmc-embargo-date, archive-date, lay-date)
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 ISO 8601 format date; see make_COInS_date()
]]
local function check_date (date_string, param, tCOinS_date)
local year; -- assume that year2, months, and days are not used;
local year2 = 0; -- second year in a year range
local month = 0;
local month2 = 0; -- second month in a month range
local day = 0;
local day2 = 0; -- second day in a day range
local anchor_year;
local coins_date;
if date_string:match (patterns['ymd'][1]) then -- year-initial numerical year month day format
year, month, day = date_string:match (patterns['ymd'][1]);
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;
elseif mw.ustring.match(date_string, patterns['Mdy'][1]) then -- month-initial: month day, year
month, day, anchor_year, year = mw.ustring.match(date_string, patterns['Mdy'][1]);
month = get_month_number (month);
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, patterns['Md-dy'][1]) then -- month-initial day range: month day–day, year; days are separated by endash
month, day, day2, anchor_year, year = mw.ustring.match(date_string, patterns['Md-dy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2=month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns['dMy'][1]) then -- day-initial: day month year
day, month, anchor_year, year = mw.ustring.match(date_string, patterns['dMy'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
--[[ NOT supported at en.wiki
elseif mw.ustring.match(date_string, patterns['yMd'][1]) then -- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed
anchor_year, year, month, day = mw.ustring.match(date_string, patterns['yMd'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
-- end NOT supported at en.wiki ]]
elseif mw.ustring.match(date_string, patterns['d-dMy'][1]) then -- day-range-initial: day–day month year; days are separated by endash
day, day2, month, anchor_year, year = mw.ustring.match(date_string, patterns['d-dMy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2 = month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns['dM-dMy'][1]) then -- day initial month-day-range: day month - day month year; uses spaced endash
day, month, day2, month2, anchor_year, year = mw.ustring.match(date_string, patterns['dM-dMy'][1]);
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end -- date range order is left to right: earlier to later;
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns['Md-Mdy'][1]) 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, patterns['Md-Mdy'][1]);
if (not is_valid_month_season_range(month, month2, param)) or not is_valid_year(year) then return false; end
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns['dMy-dMy'][1]) 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, patterns['dMy-dMy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns['Mdy-Mdy'][1]) then -- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
month, day, year, month2, day2, anchor_year, year2 = mw.ustring.match(date_string, patterns['Mdy-Mdy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns['Sy4-y2'][1]) then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
local century;
month, year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['Sy4-y2'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
year2 = century..year2; -- add the century to year2 for comparisons
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number(month, param);
elseif mw.ustring.match(date_string, patterns['Sy-y'][1]) then -- special case Winter/Summer year-year; year separated with unspaced endash
month, year, anchor_year, year2 = mw.ustring.match(date_string, patterns['Sy-y'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number (month, param); -- for metadata
elseif mw.ustring.match(date_string, patterns['My-My'][1]) then -- month/season year - month/season year; separated by spaced endash
month, year, month2, anchor_year, year2 = mw.ustring.match(date_string, patterns['My-My'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if 0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2) then -- both must be month year, same month style
month = get_month_number(month);
month2 = get_month_number(month2);
elseif 0 ~= get_season_number(month, param) and 0 ~= get_season_number(month2, param) then -- both must be season year, not mixed
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
else
return false;
end
elseif mw.ustring.match(date_string, patterns['M-My'][1]) then -- month/season range year; months separated by endash
month, month2, anchor_year, year = mw.ustring.match(date_string, patterns['M-My'][1]);
if (not is_valid_month_season_range(month, month2, param)) or (not is_valid_year(year)) then return false; end
if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
month = get_month_number(month);
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end
else
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
end
year2 = year;
elseif mw.ustring.match(date_string, patterns['My'][1]) then -- month/season/quarter/proper-name year
month, anchor_year, year = mw.ustring.match(date_string, patterns['My'][1]);
if not is_valid_year(year) then return false; end
month = get_element_number(month, param); -- get month season quarter proper-name number or nil
if not month then return false; end -- not valid whatever it is
elseif mw.ustring.match(date_string, patterns['y-y'][1]) then -- Year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
year, anchor_year, year2 = mw.ustring.match(date_string, patterns['y-y'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns['y4-y2'][1]) then -- Year range: YYYY–YY; separated by unspaced endash
local century;
year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['y4-y2'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if in_array (param, {'date', 'publication-date', 'year'}) then
add_prop_cat ('year_range_abbreviated');
end
if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003
year2 = century .. year2; -- add the century to year2 for comparisons
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns['y'][1]) then -- year; here accept either YYY or YYYY
anchor_year, year = mw.ustring.match(date_string, patterns['y'][1]);
if false == is_valid_year(year) then
return false;
end
else
return false; -- date format not one of the MOS:DATE approved formats
end
if 'access-date' == param then -- test accessdate here because we have numerical date parts
if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2 then -- none of these; accessdate must not be a range
if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then
return false; -- return false when accessdate out of bounds
end
else
return false; -- return false when accessdate is a range of two dates
end
end
local result=true; -- check whole dates for validity; assume true because not all dates will go through this test
if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date)
result = is_valid_date(year, month, day);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 ~= day2 then -- YMD-d (day range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year, month, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-md (day month range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year, month2, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 ~= year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-ymd (day month year range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year2, month2, day2);
end
if false == result then return false; end
if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values
make_COinS_date ({year = year, month = month, day = day, year2 = year2, month2 = month2, day2 = day2}, tCOinS_date); -- make an ISO 8601 date string for COinS
end
return true, anchor_year; -- format is good and date string represents a real date
end
--[[--------------------------< D A T E S >--------------------------------------------------------------------
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. The |date= parameter test is unique, it is the only date holding parameter from which values for anchor_year (used in CITEREF identifiers) and COinS_date (used in
the COinS metadata) are derived. The |date= parameter 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,
parameters with errors are added to the <error_list> sequence table as the dates are tested.
]]
local function dates(date_parameters_list, tCOinS_date, error_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 embargo_date; -- if embargo date is a good dmy, mdy, ymd date then holds original value else reset to 9999
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.val) then -- if the parameter has a value
v.val = mw.ustring.gsub(v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9
if v.val:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
local year = v.val:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested
if 'date' == k then
anchor_year, COinS_date = v.val:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
good_date = is_valid_year(year);
elseif 'year' == k then
good_date = is_valid_year(year);
end
elseif 'date' == k then -- if the parameter is |date=
if v.val:match("^n%.d%.%a?$") then -- ToDo: I18N -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((n%.d%.)%a?)"); -- ToDo: I18N -- "n.d."; no error when date parameter is set to no date
elseif v.val:match("^nd%a?$") then -- ToDo: I18N -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((nd)%a?)"); -- ToDo: I18N -- "nd"; no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v.val, k, tCOinS_date); -- go test the date
end
elseif 'year' == k then -- if the parameter is |year= it should hold only a year value
if v.val:match("^[1-9]%d%d%d?%a?$") then -- if |year = 3 or 4 digits only with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)");
end
elseif 'pmc-embargo-date' == k then -- if the parameter is |pmc-embargo-date=
good_date = check_date (v.val, k); -- go test the date
if true == good_date then -- if the date is a valid date
good_date, embargo_date = is_valid_embargo_date (v.val); -- is |pmc-embargo-date= date a single dmy, mdy, or ymd formatted date? yes: returns embargo; no: returns 9999
end
else -- any other date-holding parameter
good_date = check_date (v.val, k); -- go test the date
end
if false == good_date then -- assemble one error message so we don't add the tracking category multiple times
table.insert (error_list, wrap_style ('parameter', v.name)); -- make parameter name suitable for error message list
end
end
end
return anchor_year, embargo_date; -- and done
end
--[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------
Compare the value provided in |year= with the year value(s) provided in |date=. This function returns a numeric value:
0 - year value does not match the year value in date
1 - (default) year value matches the year value in date or one of the year values when date contains two years
2 - year value matches the year value in date when date is in the form YYYY-MM-DD and year is disambiguated (|year=YYYYx)
]]
local function year_date_check (year_string, date_string)
local year;
local date1;
local date2;
local result = 1; -- result of the test; assume that the test passes
year = year_string:match ('(%d%d%d%d?)');
if date_string:match ('%d%d%d%d%-%d%d%-%d%d') and year_string:match ('%d%d%d%d%a') then --special case where both date and year are required YYYY-MM-DD and YYYYx
date1 = date_string:match ('(%d%d%d%d)');
year = year_string:match ('(%d%d%d%d)');
if year ~= date1 then
result = 0; -- years don't match
else
result = 2; -- years match; but because disambiguated, don't add to maint cat
end
elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard range formats of date with two three- or four-digit years
date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)");
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif mw.ustring.match(date_string, "%d%d%d%d[%-–]%d%d") then -- YYYY-YY date ranges
local century;
date1, century, date2 = mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]+(%d%d)");
date2 = century..date2; -- convert YY to YYYY
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif date_string:match ("%d%d%d%d?") then -- any of the standard formats of date with one year
date1 = date_string:match ("(%d%d%d%d?)");
if year ~= date1 then
result = 0;
end
else
result = 0; -- no recognizable year in date
end
return result;
end
--[[--------------------------< R E F O R M A T T E R >--------------------------------------------------------
reformat 'date' into new format specified by format_param if pattern_idx (the current format of 'date') can be
reformatted. Does the grunt work for reformat_dates().
The table re_formats maps pattern_idx (current format) and format_param (desired format) to a table that holds:
format string used by string.format()
identifier letters ('d', 'm', 'y', 'd2', 'm2', 'y2') that serve as indexes into a table t{} that holds captures
from mw.ustring.match() for the various date parts specified by patterns[pattern_idx][1]
Items in patterns{} have the general form:
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'}, where:
['ymd'] is pattern_idx
patterns['ymd'][1] is the match pattern with captures for mw.ustring.match()
patterns['ymd'][2] is an indicator letter identifying the content of the first capture
patterns['ymd'][3] ... the second capture etc.
when a pattern matches a date, the captures are loaded into table t{} in capture order using the idemtifier
characters as indexes into t{} For the above, a ymd date is in t{} as:
t.y = first capture (year), t.m = second capture (month), t.d = third capture (day)
To reformat, this function is called with the pattern_idx that matches the current format of the date and with
format_param set to the desired format. This function loads table t{} as described and then calls string.format()
with the format string specified by re_format[pattern_idx][format_param][1] using values taken from t{} according
to the capture identifier letters specified by patterns[pattern_idx][format_param][n] where n is 2..
]]
local re_formats = {
['ymd'] = { -- date format is ymd; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Mdy'] = { -- date format is Mdy; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['dMy'] = { -- date format is dMy; reformat to:
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Md-dy'] = { -- date format is Md-dy; reformat to:
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- |df=dmy -> d-dMy
},
['d-dMy'] = { -- date format is d-d>y; reformat to:
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- |df=mdy -> Md-dy
},
['dM-dMy'] = { -- date format is dM-dMy; reformat to:
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- |df=mdy -> Md-Mdy
},
['Md-Mdy'] = { -- date format is Md-Mdy; reformat to:
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- |df=dmy -> dM-dMy
},
['dMy-dMy'] = { -- date format is dMy-dMy; reformat to:
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- |df=mdy -> Mdy-Mdy
},
['Mdy-Mdy'] = { -- date format is Mdy-Mdy; reformat to:
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- for long/short reformatting
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- |df=dmy -> dMy-dMy
},
['My-My'] = { -- these for long/short reformatting
['any'] = {'%s %s – %s %s', 'm', 'y', 'm2', 'y2'}, -- dmy/mdy agnostic
},
['M-My'] = { -- these for long/short reformatting
['any'] = {'%s–%s %s', 'm', 'm2', 'y'}, -- dmy/mdy agnostic
},
['My'] = { -- these for long/short reformatting
['any'] = {'%s %s', 'm', 'y'}, -- dmy/mdy agnostic
},
-- ['yMd'] = { -- not supported at en.wiki
-- ['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
-- ['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- },
}
local function reformatter (date, pattern_idx, format_param, mon_len)
if not in_array (pattern_idx, {'ymd', 'Mdy', 'Md-dy', 'dMy', 'yMd', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- not in this set of date format patterns then not a reformattable date
end
if 'ymd' == format_param and in_array (pattern_idx, {'ymd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- ymd date ranges not supported at en.wiki; no point in reformatting ymd to ymd
end
if in_array (pattern_idx, {'My', 'M-My', 'My-My'}) then -- these are not dmy/mdy so can't be 'reformatted' into either
format_param = 'any'; -- so format-agnostic
end
-- yMd is not supported at en.wiki
-- if yMd is supported at your wiki, uncomment the next line
-- if 'yMd' == format_param and in_array (pattern_idx, {'yMd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy'}) then -- these formats not convertable; yMd not supported at en.wiki
-- if yMd is supported at your wiki, remove or comment-out the next line
if 'yMd' == format_param then -- yMd not supported at en.wiki
return; -- not a reformattable date
end
local c1, c2, c3, c4, c5, c6, c7; -- these hold the captures specified in patterns[pattern_idx][1]
c1, c2, c3, c4, c5, c6, c7 = mw.ustring.match (date, patterns[pattern_idx][1]); -- get the captures
local t = { -- table that holds k/v pairs of date parts from the captures and patterns[pattern_idx][2..]
[patterns[pattern_idx][2]] = c1; -- at minimum there is always one capture with a matching indicator letter
[patterns[pattern_idx][3] or 'x'] = c2; -- patterns can have a variable number of captures; each capture requires an indicator letter;
[patterns[pattern_idx][4] or 'x'] = c3; -- where there is no capture, there is no indicator letter so n in patterns[pattern_idx][n] will be nil;
[patterns[pattern_idx][5] or 'x'] = c4; -- the 'x' here spoofs an indicator letter to prevent 'table index is nil' error
[patterns[pattern_idx][6] or 'x'] = c5;
[patterns[pattern_idx][7] or 'x'] = c6;
[patterns[pattern_idx][8] or 'x'] = c7;
};
if t.a then -- if this date has an anchor year capture
t.y = t.a; -- use the anchor year capture when reassembling the date
end
if tonumber(t.m) then -- if raw month is a number (converting from ymd)
if 's' == mon_len then -- if we are to use abbreviated month names
t.m = cfg.date_names['inv_local_s'][tonumber(t.m)]; -- convert it to a month name
else
t.m = cfg.date_names['inv_local_l'][tonumber(t.m)]; -- convert it to a month name
end
t.d = t.d:gsub ('0(%d)', '%1'); -- strip leading '0' from day if present
elseif 'ymd' == format_param then -- when converting to ymd
if 1582 > tonumber(t.y) then -- ymd format dates not allowed before 1582
return;
end
t.m = string.format ('%02d', get_month_number (t.m)); -- make sure that month and day are two digits
t.d = string.format ('%02d', t.d);
elseif mon_len then -- if mon_len is set to either 'short' or 'long'
for _, mon in ipairs ({'m', 'm2'}) do -- because there can be two month names, check both
if t[mon] then
t[mon] = get_month_number (t[mon]); -- get the month number for this month (is length agnostic)
if 0 == t[mon] then return; end -- seasons and named dates can't be converted
t[mon] = (('s' == mon_len) and cfg.date_names['inv_local_s'][t[mon]]) or cfg.date_names['inv_local_l'][t[mon]]; -- fetch month name according to length
end
end
end
local new_date = string.format (re_formats[pattern_idx][format_param][1], -- format string
t[re_formats[pattern_idx][format_param][2]], -- named captures from t{}
t[re_formats[pattern_idx][format_param][3]],
t[re_formats[pattern_idx][format_param][4]],
t[re_formats[pattern_idx][format_param][5]],
t[re_formats[pattern_idx][format_param][6]],
t[re_formats[pattern_idx][format_param][7]],
t[re_formats[pattern_idx][format_param][8]]
);
return new_date;
end
--[[-------------------------< R E F O R M A T _ D A T E S >--------------------------------------------------
Reformats existing dates into the format specified by format.
format is one of several manual keywords: dmy, dmy-all, mdy, mdy-all, ymd, ymd-all. The -all version includes
access- and archive-dates; otherwise these dates are not reformatted.
This function allows automatic date formatting. In ~/Configuration, the article source is searched for one of
the {{use xxx dates}} templates. If found, xxx becomes the global date format as xxx-all. If |cs1-dates= in
{{use xxx dates}} has legitimate value then that value determines how cs1|2 dates will be rendered. Legitimate
values for |cs1-dates= are:
l - all dates are rendered with long month names
ls - publication dates use long month names; access-/archive-dates use abbreviated month names
ly - publication dates use long month names; access-/archive-dates rendered in ymd format
s - all dates are rendered with abbreviated (short) month names
sy - publication dates use abbreviated month names; access-/archive-dates rendered in ymd format
y - all dates are rendered in ymd format
the format argument for automatic date formatting will be the format specified by {{use xxx dates}} with the
value supplied by |cs1-dates so one of: xxx-l, xxx-ls, xxx-ly, xxx-s, xxx-sy, xxx-y, or simply xxx (|cs1-dates=
empty, omitted, or invalid) where xxx shall be either of dmy or mdy.
dates are extracted from date_parameters_list, reformatted (if appropriate), and then written back into the
list in the new format. Dates in date_parameters_list are presumed here to be valid (no errors). This function
returns true when a date has been reformatted, false else. Actual reformatting is done by reformatter().
]]
local function reformat_dates (date_parameters_list, format)
local all = false; -- set to false to skip access- and archive-dates
local len_p = 'l'; -- default publication date length shall be long
local len_a = 'l'; -- default access-/archive-date length shall be long
local result = false;
local new_date;
if format:match('%a+%-all') then -- manual df keyword; auto df keyword when length not specified in {{use xxx dates}};
format = format:match('(%a+)%-all'); -- extract the format
all = true; -- all dates are long format dates because this keyword doesn't specify length
elseif format:match('%a+%-[lsy][sy]?') then -- auto df keywords; internal only
all = true; -- auto df applies to all dates; use length specified by capture len_p for all dates
format, len_p, len_a = format:match('(%a+)%-([lsy])([sy]?)'); -- extract the format and length keywords
if 'y' == len_p then -- because allowed by MOS:DATEUNIFY (sort of) range dates and My dates not reformatted
format = 'ymd'; -- override {{use xxx dates}}
elseif (not is_set(len_a)) or (len_p == len_a) then -- no access-/archive-date length specified or same length as publication dates then
len_a = len_p; -- in case len_a not set
end
end -- else only publication dates and they are long
for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then -- if the parameter has a value
if not (not all and in_array (param_name, {'access-date', 'archive-date'})) then -- skip access- or archive-date unless format is xxx-all; yeah, ugly; TODO: find a better way
for pattern_idx, pattern in pairs (patterns) do
if mw.ustring.match (param_val.val, pattern[1]) then
if all and in_array (param_name, {'access-date', 'archive-date'}) then -- if this date is an access- or archive-date
new_date = reformatter (param_val.val, pattern_idx, (('y' == len_a) and 'ymd') or format, len_a); -- choose ymd or dmy/mdy according to len_a setting
else -- all other dates
new_date = reformatter (param_val.val, pattern_idx, format, len_p);
end
if new_date then -- set when date was reformatted
date_parameters_list[param_name].val = new_date; -- update date in date list
result = true; -- and announce that changes have been made
end
end -- if
end -- for
end -- if
end -- if
end -- for
return result; -- declare boolean result and done
end
--[[--------------------------< D A T E _ H Y P H E N _ T O _ D A S H >----------------------------------------
Loops through the list of date-holding parameters and converts any hyphen to an ndash. Not called if the cs1|2
template has any date errors.
Modifies the date_parameters_list and returns true if hyphens are replaced, else returns false.
]]
local function date_hyphen_to_dash (date_parameters_list)
local result = false;
local n;
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then
if not mw.ustring.match (param_val.val, '%d%d%d%d%-%d%d%-%d%d') then -- for those that are not ymd dates (ustring because here digits may not be Western)
param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash
if 0 ~= n then
date_parameters_list[param_name].val = param_val.val; -- update the list
result = true;
end
end
end
end
return result; -- so we know if any hyphens were replaced
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.
if xlat_dig is true, this function will also translate Western (English) digits to the local language's digits.
This will also translate ymd dates.
]]
local function date_name_xlate (date_parameters_list, xlt_dig)
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.val) then -- if the parameter has a value
date = param_val.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 = lang_object: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].val = date; -- save the translated date
modified = true;
end
end
if xlt_dig then -- shall we also translate digits?
date = date:gsub ('%d', cfg.date_names.xlate_digits); -- translate digits from Western to 'local digits'
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
end
return modified;
end
--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------
Sets local imported functions table to same (live or sandbox) as that used by the other modules.
]]
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
add_prop_cat = utilities_page_ptr.add_prop_cat ; -- import functions from selected Module:Citation/CS1/Utilities module
is_set = utilities_page_ptr.is_set;
in_array = utilities_page_ptr.in_array;
-- set_message = utilities_page_ptr.set_message;
wrap_style = utilities_page_ptr.wrap_style;
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return { -- return exported functions
dates = dates,
year_date_check = year_date_check,
reformat_dates = reformat_dates,
date_hyphen_to_dash = date_hyphen_to_dash,
date_name_xlate = date_name_xlate,
set_selected_modules = set_selected_modules
}
ds0l4tghd9b1ze47i4ysqzmmocnzkhm
17614
17613
2026-03-29T16:39:17Z
YaThaWinTha
42
17614
Scribunto
text/plain
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
local add_prop_cat, is_set, in_array, set_message, substitute, wrap_style; -- imported functions from selected Module:Citation/CS1/Utilities
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
--[[--------------------------< F I L E - S C O P E D E C L A R A T I O N S >--------------------------------
File-scope variables are declared here
]]
local lang_object = mw.getContentLanguage(); -- used by is_valid_accessdate(), is_valid_year(), date_name_xlate(); TODO: move to ~/Configuration?
local year_limit; -- used by is_valid_year()
--[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >----------------------------------------
returns true if:
Wikipedia start date <= accessdate < today + 2 days
Wikipedia start date is 2001-01-15T00:00:00 UTC which is 979516800 seconds after 1970-01-01T00:00:00 UTC (the start of Unix time)
accessdate is the date provided in |access-date= at time 00:00:00 UTC
today is the current date at time 00:00:00 UTC plus 48 hours
if today is 2015-01-01T00:00:00 then
adding 24 hours gives 2015-01-02T00:00:00 – one second more than today
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow
This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
apparently doesn't understand non-English date month names. This function will always return false when the date
contains a non-English month name because good1 is false after the call to lang.formatDate(). To get around that
call this function with YYYY-MM-DD format dates.
]=]
local function is_valid_accessdate (accessdate)
local good1, good2;
local access_ts, tomorrow_ts; -- to hold Unix time stamps representing the dates
good1, access_ts = pcall (lang_object.formatDate, lang_object, 'U', accessdate ); -- convert accessdate value to Unix timestamp
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which which tonumber() may not understand
access_ts = tonumber (access_ts) or lang_object:parseFormattedNumber (access_ts); -- convert to numbers for the comparison;
tomorrow_ts = tonumber (tomorrow_ts) or lang_object:parseFormattedNumber (tomorrow_ts);
else
return false; -- one or both failed to convert to Unix time stamp
end
if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date
return true;
else
return false; -- accessdate out of range
end
end
--[[--------------------------< G E T _ M O N T H _ N U M B E R >----------------------------------------------
returns a number according to the month in a date: 1 for January, etc. Capitalization and spelling must be correct.
If not a valid month, returns 0
]]
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
--[[--------------------------< G E T _ S E A S O N _ N U M B E R >--------------------------------------------
returns a number according to the sequence of seasons in a year: 21 for Spring, etc. Capitalization and spelling
must be correct. If not a valid season, returns 0.
21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere”
returns 0 when <param> is not |date=
Season numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons. EDTF does support the distinction between north and south
hemisphere seasons but cs1|2 has no way to make that distinction.
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, param)
if 'date' ~= param then
return 0; -- season dates only supported by |date=
end
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
--[[--------------------------< G E T _ Q U A R T E R _ N U M B E R >------------------------------------------
returns a number according to the sequence of quarters in a year: 33 for first quarter, etc. Capitalization and spelling
must be correct. If not a valid quarter, returns 0.
33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each)
returns 0 when <param> is not |date=
Quarter numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons and quarters.
These additional divisions not currently supported:
37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each)
40-41 = Semestral 1, Semestral-2 (6 months each)
]]
local function get_quarter_number (quarter, param)
if 'date' ~= param then
return 0; -- quarter dates only supported by |date=
end
quarter = mw.ustring.gsub (quarter, ' +', ' '); -- special case replace multiple space chars with a single space char
return cfg.date_names['local'].quarter[quarter] or -- look for local names first
cfg.date_names['en'].quarter[quarter] or -- failing that, look for English names
0; -- not a recognized quarter name
end
--[[--------------------------< G E T _ P R O P E R _ N A M E _ N U M B E R >----------------------------------
returns a non-zero number if date contains a recognized proper-name. Capitalization and spelling must be correct.
returns 0 when <param> is not |date=
]]
local function get_proper_name_number (name, param)
if 'date' ~= param then
return 0; -- proper-name dates only supported by |date=
end
return cfg.date_names['local'].named[name] or -- look for local names dates first
cfg.date_names['en'].named[name] or -- failing that, look for English names
0; -- not a recognized named date
end
--[[--------------------------< G E T _ E L E M E N T _ N U M B E R <------------------------------------------
returns true if month or season or quarter or proper name is valid (properly spelled, capitalized, abbreviated)
]]
local function get_element_number (element, param)
local num;
local funcs = {get_month_number, get_season_number, get_quarter_number, get_proper_name_number}; -- list of functions to execute in order
for _, func in ipairs (funcs) do -- spin through the function list
num = func (element, param); -- call the function and get the returned number
if 0 ~= num then -- non-zero when valid month season quarter
return num; -- return that number
end
end
return nil; -- not valid
end
--[[--------------------------< I S _ V A L I D _ Y E A R >----------------------------------------------------
Function gets current year from the server and compares it to year from a citation parameter. Years more than one
year in the future are not acceptable.
Special case for |pmc-embargo-date=: years more than two years in the future are not acceptable
]]
local function is_valid_year (year, param)
if not is_set (year_limit) then
year_limit = tonumber(os.date("%Y"))+1; -- global variable so we only have to fetch it once
end
year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to number for the comparison
if year and (100 > year) then -- years less than 100 not supported
return false;
end
if 'pmc-embargo-date' == param then -- special case for |pmc-embargo-date=
return year and (year <= tonumber(os.date("%Y"))+2) or false; -- years more than two years in the future are not accepted
end
return year and (year <= year_limit) or false;
end
--[[--------------------------< I S _ V A L I D _ D A T E >----------------------------------------------------
Returns true if day is less than or equal to the number of days in month and year is no farther into the future
than next year; 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.
]]
local function is_valid_date (year, month, day, param)
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local month_length;
if not is_valid_year (year, param) then -- no farther into the future than next year except |pmc-embargo-date= no more than two years in the future
return false;
end
month = tonumber (month); -- required for YYYY-MM-DD dates
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 -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
else -- Gregorian calendar
if (0 == (year%4) and (0 ~= (year%100) or 0 == (year%400))) then -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
end
else
month_length = days_in_month[month] or 0; -- invalid month number is nil so default <month_length> to 0
end
if tonumber (day) > month_length then
return false;
end
return true;
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ R A N G E _ S T Y L E >--------------------------
Months in a range are expected to have the same style: Jan–Mar or October–December but not February–Mar or Jul–August.
This function looks in cfg.date_names{} to see if both month names are listed in the long subtable or both are
listed in the short subtable. When both have the same style (both are listed in the same table), returns true; false else
]]
local function is_valid_month_range_style (month1, month2)
if (cfg.date_names.en.long[month1] and cfg.date_names.en.long[month2]) or -- are both English names listed in the long subtable?
(cfg.date_names.en.short[month1] and cfg.date_names.en.short[month2]) or -- are both English names listed in the short subtable?
(cfg.date_names['local'].long[month1] and cfg.date_names['local'].long[month2]) or -- are both local names listed in the long subtable?
(cfg.date_names['local'].short[month1] and cfg.date_names['local'].short[month2]) then -- are both local names listed in the short subtable?
return true;
end
return false; -- names are mixed
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ S E A S O N _ R A N G E >------------------------
Check a pair of months or seasons to see if both are valid members of a month or season pair.
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, hence treat as ok
]]
local function is_valid_month_season_range(range_start, range_end, param)
local range_start_number = get_month_number (range_start);
local range_end_number;
if 0 == range_start_number then -- is this a month range?
range_start_number = get_season_number (range_start, param); -- not a month; is it a season? get start season number
range_end_number = get_season_number (range_end, param); -- get end season number
if (0 ~= range_start_number) and (0 ~= range_end_number) and (range_start_number ~= range_end_number) then
return true; -- any season pairing is accepted except when both are the same
end
return false; -- range_start and/or range_end is not a season
end
-- here when range_start is a month
range_end_number = get_month_number (range_end); -- get end month number
if range_start_number < range_end_number and -- range_start is a month; does range_start precede range_end?
is_valid_month_range_style (range_start, range_end) then -- do months have the same style?
return true; -- proper order and same style
end
return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month
end
--[[--------------------------< M A K E _ C O I N S _ D A T E >------------------------------------------------
This function receives a table of date parts for one or two dates and an empty table reference declared in
Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is
determined to be a valid date format. The question of what to do with invalid date formats is not answered here.
The date parts in the input table are converted to an ISO 8601 conforming date string:
single whole dates: yyyy-mm-dd
month and year dates: yyyy-mm
year dates: yyyy
ranges: yyyy-mm-dd/yyyy-mm-dd
yyyy-mm/yyyy-mm
yyyy/yyyy
Dates in the Julian calendar are reduced to year or year/year so that we don't have to do calendar conversion from
Julian to Proleptic Gregorian.
The input table has:
year, year2 – always present; if before 1582, ignore months and days if present
month, month2 – 0 if not provided, 1-12 for months, 21-24 for seasons; 99 Christmas
day, day2 – 0 if not provided, 1-31 for days
the output table receives:
rftdate: an ISO 8601 formatted date
rftchron: a free-form version of the date, usually without year which is in rftdate (season ranges and proper-name dates)
rftssn: one of four season keywords: winter, spring, summer, fall (lowercase)
rftquarter: one of four values: 1, 2, 3, 4
]]
local function make_COinS_date (input, tCOinS_date)
local date; -- one date or first date in a range
local date2 = ''; -- end of range date
input.year = tonumber (input.year) or lang_object:parseFormattedNumber (input.year); -- language-aware tonumber()
input.year2 = tonumber (input.year2) or lang_object:parseFormattedNumber (input.year2); -- COinS dates are pseudo-ISO 8601 so convert to Arabic numerals
if ((1582 == input.year) and (10 > tonumber(input.month))) or (1582 > input.year) then -- if a Julian calendar date
tCOinS_date.rftdate = tostring (input.year); -- &rft.date gets year only
return; -- done
end
-- here for all forms of Gregorian dates
if 20 < tonumber (input.month) then -- if season, quarter, or proper-name date
date = input.year; -- &rft.date gets year only
if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year
date = string.format ('%.4d/%.4d', input.year, input.year2) -- assemble the date range
end
local season = {[24] = 'winter', [21] = 'spring', [22] = 'summer', [23] = 'fall', [33] = '1', [34] = '2', [35] = '3', [36] = '4', [98] = 'Easter', [99] = 'Christmas'}; -- seasons lowercase, no autumn; proper-names use title case
if 0 == input.month2 then -- single season, quarter, or proper-name date
if 40 < tonumber(input.month) then
tCOinS_date.rftchron = season[input.month]; -- proper-name date; used in journal metadata only
elseif 30 < tonumber(input.month) then
tCOinS_date.rftquarter = season[input.month]; -- quarter date; used in journal metadata only
else
tCOinS_date.rftssn = season[input.month]; -- season date; used in journal metadata only
end
else -- season ranges are lumped into &rft.chron; &rft.ssn and &rft.quarter are left blank
if input.year ~= input.year2 then -- season year – season year range or season year–year
if 0 ~= input.month2 then
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2); -- used in journal metadata only
end
else -- season–season year range
tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range; used in journal metadata only
end
end
tCOinS_date.rftdate = tostring (date);
return; -- done
end
-- here for gregorian calendar dates
if 0 ~= input.day then
date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date
elseif 0 ~= input.month then
date = string.format ('%s-%.2d', input.year, tonumber(input.month)); -- year and month
else
date = string.format ('%s', input.year); -- just year
end
if 0 ~= input.year2 then
if 0 ~= input.day2 then
date2 = string.format ('/%s-%.2d-%.2d', input.year2, tonumber(input.month2), tonumber(input.day2)); -- whole date
elseif 0 ~= input.month2 then
date2 = string.format ('/%s-%.2d', input.year2, tonumber(input.month2)); -- year and month
else
date2 = string.format ('/%s', input.year2); -- just year
end
end
tCOinS_date.rftdate = date .. date2; -- date2 has the '/' separator
return;
end
--[[--------------------------< P A T T E R N S _ T >----------------------------------------------------------
this is the list of patterns for date formats that this module recognizes. Approximately the first half of these
patterns represent formats that might be reformatted into another format. Those that might be reformatted have
'indicator' letters that identify the content of the matching capture: 'd' (day), 'm' (month), 'a' (anchor year),
'y' (year); second day, month, year have a '2' suffix.
These patterns are used for both date validation and for reformatting. This table should not be moved to ~/Configuration
because changes to this table require changes to check_date() and to reformatter() and reformat_date()
]]
local patterns_t = {
-- year-initial numerical year-month-day
['ymd'] = {'^([1-9]%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'},
-- month-initial: month day, year
['Mdy'] = {'^(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'a', 'y'},
-- month-initial day range: month day–day, year; days are separated by endash
['Md-dy'] = {'^(%D-) +([1-9]%d?)[%-–]([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'd2', 'a', 'y'},
-- day-initial: day month year
['dMy'] = {'^([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'a', 'y'},
-- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed; not supported at en.wiki
-- ['yMd'] = {'^(([1-9]%d%d%d?)%a?) +(%D-) +(%d%d?)$', 'a', 'y', 'm', 'd'},
-- day-range-initial: day–day month year; days are separated by endash
['d-dMy'] = {'^([1-9]%d?)[%-–]([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'd2', 'm', 'a', 'y'},
-- day initial month-day-range: day month - day month year; uses spaced endash
['dM-dMy'] = {'^([1-9]%d?) +(%D-) +[%-–] +([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'd2', 'm2', 'a', 'y'},
-- month initial month-day-range: month day – month day, year; uses spaced endash
['Md-Mdy'] = {'^(%D-) +([1-9]%d?) +[%-–] +(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$','m', 'd', 'm2', 'd2', 'a', 'y'},
-- day initial month-day-year-range: day month year - day month year; uses spaced endash
['dMy-dMy'] = {'^([1-9]%d?) +(%D-) +([1-9]%d%d%d?) +[%-–] +([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'y', 'd2', 'm2', 'a', 'y2'},
-- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
['Mdy-Mdy'] = {'^(%D-) +([1-9]%d?), +([1-9]%d%d%d?) +[%-–] +(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'y', 'm2', 'd2', 'a', 'y2'},
-- these date formats cannot be converted, per se, but month name can be rendered short or long
-- month/season year - month/season year; separated by spaced endash
['My-My'] = {'^(%D-) +([1-9]%d%d%d?) +[%-–] +(%D-) +(([1-9]%d%d%d?)%a?)$', 'm', 'y', 'm2', 'a', 'y2'},
-- month/season range year; months separated by endash
['M-My'] = {'^(%D-)[%-–](%D-) +(([1-9]%d%d%d?)%a?)$', 'm', 'm2', 'a', 'y'},
-- month/season year or proper-name year; quarter year when First Quarter YYYY etc.
['My'] = {'^([^%d–]-) +(([1-9]%d%d%d?)%a?)$', 'm', 'a', 'y'}, -- this way because endash is a member of %D; %D- will match January–March 2019 when it shouldn't
-- these date formats cannot be converted
['Sy4-y2'] = {'^(%D-) +(([1-9]%d)%d%d)[%-–]((%d%d)%a?)$'}, -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
['Sy-y'] = {'^(%D-) +([1-9]%d%d%d?)[%-–](([1-9]%d%d%d?)%a?)$'}, -- special case Winter/Summer year-year; year separated with unspaced endash
['y-y'] = {'^([1-9]%d%d%d?)[%-–](([1-9]%d%d%d?)%a?)$'}, -- year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
['y4-y2'] = {'^(([1-9]%d)%d%d)[%-–]((%d%d)%a?)$'}, -- year range: YYYY–YY; separated by unspaced endash
['y'] = {'^(([1-9]%d%d%d?)%a?)$'}, -- year; here accept either YYY or YYYY
}
--[[--------------------------< I S _ V A L I D _ E M B A R G O _ D A T E >------------------------------------
returns true and date value if that value has proper dmy, mdy, ymd format.
returns false and 9999 (embargoed forever) when date value is not proper format; assumes that when |pmc-embargo-date= is
set, the editor intended to embargo a PMC but |pmc-embargo-date= does not hold a single date.
]]
local function is_valid_embargo_date (v)
if v:match (patterns_t['ymd'][1]) or -- ymd
v:match (patterns_t['Mdy'][1]) or -- dmy
v:match (patterns_t['dMy'][1]) then -- mdy
return true, v;
end
return false, '9999'; -- if here not good date so return false and set embargo date to long time in future
end
--[[--------------------------< C H E C K _ D A T E >----------------------------------------------------------
Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only
allowed range separator is endash. 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. Future years beyond next year are not allowed.
If the date fails the format tests, this function returns false and does not return values for anchor_year and
COinS_date. When this happens, the date parameter is (DEBUG: not?) used in the COinS metadata and the CITEREF identifier gets
its year from the year parameter if present otherwise CITEREF does not get a date value.
Inputs:
date_string - date string from date-holding parameters (date, year, publication-date, access-date, pmc-embargo-date, archive-date, lay-date)
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 ISO 8601 format date; see make_COInS_date()
]]
local function check_date (date_string, param, tCOinS_date)
local year; -- assume that year2, months, and days are not used;
local year2 = 0; -- second year in a year range
local month = 0;
local month2 = 0; -- second month in a month range
local day = 0;
local day2 = 0; -- second day in a day range
local anchor_year;
local coins_date;
if date_string:match (patterns_t['ymd'][1]) then -- year-initial numerical year month day format
year, month, day = date_string:match (patterns_t['ymd'][1]);
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;
elseif mw.ustring.match(date_string, patterns_t['Mdy'][1]) then -- month-initial: month day, year
month, day, anchor_year, year = mw.ustring.match(date_string, patterns_t['Mdy'][1]);
month = get_month_number (month);
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, patterns_t['Md-dy'][1]) then -- month-initial day range: month day–day, year; days are separated by endash
month, day, day2, anchor_year, year = mw.ustring.match(date_string, patterns_t['Md-dy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2=month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dMy'][1]) then -- day-initial: day month year
day, month, anchor_year, year = mw.ustring.match(date_string, patterns_t['dMy'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
--[[ NOT supported at en.wiki
elseif mw.ustring.match(date_string, patterns_t['yMd'][1]) then -- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed
anchor_year, year, month, day = mw.ustring.match(date_string, patterns_t['yMd'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
-- end NOT supported at en.wiki ]]
elseif mw.ustring.match(date_string, patterns_t['d-dMy'][1]) then -- day-range-initial: day–day month year; days are separated by endash
day, day2, month, anchor_year, year = mw.ustring.match(date_string, patterns_t['d-dMy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2 = month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dM-dMy'][1]) then -- day initial month-day-range: day month - day month year; uses spaced endash
day, month, day2, month2, anchor_year, year = mw.ustring.match(date_string, patterns_t['dM-dMy'][1]);
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end -- date range order is left to right: earlier to later;
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['Md-Mdy'][1]) 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, patterns_t['Md-Mdy'][1]);
if (not is_valid_month_season_range(month, month2, param)) or not is_valid_year(year) then return false; end
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dMy-dMy'][1]) 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, patterns_t['dMy-dMy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns_t['Mdy-Mdy'][1]) then -- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
month, day, year, month2, day2, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Mdy-Mdy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns_t['Sy4-y2'][1]) then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
local century;
month, year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Sy4-y2'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
year2 = century..year2; -- add the century to year2 for comparisons
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number(month, param);
elseif mw.ustring.match(date_string, patterns_t['Sy-y'][1]) then -- special case Winter/Summer year-year; year separated with unspaced endash
month, year, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Sy-y'][1]);
month = get_season_number (month, param); -- <month> can only be winter or summer; also for metadata
if (month ~= cfg.date_names['en'].season['Winter']) and (month ~= cfg.date_names['en'].season['Summer']) then
return false; -- not Summer or Winter; abandon
end
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns_t['My-My'][1]) then -- month/season year - month/season year; separated by spaced endash
month, year, month2, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['My-My'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if 0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2) then -- both must be month year, same month style
month = get_month_number(month);
month2 = get_month_number(month2);
elseif 0 ~= get_season_number(month, param) and 0 ~= get_season_number(month2, param) then -- both must be season year, not mixed
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
else
return false;
end
elseif mw.ustring.match(date_string, patterns_t['M-My'][1]) then -- month/season range year; months separated by endash
month, month2, anchor_year, year = mw.ustring.match(date_string, patterns_t['M-My'][1]);
if (not is_valid_month_season_range(month, month2, param)) or (not is_valid_year(year)) then return false; end
if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
month = get_month_number(month);
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end
else
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
end
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['My'][1]) then -- month/season/quarter/proper-name year
month, anchor_year, year = mw.ustring.match(date_string, patterns_t['My'][1]);
if not is_valid_year(year) then return false; end
month = get_element_number(month, param); -- get month season quarter proper-name number or nil
if not month then return false; end -- not valid whatever it is
elseif mw.ustring.match(date_string, patterns_t['y-y'][1]) then -- Year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
year, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['y-y'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns_t['y4-y2'][1]) then -- Year range: YYYY–YY; separated by unspaced endash
local century;
year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['y4-y2'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003
year2 = century .. year2; -- add the century to year2 for comparisons
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if in_array (param, {'date', 'publication-date', 'year'}) then -- here when 'valid' abbreviated year range; if one of these parameters
add_prop_cat ('year-range-abbreviated'); -- add properties cat
end
elseif mw.ustring.match(date_string, patterns_t['y'][1]) then -- year; here accept either YYY or YYYY
anchor_year, year = mw.ustring.match(date_string, patterns_t['y'][1]);
if false == is_valid_year(year) then
return false;
end
else
return false; -- date format not one of the MOS:DATE approved formats
end
if param ~= 'date' then -- CITEREF disambiguation only allowed in |date=; |year= & |publication-date= promote to date
if anchor_year:match ('%l$') then
return false;
end
end
if 'access-date' == param then -- test access-date here because we have numerical date parts
if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2 then -- none of these; access-date must not be a range
if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then
return false; -- return false when access-date out of bounds
end
else
return false; -- return false when access-date is a range of two dates
end
end
if 'archive-date' == param then -- test archive-date here because we have numerical date parts
if not (0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2) then -- none of these; archive-date must not be a range
return false; -- return false when archive-date is a range of two dates
end
end
local result=true; -- check whole dates for validity; assume true because not all dates will go through this test
if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date)
result = is_valid_date (year, month, day, param); -- <param> for |pmc-embargo-date=
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 ~= day2 then -- YMD-d (day range)
result = is_valid_date (year, month, day);
result = result and is_valid_date (year, month, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-md (day month range)
result = is_valid_date (year, month, day);
result = result and is_valid_date (year, month2, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 ~= year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-ymd (day month year range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year2, month2, day2);
end
if false == result then return false; end
if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values
make_COinS_date ({year = year, month = month, day = day, year2 = year2, month2 = month2, day2 = day2}, tCOinS_date); -- make an ISO 8601 date string for COinS
end
return true, anchor_year; -- format is good and date string represents a real date
end
--[[--------------------------< D A T E S >--------------------------------------------------------------------
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. The |date= parameter test is unique, it is the only date holding parameter from which values for anchor_year (used in CITEREF identifiers) and COinS_date (used in
the COinS metadata) are derived. The |date= parameter 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,
parameters with errors are added to the <error_list> sequence table as the dates are tested.
]]
local function dates(date_parameters_list, tCOinS_date, error_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 embargo_date; -- if embargo date is a good dmy, mdy, ymd date then holds original value else reset to 9999
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.val) then -- if the parameter has a value
v.val = mw.ustring.gsub(v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9
if v.val:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
local year = v.val:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested
if 'date' == k then
anchor_year, COinS_date = v.val:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
good_date = is_valid_year(year);
elseif 'year' == k then
good_date = is_valid_year(year);
else
good_date = false;
end
elseif 'date' == k then -- if the parameter is |date=
if v.val:match("^n%.d%.%a?$") then -- ToDo: I18N -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((n%.d%.)%a?)"); -- ToDo: I18N -- "n.d."; no error when date parameter is set to no date
elseif v.val:match("^nd%a?$") then -- ToDo: I18N -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((nd)%a?)"); -- ToDo: I18N -- "nd"; no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v.val, k, tCOinS_date); -- go test the date
end
elseif 'year' == k then -- if the parameter is |year= it should hold only a year value
if v.val:match("^[1-9]%d%d%d?%a?$") then -- if |year = 3 or 4 digits only with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)");
else
good_date = false;
end
elseif 'pmc-embargo-date' == k then -- if the parameter is |pmc-embargo-date=
good_date = check_date (v.val, k); -- go test the date
if true == good_date then -- if the date is a valid date
good_date, embargo_date = is_valid_embargo_date (v.val); -- is |pmc-embargo-date= date a single dmy, mdy, or ymd formatted date? yes: returns embargo date; no: returns 9999
end
else -- any other date-holding parameter
good_date = check_date (v.val, k); -- go test the date
end
if false == good_date then -- assemble one error message so we don't add the tracking category multiple times
table.insert (error_list, wrap_style ('parameter', v.name)); -- make parameter name suitable for error message list
end
end
end
return anchor_year, embargo_date; -- and done
end
--[[--------------------------< Y E A R _ C H E C K >----------------------------------------------------------
Temporary function to test |year= for acceptable values:
YYY, YYYY, year-only ranges, their circa forms, with or without CITEREF disambiguators.
When |year= holds some form of date that is not one of these year-only dates, emit a maintenance message.
This function necessary because many non-cs1|2 templates have a |year= parameter so cirrus searches are more-or-
less useless
]]
local function year_check (year)
year = year:gsub ('c%. *', ''); -- remove circa annotation (if present) before testing <year>
for _, index in ipairs ({'y-y', 'y4-y2', 'y'}) do -- spin through these indexes into patterns_t
if mw.ustring.match (year, patterns_t[index][1]) then
return; -- if a match then |year= holds a valid 'year'
end
end
set_message ('maint_year'); -- if here, |year= value is not an accepted value; add a maint cat
end
--[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------
Compare the value provided in |year= with the year value(s) provided in |date=. This function sets a local numeric value:
0 - year value does not match the year value in date
1 - (default) year value matches the year value in date or one of the year values when date contains two years
2 - year value matches the year value in date when date is in the form YYYY-MM-DD and year is disambiguated (|year=YYYYx)
the numeric value in <result> determines the 'output' if any from this function:
0 – adds error message to error_list sequence table
1 – adds maint cat
2 – does nothing
]]
local function year_date_check (year_string, year_origin, date_string, date_origin, error_list)
local year;
local date1;
local date2;
local result = 1; -- result of the test; assume that the test passes
year = year_string:match ('(%d%d%d%d?)');
if date_string:match ('%d%d%d%d%-%d%d%-%d%d') then --special case where both date and year are required YYYY-MM-DD and YYYYx
date1 = date_string:match ('(%d%d%d%d)');
year = year_string:match ('(%d%d%d%d)');
if year ~= date1 then
result = 0; -- years don't match
elseif year_string:match ('%d%d%d%d%a') then
result = 2; -- years match; but because disambiguated, don't add to maint cat
end
elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard range formats of date with two three- or four-digit years
date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)");
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif mw.ustring.match(date_string, "%d%d%d%d[%-–]%d%d") then -- YYYY-YY date ranges
local century;
date1, century, date2 = mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]+(%d%d)");
date2 = century..date2; -- convert YY to YYYY
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif date_string:match ("%d%d%d%d?") then -- any of the standard formats of date with one year
date1 = date_string:match ("(%d%d%d%d?)");
if year ~= date1 then
result = 0;
end
else -- should never get here; this function called only when no other date errors
result = 0; -- no recognizable year in date
end
if 0 == result then -- year / date mismatch
table.insert (error_list, substitute (cfg.messages['mismatch'], {year_origin, date_origin})); -- add error message to error_list sequence table
elseif 1 == result then -- redundant year / date
set_message ('maint_date_year'); -- add a maint cat
end
end
--[[--------------------------< R E F O R M A T T E R >--------------------------------------------------------
reformat 'date' into new format specified by format_param if pattern_idx (the current format of 'date') can be
reformatted. Does the grunt work for reformat_dates().
The table re_formats maps pattern_idx (current format) and format_param (desired format) to a table that holds:
format string used by string.format()
identifier letters ('d', 'm', 'y', 'd2', 'm2', 'y2') that serve as indexes into a table t{} that holds captures
from mw.ustring.match() for the various date parts specified by patterns_t[pattern_idx][1]
Items in patterns_t{} have the general form:
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'}, where:
['ymd'] is pattern_idx
patterns_t['ymd'][1] is the match pattern with captures for mw.ustring.match()
patterns_t['ymd'][2] is an indicator letter identifying the content of the first capture
patterns_t['ymd'][3] ... the second capture etc.
when a pattern matches a date, the captures are loaded into table t{} in capture order using the idemtifier
characters as indexes into t{} For the above, a ymd date is in t{} as:
t.y = first capture (year), t.m = second capture (month), t.d = third capture (day)
To reformat, this function is called with the pattern_idx that matches the current format of the date and with
format_param set to the desired format. This function loads table t{} as described and then calls string.format()
with the format string specified by re_format[pattern_idx][format_param][1] using values taken from t{} according
to the capture identifier letters specified by patterns_t[pattern_idx][format_param][n] where n is 2..
]]
local re_formats = {
['ymd'] = { -- date format is ymd; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Mdy'] = { -- date format is Mdy; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['dMy'] = { -- date format is dMy; reformat to:
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Md-dy'] = { -- date format is Md-dy; reformat to:
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- |df=dmy -> d-dMy
},
['d-dMy'] = { -- date format is d-d>y; reformat to:
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- |df=mdy -> Md-dy
},
['dM-dMy'] = { -- date format is dM-dMy; reformat to:
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- |df=mdy -> Md-Mdy
},
['Md-Mdy'] = { -- date format is Md-Mdy; reformat to:
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- |df=dmy -> dM-dMy
},
['dMy-dMy'] = { -- date format is dMy-dMy; reformat to:
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- |df=mdy -> Mdy-Mdy
},
['Mdy-Mdy'] = { -- date format is Mdy-Mdy; reformat to:
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- for long/short reformatting
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- |df=dmy -> dMy-dMy
},
['My-My'] = { -- these for long/short reformatting
['any'] = {'%s %s – %s %s', 'm', 'y', 'm2', 'y2'}, -- dmy/mdy agnostic
},
['M-My'] = { -- these for long/short reformatting
['any'] = {'%s–%s %s', 'm', 'm2', 'y'}, -- dmy/mdy agnostic
},
['My'] = { -- these for long/short reformatting
['any'] = {'%s %s', 'm', 'y'}, -- dmy/mdy agnostic
},
-- ['yMd'] = { -- not supported at en.wiki
-- ['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
-- ['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- },
}
local function reformatter (date, pattern_idx, format_param, mon_len)
if not in_array (pattern_idx, {'ymd', 'Mdy', 'Md-dy', 'dMy', 'yMd', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- not in this set of date format patterns_t then not a reformattable date
end
if 'ymd' == format_param and in_array (pattern_idx, {'ymd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- ymd date ranges not supported at en.wiki; no point in reformatting ymd to ymd
end
if in_array (pattern_idx, {'My', 'M-My', 'My-My'}) then -- these are not dmy/mdy so can't be 'reformatted' into either
format_param = 'any'; -- so format-agnostic
end
-- yMd is not supported at en.wiki; when yMd is supported at your wiki, uncomment the next line
-- if 'yMd' == format_param and in_array (pattern_idx, {'yMd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy'}) then -- these formats not convertable; yMd not supported at en.wiki
if 'yMd' == format_param then -- yMd not supported at en.wiki; when yMd is supported at your wiki, remove or comment-out this line
return; -- not a reformattable date
end
local c1, c2, c3, c4, c5, c6, c7; -- these hold the captures specified in patterns_t[pattern_idx][1]
c1, c2, c3, c4, c5, c6, c7 = mw.ustring.match (date, patterns_t[pattern_idx][1]); -- get the captures
local t = { -- table that holds k/v pairs of date parts from the captures and patterns_t[pattern_idx][2..]
[patterns_t[pattern_idx][2]] = c1; -- at minimum there is always one capture with a matching indicator letter
[patterns_t[pattern_idx][3] or 'x'] = c2; -- patterns_t can have a variable number of captures; each capture requires an indicator letter;
[patterns_t[pattern_idx][4] or 'x'] = c3; -- where there is no capture, there is no indicator letter so n in patterns_t[pattern_idx][n] will be nil;
[patterns_t[pattern_idx][5] or 'x'] = c4; -- the 'x' here spoofs an indicator letter to prevent 'table index is nil' error
[patterns_t[pattern_idx][6] or 'x'] = c5;
[patterns_t[pattern_idx][7] or 'x'] = c6;
[patterns_t[pattern_idx][8] or 'x'] = c7;
};
if t.a then -- if this date has an anchor year capture (all convertable date formats except ymd)
if t.y2 then -- for year range date formats
t.y2 = t.a; -- use the anchor year capture when reassembling the date
else -- here for single date formats (except ymd)
t.y = t.a; -- use the anchor year capture when reassembling the date
end
end
if tonumber(t.m) then -- if raw month is a number (converting from ymd)
if 's' == mon_len then -- if we are to use abbreviated month names
t.m = cfg.date_names['inv_local_short'][tonumber(t.m)]; -- convert it to a month name
else
t.m = cfg.date_names['inv_local_long'][tonumber(t.m)]; -- convert it to a month name
end
t.d = t.d:gsub ('0(%d)', '%1'); -- strip leading '0' from day if present
elseif 'ymd' == format_param then -- when converting to ymd
t.y = t.y:gsub ('%a', ''); -- strip CITREF disambiguator if present; anchor year already known so process can proceed; TODO: maint message?
if 1582 > tonumber (t.y) then -- ymd format dates not allowed before 1582
return;
end
t.m = string.format ('%02d', get_month_number (t.m)); -- make sure that month and day are two digits
t.d = string.format ('%02d', t.d);
elseif mon_len then -- if mon_len is set to either 'short' or 'long'
for _, mon in ipairs ({'m', 'm2'}) do -- because there can be two month names, check both
if t[mon] then
t[mon] = get_month_number (t[mon]); -- get the month number for this month (is length agnostic)
if 0 == t[mon] then return; end -- seasons and named dates can't be converted
t[mon] = (('s' == mon_len) and cfg.date_names['inv_local_short'][t[mon]]) or cfg.date_names['inv_local_long'][t[mon]]; -- fetch month name according to length
end
end
end
local new_date = string.format (re_formats[pattern_idx][format_param][1], -- format string
t[re_formats[pattern_idx][format_param][2]], -- named captures from t{}
t[re_formats[pattern_idx][format_param][3]],
t[re_formats[pattern_idx][format_param][4]],
t[re_formats[pattern_idx][format_param][5]],
t[re_formats[pattern_idx][format_param][6]],
t[re_formats[pattern_idx][format_param][7]],
t[re_formats[pattern_idx][format_param][8]]
);
return new_date;
end
--[[-------------------------< R E F O R M A T _ D A T E S >--------------------------------------------------
Reformats existing dates into the format specified by format.
format is one of several manual keywords: dmy, dmy-all, mdy, mdy-all, ymd, ymd-all. The -all version includes
access- and archive-dates; otherwise these dates are not reformatted.
This function allows automatic date formatting. In ~/Configuration, the article source is searched for one of
the {{use xxx dates}} templates. If found, xxx becomes the global date format as xxx-all. If |cs1-dates= in
{{use xxx dates}} has legitimate value then that value determines how cs1|2 dates will be rendered. Legitimate
values for |cs1-dates= are:
l - all dates are rendered with long month names
ls - publication dates use long month names; access-/archive-dates use abbreviated month names
ly - publication dates use long month names; access-/archive-dates rendered in ymd format
s - all dates are rendered with abbreviated (short) month names
sy - publication dates use abbreviated month names; access-/archive-dates rendered in ymd format
y - all dates are rendered in ymd format
the format argument for automatic date formatting will be the format specified by {{use xxx dates}} with the
value supplied by |cs1-dates so one of: xxx-l, xxx-ls, xxx-ly, xxx-s, xxx-sy, xxx-y, or simply xxx (|cs1-dates=
empty, omitted, or invalid) where xxx shall be either of dmy or mdy.
dates are extracted from date_parameters_list, reformatted (if appropriate), and then written back into the
list in the new format. Dates in date_parameters_list are presumed here to be valid (no errors). This function
returns true when a date has been reformatted, false else. Actual reformatting is done by reformatter().
]]
local function reformat_dates (date_parameters_list, format)
local all = false; -- set to false to skip access- and archive-dates
local len_p = 'l'; -- default publication date length shall be long
local len_a = 'l'; -- default access-/archive-date length shall be long
local result = false;
local new_date;
if format:match('%a+%-all') then -- manual df keyword; auto df keyword when length not specified in {{use xxx dates}};
format = format:match('(%a+)%-all'); -- extract the format
all = true; -- all dates are long format dates because this keyword doesn't specify length
elseif format:match('%a+%-[lsy][sy]?') then -- auto df keywords; internal only
all = true; -- auto df applies to all dates; use length specified by capture len_p for all dates
format, len_p, len_a = format:match('(%a+)%-([lsy])([sy]?)'); -- extract the format and length keywords
if 'y' == len_p then -- because allowed by MOS:DATEUNIFY (sort of) range dates and My dates not reformatted
format = 'ymd'; -- override {{use xxx dates}}
elseif (not is_set(len_a)) or (len_p == len_a) then -- no access-/archive-date length specified or same length as publication dates then
len_a = len_p; -- in case len_a not set
end
end -- else only publication dates and they are long
for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then -- if the parameter has a value
if not (not all and in_array (param_name, {'access-date', 'archive-date'})) then -- skip access- or archive-date unless format is xxx-all; yeah, ugly; TODO: find a better way
for pattern_idx, pattern in pairs (patterns_t) do
if mw.ustring.match (param_val.val, pattern[1]) then
if all and in_array (param_name, {'access-date', 'archive-date'}) then -- if this date is an access- or archive-date
new_date = reformatter (param_val.val, pattern_idx, (('y' == len_a) and 'ymd') or format, len_a); -- choose ymd or dmy/mdy according to len_a setting
else -- all other dates
new_date = reformatter (param_val.val, pattern_idx, format, len_p);
end
if new_date then -- set when date was reformatted
date_parameters_list[param_name].val = new_date; -- update date in date list
result = true; -- and announce that changes have been made
break;
end
end -- if
end -- for
end -- if
end -- if
end -- for
return result; -- declare boolean result and done
end
--[[--------------------------< D A T E _ H Y P H E N _ T O _ D A S H >----------------------------------------
Loops through the list of date-holding parameters and converts any hyphen to an ndash. Not called if the cs1|2
template has any date errors.
Modifies the date_parameters_list and returns true if hyphens are replaced, else returns false.
]]
local function date_hyphen_to_dash (date_parameters_list)
local result = false;
local n;
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) and
not mw.ustring.match (param_val.val, patterns_t.ymd[1]) then -- for those that are not ymd dates (ustring because here digits may not be Western)
param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash
if 0 ~= n then
date_parameters_list[param_name].val = param_val.val; -- update the list
result = true;
end
end
end
return result; -- so we know if any hyphens were replaced
end
--[[-------------------------< D A T E _ N A M E _ X L A T E >------------------------------------------------
Attempts to translate English date names to local-language date names using names supplied by MediaWiki's
date parser function. This is simple name-for-name replacement and may not work for all languages.
if xlat_dig is true, this function will also translate Western (English) digits to the local language's digits.
This will also translate ymd dates.
]]
local function date_name_xlate (date_parameters_list, xlt_dig)
local xlate;
local mode; -- long or short month names
local modified = false;
local date;
local sources_t = {
{cfg.date_names.en.long, cfg.date_names.inv_local_long}, -- for translating long English month names to long local month names
{cfg.date_names.en.short, cfg.date_names.inv_local_short}, -- short month names
{cfg.date_names.en.quarter, cfg.date_names.inv_local_quarter}, -- quarter date names
{cfg.date_names.en.season, cfg.date_names.inv_local_season}, -- season date nam
{cfg.date_names.en.named, cfg.date_names.inv_local_named}, -- named dates
}
local function is_xlateable (month) -- local function to get local date name that replaces existing English-language date name
for _, date_names_t in ipairs (sources_t) do -- for each sequence table in date_names_t
if date_names_t[1][month] then -- if date name is English month (long or short), quarter, season or named and
if date_names_t[2][date_names_t[1][month]] then -- if there is a matching local date name
return date_names_t[2][date_names_t[1][month]]; -- return the local date name
end
end
end
end
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set(param_val.val) then -- if the parameter has a value
date = param_val.val;
for month in mw.ustring.gmatch (date, '[%a ]+') do -- iterate through all date names in the date (single date or date range)
month = mw.text.trim (month); -- this because quarterly dates contain whitespace
xlate = is_xlateable (month); -- get translate <month>; returns translation or nil
if xlate then
date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
if xlt_dig then -- shall we also translate digits?
date = date:gsub ('%d', cfg.date_names.xlate_digits); -- translate digits from Western to 'local digits'
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
end
return modified;
end
--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------
Sets local imported functions table to same (live or sandbox) as that used by the other modules.
]]
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
add_prop_cat = utilities_page_ptr.add_prop_cat ; -- import functions from selected Module:Citation/CS1/Utilities module
is_set = utilities_page_ptr.is_set;
in_array = utilities_page_ptr.in_array;
set_message = utilities_page_ptr.set_message;
substitute = utilities_page_ptr.substitute;
wrap_style = utilities_page_ptr.wrap_style;
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration
end
--[[--------------------------< A R C H I V E _ D A T E _ C H E C K >------------------------------------------
Compare value in |archive-date= with the timestamp in Wayback machine urls. Emits an error message with suggested
date from the |archive-url= timestamp in an appropriate format when the value in |archive-date= does not match
the timestamp.
this function never called when any date in a cs1|2 template has errors
error message suggests new |archive-date= value in an appropriate format specified by <df>. <df> is either
|df= or cfg.global_df in that order. If <df> is nil, suggested date has format from |archive-date=. There is
a caveat: when |df=dmy or |df=mdy, the reformatter leaves |access-date= and |archive-date= formats as they are.
The error message suggested date is passed to the formatter as YYYY-MM-DD so when |df=dmy or |df=mdy, the format
is not changed.
]]
local function archive_date_check (archive_date, archive_url_timestamp, df)
local archive_date_format = 'dmy-y'; -- holds the date format of date in |archive-date; default to ymd; 'dmy' used here to spoof reformat_dates()
for _, v_t in ipairs ({{'dMy', 'dmy-all'}, {'Mdy', 'mdy-all'}}) do -- is |archive-date= format dmy or mdy?
if archive_date:match (patterns_t[v_t[1]][1]) then -- does the pattern match?
archive_date_format = cfg.keywords_xlate[v_t[2]]; -- get appropriate |df= supported keyword from the i18n translator table
break;
end
end
local dates_t = {};
dates_t['archive-date'] = {val=archive_date, name=''}; -- setup to call reformat_dates(); never called when errors so <name> unset as not needed
reformat_dates (dates_t, 'dmy-y'); -- reformat |archive-date= to ymd; 'dmy' used here to spoof reformat_dates()
local archive_url_date = archive_url_timestamp:gsub ('(%d%d%d%d)(%d%d)(%d%d)%d*', '%1-%2-%3'); -- make ymd format date from timestamp
if dates_t['archive-date'].val == archive_url_date then -- are the two dates the same
return; -- yes, done
else
dates_t['archive-date'] = {val=archive_url_date, name=''}; -- setup to call reformat_dates() with the timestamp date
reformat_dates (dates_t, df or archive_date_format); -- reformat timestamp to format specified by <df> or format used in |archive-date=
archive_url_date = dates_t['archive-date'].val;
set_message ('err_archive_date_url_ts_mismatch', archive_url_date); -- emit an error message
end
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return { -- return exported functions
archive_date_check = archive_date_check,
date_hyphen_to_dash = date_hyphen_to_dash,
date_name_xlate = date_name_xlate,
dates = dates,
is_valid_date = is_valid_date,
reformat_dates = reformat_dates,
set_selected_modules = set_selected_modules,
year_check = year_check,
year_date_check = year_date_check,
}
039z8dc7ugbbv8w4tsnejz5bfud8dgw
17615
17614
2026-03-29T16:41:12Z
YaThaWinTha
42
17615
Scribunto
text/plain
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
local add_prop_cat, is_set, in_array, wrap_style; -- imported functions from selected Module:Citation/CS1/Utilities
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
--[[--------------------------< F I L E - S C O P E D E C L A R A T I O N S >--------------------------------
File-scope variables are declared here
]]
local lang_object = mw.getContentLanguage(); -- used by is_valid_accessdate(), is_valid_year(), date_name_xlate(); TODO: move to ~/Configuration?
local year_limit; -- used by is_valid_year()
--[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >----------------------------------------
returns true if:
Wikipedia start date <= accessdate < today + 2 days
Wikipedia start date is 2001-01-15T00:00:00 UTC which is 979516800 seconds after 1970-01-01T00:00:00 UTC (the start of Unix time)
accessdate is the date provided in |access-date= at time 00:00:00 UTC
today is the current date at time 00:00:00 UTC plus 48 hours
if today is 2015-01-01T00:00:00 then
adding 24 hours gives 2015-01-02T00:00:00 – one second more than today
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow
This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
apparently doesn't understand non-English date month names. This function will always return false when the date
contains a non-English month name because good1 is false after the call to lang.formatDate(). To get around that
call this function with YYYY-MM-DD format dates.
]=]
local function is_valid_accessdate (accessdate)
local good1, good2;
local access_ts, tomorrow_ts; -- to hold Unix time stamps representing the dates
good1, access_ts = pcall (lang_object.formatDate, lang_object, 'U', accessdate ); -- convert accessdate value to Unix timestamp
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which which tonumber() may not understand
access_ts = tonumber (access_ts) or lang_object:parseFormattedNumber (access_ts); -- convert to numbers for the comparison;
tomorrow_ts = tonumber (tomorrow_ts) or lang_object:parseFormattedNumber (tomorrow_ts);
else
return false; -- one or both failed to convert to Unix time stamp
end
if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date
return true;
else
return false; -- accessdate out of range
end
end
--[[--------------------------< I S _ V A L I D _ E M B A R G O _ D A T E >------------------------------------
returns true and date value if that value has proper dmy, mdy, ymd format.
returns false and 9999 (embargoed forever) when date value is not proper format; assumes that when |pmc-embargo-date= is
set, the editor intended to embargo a PMC but |pmc-embargo-date= does not hold a single date.
]]
local function is_valid_embargo_date (v)
if v:match ('^%d%d%d%d%-%d%d%-%d%d$') or -- ymd
v:match ('^%d%d?%s+%a+%s+%d%d%d%d$') or -- dmy
v:match ('^%a+%s+%d%d?%s*,%s*%d%d%d%d$') then -- mdy
return true, v;
end
return false, '9999'; -- if here not good date so return false and set embargo date to long time in future
end
--[[--------------------------< G E T _ M O N T H _ N U M B E R >----------------------------------------------
returns a number according to the month in a date: 1 for January, etc. Capitalization and spelling must be correct.
If not a valid month, returns 0
]]
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
--[[--------------------------< G E T _ S E A S O N _ N U M B E R >--------------------------------------------
returns a number according to the sequence of seasons in a year: 21 for Spring, etc. Capitalization and spelling
must be correct. If not a valid season, returns 0.
21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere”
returns 0 when <param> is not |date=
Season numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons. EDTF does support the distinction between north and south
hemispere seasons but cs1|2 has no way to make that distinction.
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, param)
if 'date' ~= param then
return 0; -- season dates only supported by |date=
end
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
--[[--------------------------< G E T _ Q U A R T E R _ N U M B E R >------------------------------------------
returns a number according to the sequence of quarters in a year: 33 for first quarter, etc. Capitalization and spelling
must be correct. If not a valid quarter, returns 0.
33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each)
returns 0 when <param> is not |date=
Quarter numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons and quarters.
These additional divisions not currently supported:
37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each)
40-41 = Semestral 1, Semestral-2 (6 months each)
]]
local function get_quarter_number (quarter, param)
if 'date' ~= param then
return 0; -- quarter dates only supported by |date=
end
quarter = mw.ustring.gsub (quarter, ' +', ' '); -- special case replace multiple space chars with a single space char
return cfg.date_names['local'].quarter[quarter] or -- look for local names first
cfg.date_names['en'].quarter[quarter] or -- failing that, look for English names
0; -- not a recognized quarter name
end
--[[--------------------------< G E T _ P R O P E R _ N A M E _ N U M B E R >----------------------------------
returns a non-zero number if date contains a recognized proper-name. Capitalization and spelling must be correct.
returns 0 when <param> is not |date=
]]
local function get_proper_name_number (name, param)
if 'date' ~= param then
return 0; -- proper-name dates only supported by |date=
end
return cfg.date_names['local'].named[name] or -- look for local names dates first
cfg.date_names['en'].named[name] or -- failing that, look for English names
0; -- not a recognized named date
end
--[[--------------------------< G E T _ E L E M E N T _ N U M B E R <------------------------------------------
returns true if month or season or quarter or proper name is valid (properly spelled, capitalized, abbreviated)
]]
local function get_element_number (element, param)
local num;
local funcs = {get_month_number, get_season_number, get_quarter_number, get_proper_name_number}; -- list of functions to execute in order
for _, func in ipairs (funcs) do -- spin through the function list
num = func (element, param); -- call the function and get the returned number
if 0 ~= num then -- non-zero when valid month season quarter
return num; -- return that number
end
end
return nil; -- not valid
end
--[[--------------------------< I S _ V A L I D _ Y E A R >----------------------------------------------------
Function gets current year from the server and compares it to year from a citation parameter. Years more than one
year in the future are not acceptable.
]]
local function is_valid_year (year)
if not is_set(year_limit) then
year_limit = tonumber(os.date("%Y"))+1; -- global variable so we only have to fetch it once
end
year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to numbers for the comparison;
return year and (year <= year_limit) or false;
end
--[[--------------------------< I S _ V A L I D _ D A T E >----------------------------------------------------
Returns true if day is less than or equal to the number of days in month and year is no farther into the future
than next year; 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.
]]
local 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 not is_valid_year(year) then -- no farther into the future than next year
return false;
end
month = tonumber(month); -- required for YYYY-MM-DD dates
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 -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
else -- Gregorian calendar
if (0 == (year%4) and (0 ~= (year%100) or 0 == (year%400))) then -- is 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
--[[--------------------------< I S _ V A L I D _ M O N T H _ R A N G E _ S T Y L E >--------------------------
Months in a range are expected to have the same style: Jan–Mar or October–December but not February–Mar or Jul–August.
There is a special test for May because it can be either short or long form.
Returns true when style for both months is the same
]]
local function is_valid_month_range_style (month1, month2)
local len1 = month1:len();
local len2 = month2:len();
if len1 == len2 then
return true; -- both months are short form so return true
elseif 'May' == month1 or 'May'== month2 then -- ToDo: I18N
return true; -- both months are long form so return true
elseif 3 == len1 or 3 == len2 then
return false; -- months are mixed form so return false
else
return true; -- both months are long form so return true
end
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ S E A S O N _ R A N G E >------------------------
Check a pair of months or seasons to see if both are valid members of a month or season pair.
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, hence treat as ok
]]
local function is_valid_month_season_range(range_start, range_end, param)
local range_start_number = get_month_number (range_start);
local range_end_number;
if 0 == range_start_number then -- is this a month range?
range_start_number = get_season_number (range_start, param); -- not a month; is it a season? get start season number
range_end_number = get_season_number (range_end, param); -- get end season number
if (0 ~= range_start_number) and (0 ~= range_end_number) and (range_start_number ~= range_end_number) then
return true; -- any season pairing is accepted except when both are the same
end
return false; -- range_start and/or range_end is not a season
end
-- here when range_start is a month
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 is_valid_month_range_style (range_start, range_end) then -- do months have the same style?
return true; -- proper order and same style
end
end
return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month
end
--[[--------------------------< M A K E _ C O I N S _ D A T E >------------------------------------------------
This function receives a table of date parts for one or two dates and an empty table reference declared in
Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is
determined to be a valid date format. The question of what to do with invalid date formats is not answered here.
The date parts in the input table are converted to an ISO 8601 conforming date string:
single whole dates: yyyy-mm-dd
month and year dates: yyyy-mm
year dates: yyyy
ranges: yyyy-mm-dd/yyyy-mm-dd
yyyy-mm/yyyy-mm
yyyy/yyyy
Dates in the Julian calendar are reduced to year or year/year so that we don't have to do calendar conversion from
Julian to Proleptic Gregorian.
The input table has:
year, year2 – always present; if before 1582, ignore months and days if present
month, month2 – 0 if not provided, 1-12 for months, 21-24 for seasons; 99 Christmas
day, day2 – 0 if not provided, 1-31 for days
the output table receives:
rftdate: an ISO 8601 formatted date
rftchron: a free-form version of the date, usually without year which is in rftdate (season ranges and proper-name dates)
rftssn: one of four season keywords: winter, spring, summer, fall (lowercase)
rftquarter: one of four values: 1, 2, 3, 4
]]
local function make_COinS_date (input, tCOinS_date)
local date; -- one date or first date in a range
local date2 = ''; -- end of range date
-- start temporary Julian / Gregorian calendar uncertainty detection
local year = tonumber(input.year); -- this temporary code to determine the extent of sources dated to the Julian/Gregorian
local month = tonumber(input.month); -- interstice 1 October 1582 – 1 January 1926
local day = tonumber (input.day);
if (0 ~= day) and -- day must have a value for this to be a whole date
(((1582 == year) and (10 <= month) and (12 >= month)) or -- any whole 1582 date from 1 October to 31 December or
((1926 == year) and (1 == month) and (1 == input.day)) or -- 1 January 1926 or
((1582 < year) and (1925 >= year))) then -- any date 1 January 1583 – 31 December 1925
tCOinS_date.inter_cal_cat = true; -- set category flag true
end
-- end temporary Julian / Gregorian calendar uncertainty detection
if 1582 > tonumber(input.year) or 20 < tonumber(input.month) then -- Julian calendar or season so &rft.date gets year only
date = input.year;
if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year
date = string.format ('%.4d/%.4d', tonumber(input.year), tonumber(input.year2)) -- assemble the date range
end
if 20 < tonumber(input.month) then -- if season or proper-name date
local season = {[24] = 'winter', [21] = 'spring', [22] = 'summer', [23] = 'fall', [33] = '1', [34] = '2', [35] = '3', [36] = '4', [98] = 'Easter', [99] = 'Christmas'}; -- seasons lowercase, no autumn; proper-names use title case
if 0 == input.month2 then -- single season date
if 40 < tonumber(input.month) then
tCOinS_date.rftchron = season[input.month]; -- proper-name dates
elseif 30 < tonumber(input.month) then
tCOinS_date.rftquarter = season[input.month]; -- quarters
else
tCOinS_date.rftssn = season[input.month]; -- seasons
end
else -- season range with a second season specified
if input.year ~= input.year2 then -- season year – season year range or season year–year
tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
if 0~= input.month2 then
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2);
end
else -- season–season year range
tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range
end
end
end
tCOinS_date.rftdate = date;
return; -- done
end
if 0 ~= input.day then
date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date
elseif 0 ~= input.month then
date = string.format ('%s-%.2d', input.year, tonumber(input.month)); -- year and month
else
date = string.format ('%s', input.year); -- just year
end
if 0 ~= input.year2 then
if 0 ~= input.day2 then
date2 = string.format ('/%s-%.2d-%.2d', input.year2, tonumber(input.month2), tonumber(input.day2)); -- whole date
elseif 0 ~= input.month2 then
date2 = string.format ('/%s-%.2d', input.year2, tonumber(input.month2)); -- year and month
else
date2 = string.format ('/%s', input.year2); -- just year
end
end
tCOinS_date.rftdate = date .. date2; -- date2 has the '/' separator
return;
end
--[[--------------------------< P A T T E R N S >--------------------------------------------------------------
this is the list of patterns for date formats that this module recognizes. Approximately the first half of these
patterns represent formats that might be reformatted into another format. Those that might be reformatted have
'indicator' letters that identify the content of the matching capture: 'd' (day), 'm' (month), 'a' (anchor year),
'y' (year); second day, month, year have a '2' suffix.
These patterns are used for both date validation and for reformatting. This table should not be moved to ~/Configuration
because changes to this table require changes to check_date() and to reformatter() and reformat_date()
]]
local patterns = {
-- year-initial numerical year-month-day
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'},
-- month-initial: month day, year
['Mdy'] = {'^(%D-) +([1-9]%d?), +((%d%d%d%d?)%a?)$', 'm', 'd', 'a', 'y'},
-- month-initial day range: month day–day, year; days are separated by endash
['Md-dy'] = {'^(%D-) +([1-9]%d?)[%-–]([1-9]%d?), +((%d%d%d%d)%a?)$', 'm', 'd', 'd2', 'a', 'y'},
-- day-initial: day month year
['dMy'] = {'^([1-9]%d?) +(%D-) +((%d%d%d%d?)%a?)$', 'd', 'm', 'a', 'y'},
-- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed; not supported at en.wiki
-- ['yMd'] = {'^((%d%d%d%d?)%a?) +(%D-) +(%d%d?)$', 'a', 'y', 'm', 'd'},
-- day-range-initial: day–day month year; days are separated by endash
['d-dMy'] = {'^([1-9]%d?)[%-–]([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'd2', 'm', 'a', 'y'},
-- day initial month-day-range: day month - day month year; uses spaced endash
['dM-dMy'] = {'^([1-9]%d?) +(%D-) +[%-–] +([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'm', 'd2', 'm2', 'a', 'y'},
-- month initial month-day-range: month day – month day, year; uses spaced endash
['Md-Mdy'] = {'^(%D-) +([1-9]%d?) +[%-–] +(%D-) +([1-9]%d?), +((%d%d%d%d)%a?)$','m', 'd', 'm2', 'd2', 'a', 'y'},
-- day initial month-day-year-range: day month year - day month year; uses spaced endash
['dMy-dMy'] = {'^([1-9]%d?) +(%D-) +(%d%d%d%d) +[%-–] +([1-9]%d?) +(%D-) +((%d%d%d%d)%a?)$', 'd', 'm', 'y', 'd2', 'm2', 'a', 'y2'},
-- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
['Mdy-Mdy'] = {'^(%D-) +([1-9]%d?), +(%d%d%d%d) +[%-–] +(%D-) +([1-9]%d?), +((%d%d%d%d)%a?)$', 'm', 'd', 'y', 'm2', 'd2', 'a', 'y2'},
-- these date formats cannot be converted, per se, but month name can be rendered short or long
-- month/season year - month/season year; separated by spaced endash
['My-My'] = {'^(%D-) +(%d%d%d%d) +[%-–] +(%D-) +((%d%d%d%d)%a?)$', 'm', 'y', 'm2', 'a', 'y2'},
-- month/season range year; months separated by endash
['M-My'] = {'^(%D-)[%-–](%D-) +((%d%d%d%d)%a?)$', 'm', 'm2', 'a', 'y'},
-- month/season year or proper-name year; quarter year when First Quarter YYYY etc.
['My'] = {'^([^%d–]-) +((%d%d%d%d)%a?)$', 'm', 'a', 'y'}, -- this way because endash is a member of %D; %D- will match January–March 2019 when it shouldn't
-- these date formats cannot be converted
['Sy4-y2'] = {'^(%D-) +((%d%d)%d%d)[%-–]((%d%d)%a?)$'}, -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
['Sy-y'] = {'^(%D-) +(%d%d%d%d)[%-–]((%d%d%d%d)%a?)$'}, -- special case Winter/Summer year-year; year separated with unspaced endash
['y-y'] = {'^(%d%d%d%d?)[%-–]((%d%d%d%d?)%a?)$'}, -- year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
['y4-y2'] = {'^((%d%d)%d%d)[%-–]((%d%d)%a?)$'}, -- year range: YYYY–YY; separated by unspaced endash
['y'] = {'^((%d%d%d%d?)%a?)$'}, -- year; here accept either YYY or YYYY
}
--[[--------------------------< C H E C K _ D A T E >----------------------------------------------------------
Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only
allowed range separator is endash. 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. Future years beyond next year are not allowed.
If the date fails the format tests, this function returns false and does not return values for anchor_year and
COinS_date. When this happens, the date parameter is (DEBUG: not?) used in the COinS metadata and the CITEREF identifier gets
its year from the year parameter if present otherwise CITEREF does not get a date value.
Inputs:
date_string - date string from date-holding parameters (date, year, publication-date, access-date, pmc-embargo-date, archive-date, lay-date)
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 ISO 8601 format date; see make_COInS_date()
]]
local function check_date (date_string, param, tCOinS_date)
local year; -- assume that year2, months, and days are not used;
local year2 = 0; -- second year in a year range
local month = 0;
local month2 = 0; -- second month in a month range
local day = 0;
local day2 = 0; -- second day in a day range
local anchor_year;
local coins_date;
if date_string:match (patterns['ymd'][1]) then -- year-initial numerical year month day format
year, month, day = date_string:match (patterns['ymd'][1]);
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;
elseif mw.ustring.match(date_string, patterns['Mdy'][1]) then -- month-initial: month day, year
month, day, anchor_year, year = mw.ustring.match(date_string, patterns['Mdy'][1]);
month = get_month_number (month);
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, patterns['Md-dy'][1]) then -- month-initial day range: month day–day, year; days are separated by endash
month, day, day2, anchor_year, year = mw.ustring.match(date_string, patterns['Md-dy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2=month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns['dMy'][1]) then -- day-initial: day month year
day, month, anchor_year, year = mw.ustring.match(date_string, patterns['dMy'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
--[[ NOT supported at en.wiki
elseif mw.ustring.match(date_string, patterns['yMd'][1]) then -- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed
anchor_year, year, month, day = mw.ustring.match(date_string, patterns['yMd'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
-- end NOT supported at en.wiki ]]
elseif mw.ustring.match(date_string, patterns['d-dMy'][1]) then -- day-range-initial: day–day month year; days are separated by endash
day, day2, month, anchor_year, year = mw.ustring.match(date_string, patterns['d-dMy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2 = month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns['dM-dMy'][1]) then -- day initial month-day-range: day month - day month year; uses spaced endash
day, month, day2, month2, anchor_year, year = mw.ustring.match(date_string, patterns['dM-dMy'][1]);
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end -- date range order is left to right: earlier to later;
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns['Md-Mdy'][1]) 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, patterns['Md-Mdy'][1]);
if (not is_valid_month_season_range(month, month2, param)) or not is_valid_year(year) then return false; end
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns['dMy-dMy'][1]) 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, patterns['dMy-dMy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns['Mdy-Mdy'][1]) then -- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
month, day, year, month2, day2, anchor_year, year2 = mw.ustring.match(date_string, patterns['Mdy-Mdy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns['Sy4-y2'][1]) then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
local century;
month, year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['Sy4-y2'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
year2 = century..year2; -- add the century to year2 for comparisons
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number(month, param);
elseif mw.ustring.match(date_string, patterns['Sy-y'][1]) then -- special case Winter/Summer year-year; year separated with unspaced endash
month, year, anchor_year, year2 = mw.ustring.match(date_string, patterns['Sy-y'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number (month, param); -- for metadata
elseif mw.ustring.match(date_string, patterns['My-My'][1]) then -- month/season year - month/season year; separated by spaced endash
month, year, month2, anchor_year, year2 = mw.ustring.match(date_string, patterns['My-My'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if 0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2) then -- both must be month year, same month style
month = get_month_number(month);
month2 = get_month_number(month2);
elseif 0 ~= get_season_number(month, param) and 0 ~= get_season_number(month2, param) then -- both must be season year, not mixed
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
else
return false;
end
elseif mw.ustring.match(date_string, patterns['M-My'][1]) then -- month/season range year; months separated by endash
month, month2, anchor_year, year = mw.ustring.match(date_string, patterns['M-My'][1]);
if (not is_valid_month_season_range(month, month2, param)) or (not is_valid_year(year)) then return false; end
if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
month = get_month_number(month);
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end
else
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
end
year2 = year;
elseif mw.ustring.match(date_string, patterns['My'][1]) then -- month/season/quarter/proper-name year
month, anchor_year, year = mw.ustring.match(date_string, patterns['My'][1]);
if not is_valid_year(year) then return false; end
month = get_element_number(month, param); -- get month season quarter proper-name number or nil
if not month then return false; end -- not valid whatever it is
elseif mw.ustring.match(date_string, patterns['y-y'][1]) then -- Year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
year, anchor_year, year2 = mw.ustring.match(date_string, patterns['y-y'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns['y4-y2'][1]) then -- Year range: YYYY–YY; separated by unspaced endash
local century;
year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['y4-y2'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if in_array (param, {'date', 'publication-date', 'year'}) then
add_prop_cat ('year_range_abbreviated');
end
if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003
year2 = century .. year2; -- add the century to year2 for comparisons
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns['y'][1]) then -- year; here accept either YYY or YYYY
anchor_year, year = mw.ustring.match(date_string, patterns['y'][1]);
if false == is_valid_year(year) then
return false;
end
else
return false; -- date format not one of the MOS:DATE approved formats
end
if 'access-date' == param then -- test accessdate here because we have numerical date parts
if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2 then -- none of these; accessdate must not be a range
if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then
return false; -- return false when accessdate out of bounds
end
else
return false; -- return false when accessdate is a range of two dates
end
end
local result=true; -- check whole dates for validity; assume true because not all dates will go through this test
if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date)
result = is_valid_date(year, month, day);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 ~= day2 then -- YMD-d (day range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year, month, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-md (day month range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year, month2, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 ~= year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-ymd (day month year range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year2, month2, day2);
end
if false == result then return false; end
if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values
make_COinS_date ({year = year, month = month, day = day, year2 = year2, month2 = month2, day2 = day2}, tCOinS_date); -- make an ISO 8601 date string for COinS
end
return true, anchor_year; -- format is good and date string represents a real date
end
--[[--------------------------< D A T E S >--------------------------------------------------------------------
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. The |date= parameter test is unique, it is the only date holding parameter from which values for anchor_year (used in CITEREF identifiers) and COinS_date (used in
the COinS metadata) are derived. The |date= parameter 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,
parameters with errors are added to the <error_list> sequence table as the dates are tested.
]]
local function dates(date_parameters_list, tCOinS_date, error_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 embargo_date; -- if embargo date is a good dmy, mdy, ymd date then holds original value else reset to 9999
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.val) then -- if the parameter has a value
v.val = mw.ustring.gsub(v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9
if v.val:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
local year = v.val:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested
if 'date' == k then
anchor_year, COinS_date = v.val:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
good_date = is_valid_year(year);
elseif 'year' == k then
good_date = is_valid_year(year);
end
elseif 'date' == k then -- if the parameter is |date=
if v.val:match("^n%.d%.%a?$") then -- ToDo: I18N -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((n%.d%.)%a?)"); -- ToDo: I18N -- "n.d."; no error when date parameter is set to no date
elseif v.val:match("^nd%a?$") then -- ToDo: I18N -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((nd)%a?)"); -- ToDo: I18N -- "nd"; no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v.val, k, tCOinS_date); -- go test the date
end
elseif 'year' == k then -- if the parameter is |year= it should hold only a year value
if v.val:match("^[1-9]%d%d%d?%a?$") then -- if |year = 3 or 4 digits only with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)");
end
elseif 'pmc-embargo-date' == k then -- if the parameter is |pmc-embargo-date=
good_date = check_date (v.val, k); -- go test the date
if true == good_date then -- if the date is a valid date
good_date, embargo_date = is_valid_embargo_date (v.val); -- is |pmc-embargo-date= date a single dmy, mdy, or ymd formatted date? yes: returns embargo; no: returns 9999
end
else -- any other date-holding parameter
good_date = check_date (v.val, k); -- go test the date
end
if false == good_date then -- assemble one error message so we don't add the tracking category multiple times
table.insert (error_list, wrap_style ('parameter', v.name)); -- make parameter name suitable for error message list
end
end
end
return anchor_year, embargo_date; -- and done
end
--[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------
Compare the value provided in |year= with the year value(s) provided in |date=. This function returns a numeric value:
0 - year value does not match the year value in date
1 - (default) year value matches the year value in date or one of the year values when date contains two years
2 - year value matches the year value in date when date is in the form YYYY-MM-DD and year is disambiguated (|year=YYYYx)
]]
local function year_date_check (year_string, date_string)
local year;
local date1;
local date2;
local result = 1; -- result of the test; assume that the test passes
year = year_string:match ('(%d%d%d%d?)');
if date_string:match ('%d%d%d%d%-%d%d%-%d%d') and year_string:match ('%d%d%d%d%a') then --special case where both date and year are required YYYY-MM-DD and YYYYx
date1 = date_string:match ('(%d%d%d%d)');
year = year_string:match ('(%d%d%d%d)');
if year ~= date1 then
result = 0; -- years don't match
else
result = 2; -- years match; but because disambiguated, don't add to maint cat
end
elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard range formats of date with two three- or four-digit years
date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)");
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif mw.ustring.match(date_string, "%d%d%d%d[%-–]%d%d") then -- YYYY-YY date ranges
local century;
date1, century, date2 = mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]+(%d%d)");
date2 = century..date2; -- convert YY to YYYY
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif date_string:match ("%d%d%d%d?") then -- any of the standard formats of date with one year
date1 = date_string:match ("(%d%d%d%d?)");
if year ~= date1 then
result = 0;
end
else
result = 0; -- no recognizable year in date
end
return result;
end
--[[--------------------------< R E F O R M A T T E R >--------------------------------------------------------
reformat 'date' into new format specified by format_param if pattern_idx (the current format of 'date') can be
reformatted. Does the grunt work for reformat_dates().
The table re_formats maps pattern_idx (current format) and format_param (desired format) to a table that holds:
format string used by string.format()
identifier letters ('d', 'm', 'y', 'd2', 'm2', 'y2') that serve as indexes into a table t{} that holds captures
from mw.ustring.match() for the various date parts specified by patterns[pattern_idx][1]
Items in patterns{} have the general form:
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'}, where:
['ymd'] is pattern_idx
patterns['ymd'][1] is the match pattern with captures for mw.ustring.match()
patterns['ymd'][2] is an indicator letter identifying the content of the first capture
patterns['ymd'][3] ... the second capture etc.
when a pattern matches a date, the captures are loaded into table t{} in capture order using the idemtifier
characters as indexes into t{} For the above, a ymd date is in t{} as:
t.y = first capture (year), t.m = second capture (month), t.d = third capture (day)
To reformat, this function is called with the pattern_idx that matches the current format of the date and with
format_param set to the desired format. This function loads table t{} as described and then calls string.format()
with the format string specified by re_format[pattern_idx][format_param][1] using values taken from t{} according
to the capture identifier letters specified by patterns[pattern_idx][format_param][n] where n is 2..
]]
local re_formats = {
['ymd'] = { -- date format is ymd; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Mdy'] = { -- date format is Mdy; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['dMy'] = { -- date format is dMy; reformat to:
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Md-dy'] = { -- date format is Md-dy; reformat to:
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- |df=dmy -> d-dMy
},
['d-dMy'] = { -- date format is d-d>y; reformat to:
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- |df=mdy -> Md-dy
},
['dM-dMy'] = { -- date format is dM-dMy; reformat to:
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- |df=mdy -> Md-Mdy
},
['Md-Mdy'] = { -- date format is Md-Mdy; reformat to:
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- |df=dmy -> dM-dMy
},
['dMy-dMy'] = { -- date format is dMy-dMy; reformat to:
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- |df=mdy -> Mdy-Mdy
},
['Mdy-Mdy'] = { -- date format is Mdy-Mdy; reformat to:
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- for long/short reformatting
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- |df=dmy -> dMy-dMy
},
['My-My'] = { -- these for long/short reformatting
['any'] = {'%s %s – %s %s', 'm', 'y', 'm2', 'y2'}, -- dmy/mdy agnostic
},
['M-My'] = { -- these for long/short reformatting
['any'] = {'%s–%s %s', 'm', 'm2', 'y'}, -- dmy/mdy agnostic
},
['My'] = { -- these for long/short reformatting
['any'] = {'%s %s', 'm', 'y'}, -- dmy/mdy agnostic
},
-- ['yMd'] = { -- not supported at en.wiki
-- ['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
-- ['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- },
}
local function reformatter (date, pattern_idx, format_param, mon_len)
if not in_array (pattern_idx, {'ymd', 'Mdy', 'Md-dy', 'dMy', 'yMd', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- not in this set of date format patterns then not a reformattable date
end
if 'ymd' == format_param and in_array (pattern_idx, {'ymd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- ymd date ranges not supported at en.wiki; no point in reformatting ymd to ymd
end
if in_array (pattern_idx, {'My', 'M-My', 'My-My'}) then -- these are not dmy/mdy so can't be 'reformatted' into either
format_param = 'any'; -- so format-agnostic
end
-- yMd is not supported at en.wiki
-- if yMd is supported at your wiki, uncomment the next line
-- if 'yMd' == format_param and in_array (pattern_idx, {'yMd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy'}) then -- these formats not convertable; yMd not supported at en.wiki
-- if yMd is supported at your wiki, remove or comment-out the next line
if 'yMd' == format_param then -- yMd not supported at en.wiki
return; -- not a reformattable date
end
local c1, c2, c3, c4, c5, c6, c7; -- these hold the captures specified in patterns[pattern_idx][1]
c1, c2, c3, c4, c5, c6, c7 = mw.ustring.match (date, patterns[pattern_idx][1]); -- get the captures
local t = { -- table that holds k/v pairs of date parts from the captures and patterns[pattern_idx][2..]
[patterns[pattern_idx][2]] = c1; -- at minimum there is always one capture with a matching indicator letter
[patterns[pattern_idx][3] or 'x'] = c2; -- patterns can have a variable number of captures; each capture requires an indicator letter;
[patterns[pattern_idx][4] or 'x'] = c3; -- where there is no capture, there is no indicator letter so n in patterns[pattern_idx][n] will be nil;
[patterns[pattern_idx][5] or 'x'] = c4; -- the 'x' here spoofs an indicator letter to prevent 'table index is nil' error
[patterns[pattern_idx][6] or 'x'] = c5;
[patterns[pattern_idx][7] or 'x'] = c6;
[patterns[pattern_idx][8] or 'x'] = c7;
};
if t.a then -- if this date has an anchor year capture
t.y = t.a; -- use the anchor year capture when reassembling the date
end
if tonumber(t.m) then -- if raw month is a number (converting from ymd)
if 's' == mon_len then -- if we are to use abbreviated month names
t.m = cfg.date_names['inv_local_s'][tonumber(t.m)]; -- convert it to a month name
else
t.m = cfg.date_names['inv_local_l'][tonumber(t.m)]; -- convert it to a month name
end
t.d = t.d:gsub ('0(%d)', '%1'); -- strip leading '0' from day if present
elseif 'ymd' == format_param then -- when converting to ymd
if 1582 > tonumber(t.y) then -- ymd format dates not allowed before 1582
return;
end
t.m = string.format ('%02d', get_month_number (t.m)); -- make sure that month and day are two digits
t.d = string.format ('%02d', t.d);
elseif mon_len then -- if mon_len is set to either 'short' or 'long'
for _, mon in ipairs ({'m', 'm2'}) do -- because there can be two month names, check both
if t[mon] then
t[mon] = get_month_number (t[mon]); -- get the month number for this month (is length agnostic)
if 0 == t[mon] then return; end -- seasons and named dates can't be converted
t[mon] = (('s' == mon_len) and cfg.date_names['inv_local_s'][t[mon]]) or cfg.date_names['inv_local_l'][t[mon]]; -- fetch month name according to length
end
end
end
local new_date = string.format (re_formats[pattern_idx][format_param][1], -- format string
t[re_formats[pattern_idx][format_param][2]], -- named captures from t{}
t[re_formats[pattern_idx][format_param][3]],
t[re_formats[pattern_idx][format_param][4]],
t[re_formats[pattern_idx][format_param][5]],
t[re_formats[pattern_idx][format_param][6]],
t[re_formats[pattern_idx][format_param][7]],
t[re_formats[pattern_idx][format_param][8]]
);
return new_date;
end
--[[-------------------------< R E F O R M A T _ D A T E S >--------------------------------------------------
Reformats existing dates into the format specified by format.
format is one of several manual keywords: dmy, dmy-all, mdy, mdy-all, ymd, ymd-all. The -all version includes
access- and archive-dates; otherwise these dates are not reformatted.
This function allows automatic date formatting. In ~/Configuration, the article source is searched for one of
the {{use xxx dates}} templates. If found, xxx becomes the global date format as xxx-all. If |cs1-dates= in
{{use xxx dates}} has legitimate value then that value determines how cs1|2 dates will be rendered. Legitimate
values for |cs1-dates= are:
l - all dates are rendered with long month names
ls - publication dates use long month names; access-/archive-dates use abbreviated month names
ly - publication dates use long month names; access-/archive-dates rendered in ymd format
s - all dates are rendered with abbreviated (short) month names
sy - publication dates use abbreviated month names; access-/archive-dates rendered in ymd format
y - all dates are rendered in ymd format
the format argument for automatic date formatting will be the format specified by {{use xxx dates}} with the
value supplied by |cs1-dates so one of: xxx-l, xxx-ls, xxx-ly, xxx-s, xxx-sy, xxx-y, or simply xxx (|cs1-dates=
empty, omitted, or invalid) where xxx shall be either of dmy or mdy.
dates are extracted from date_parameters_list, reformatted (if appropriate), and then written back into the
list in the new format. Dates in date_parameters_list are presumed here to be valid (no errors). This function
returns true when a date has been reformatted, false else. Actual reformatting is done by reformatter().
]]
local function reformat_dates (date_parameters_list, format)
local all = false; -- set to false to skip access- and archive-dates
local len_p = 'l'; -- default publication date length shall be long
local len_a = 'l'; -- default access-/archive-date length shall be long
local result = false;
local new_date;
if format:match('%a+%-all') then -- manual df keyword; auto df keyword when length not specified in {{use xxx dates}};
format = format:match('(%a+)%-all'); -- extract the format
all = true; -- all dates are long format dates because this keyword doesn't specify length
elseif format:match('%a+%-[lsy][sy]?') then -- auto df keywords; internal only
all = true; -- auto df applies to all dates; use length specified by capture len_p for all dates
format, len_p, len_a = format:match('(%a+)%-([lsy])([sy]?)'); -- extract the format and length keywords
if 'y' == len_p then -- because allowed by MOS:DATEUNIFY (sort of) range dates and My dates not reformatted
format = 'ymd'; -- override {{use xxx dates}}
elseif (not is_set(len_a)) or (len_p == len_a) then -- no access-/archive-date length specified or same length as publication dates then
len_a = len_p; -- in case len_a not set
end
end -- else only publication dates and they are long
for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then -- if the parameter has a value
if not (not all and in_array (param_name, {'access-date', 'archive-date'})) then -- skip access- or archive-date unless format is xxx-all; yeah, ugly; TODO: find a better way
for pattern_idx, pattern in pairs (patterns) do
if mw.ustring.match (param_val.val, pattern[1]) then
if all and in_array (param_name, {'access-date', 'archive-date'}) then -- if this date is an access- or archive-date
new_date = reformatter (param_val.val, pattern_idx, (('y' == len_a) and 'ymd') or format, len_a); -- choose ymd or dmy/mdy according to len_a setting
else -- all other dates
new_date = reformatter (param_val.val, pattern_idx, format, len_p);
end
if new_date then -- set when date was reformatted
date_parameters_list[param_name].val = new_date; -- update date in date list
result = true; -- and announce that changes have been made
end
end -- if
end -- for
end -- if
end -- if
end -- for
return result; -- declare boolean result and done
end
--[[--------------------------< D A T E _ H Y P H E N _ T O _ D A S H >----------------------------------------
Loops through the list of date-holding parameters and converts any hyphen to an ndash. Not called if the cs1|2
template has any date errors.
Modifies the date_parameters_list and returns true if hyphens are replaced, else returns false.
]]
local function date_hyphen_to_dash (date_parameters_list)
local result = false;
local n;
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then
if not mw.ustring.match (param_val.val, '%d%d%d%d%-%d%d%-%d%d') then -- for those that are not ymd dates (ustring because here digits may not be Western)
param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash
if 0 ~= n then
date_parameters_list[param_name].val = param_val.val; -- update the list
result = true;
end
end
end
end
return result; -- so we know if any hyphens were replaced
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.
if xlat_dig is true, this function will also translate Western (English) digits to the local language's digits.
This will also translate ymd dates.
]]
local function date_name_xlate (date_parameters_list, xlt_dig)
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.val) then -- if the parameter has a value
date = param_val.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 = lang_object: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].val = date; -- save the translated date
modified = true;
end
end
if xlt_dig then -- shall we also translate digits?
date = date:gsub ('%d', cfg.date_names.xlate_digits); -- translate digits from Western to 'local digits'
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
end
return modified;
end
--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------
Sets local imported functions table to same (live or sandbox) as that used by the other modules.
]]
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
add_prop_cat = utilities_page_ptr.add_prop_cat ; -- import functions from selected Module:Citation/CS1/Utilities module
is_set = utilities_page_ptr.is_set;
in_array = utilities_page_ptr.in_array;
-- set_message = utilities_page_ptr.set_message;
wrap_style = utilities_page_ptr.wrap_style;
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return { -- return exported functions
dates = dates,
year_date_check = year_date_check,
reformat_dates = reformat_dates,
date_hyphen_to_dash = date_hyphen_to_dash,
date_name_xlate = date_name_xlate,
set_selected_modules = set_selected_modules
}
ds0l4tghd9b1ze47i4ysqzmmocnzkhm
17616
17615
2026-03-29T16:41:57Z
YaThaWinTha
42
17616
Scribunto
text/plain
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
local add_prop_cat, is_set, in_array, set_message, substitute, wrap_style; -- imported functions from selected Module:Citation/CS1/Utilities
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
--[[--------------------------< F I L E - S C O P E D E C L A R A T I O N S >--------------------------------
File-scope variables are declared here
]]
local lang_object = mw.getContentLanguage(); -- used by is_valid_accessdate(), is_valid_year(), date_name_xlate(); TODO: move to ~/Configuration?
local year_limit; -- used by is_valid_year()
--[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >----------------------------------------
returns true if:
Wikipedia start date <= accessdate < today + 2 days
Wikipedia start date is 2001-01-15T00:00:00 UTC which is 979516800 seconds after 1970-01-01T00:00:00 UTC (the start of Unix time)
accessdate is the date provided in |access-date= at time 00:00:00 UTC
today is the current date at time 00:00:00 UTC plus 48 hours
if today is 2015-01-01T00:00:00 then
adding 24 hours gives 2015-01-02T00:00:00 – one second more than today
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow
This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
apparently doesn't understand non-English date month names. This function will always return false when the date
contains a non-English month name because good1 is false after the call to lang.formatDate(). To get around that
call this function with YYYY-MM-DD format dates.
]=]
local function is_valid_accessdate (accessdate)
local good1, good2;
local access_ts, tomorrow_ts; -- to hold Unix time stamps representing the dates
good1, access_ts = pcall (lang_object.formatDate, lang_object, 'U', accessdate ); -- convert accessdate value to Unix timestamp
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which which tonumber() may not understand
access_ts = tonumber (access_ts) or lang_object:parseFormattedNumber (access_ts); -- convert to numbers for the comparison;
tomorrow_ts = tonumber (tomorrow_ts) or lang_object:parseFormattedNumber (tomorrow_ts);
else
return false; -- one or both failed to convert to Unix time stamp
end
if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date
return true;
else
return false; -- accessdate out of range
end
end
--[[--------------------------< G E T _ M O N T H _ N U M B E R >----------------------------------------------
returns a number according to the month in a date: 1 for January, etc. Capitalization and spelling must be correct.
If not a valid month, returns 0
]]
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
--[[--------------------------< G E T _ S E A S O N _ N U M B E R >--------------------------------------------
returns a number according to the sequence of seasons in a year: 21 for Spring, etc. Capitalization and spelling
must be correct. If not a valid season, returns 0.
21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere”
returns 0 when <param> is not |date=
Season numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons. EDTF does support the distinction between north and south
hemisphere seasons but cs1|2 has no way to make that distinction.
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, param)
if 'date' ~= param then
return 0; -- season dates only supported by |date=
end
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
--[[--------------------------< G E T _ Q U A R T E R _ N U M B E R >------------------------------------------
returns a number according to the sequence of quarters in a year: 33 for first quarter, etc. Capitalization and spelling
must be correct. If not a valid quarter, returns 0.
33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each)
returns 0 when <param> is not |date=
Quarter numbering is defined by Extended Date/Time Format (EDTF) specification (https://www.loc.gov/standards/datetime/)
which became part of ISO 8601 in 2019. See '§Sub-year groupings'. The standard defines various divisions using
numbers 21-41. cs1|2 only supports generic seasons and quarters.
These additional divisions not currently supported:
37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each)
40-41 = Semestral 1, Semestral-2 (6 months each)
]]
local function get_quarter_number (quarter, param)
if 'date' ~= param then
return 0; -- quarter dates only supported by |date=
end
quarter = mw.ustring.gsub (quarter, ' +', ' '); -- special case replace multiple space chars with a single space char
return cfg.date_names['local'].quarter[quarter] or -- look for local names first
cfg.date_names['en'].quarter[quarter] or -- failing that, look for English names
0; -- not a recognized quarter name
end
--[[--------------------------< G E T _ P R O P E R _ N A M E _ N U M B E R >----------------------------------
returns a non-zero number if date contains a recognized proper-name. Capitalization and spelling must be correct.
returns 0 when <param> is not |date=
]]
local function get_proper_name_number (name, param)
if 'date' ~= param then
return 0; -- proper-name dates only supported by |date=
end
return cfg.date_names['local'].named[name] or -- look for local names dates first
cfg.date_names['en'].named[name] or -- failing that, look for English names
0; -- not a recognized named date
end
--[[--------------------------< G E T _ E L E M E N T _ N U M B E R <------------------------------------------
returns true if month or season or quarter or proper name is valid (properly spelled, capitalized, abbreviated)
]]
local function get_element_number (element, param)
local num;
local funcs = {get_month_number, get_season_number, get_quarter_number, get_proper_name_number}; -- list of functions to execute in order
for _, func in ipairs (funcs) do -- spin through the function list
num = func (element, param); -- call the function and get the returned number
if 0 ~= num then -- non-zero when valid month season quarter
return num; -- return that number
end
end
return nil; -- not valid
end
--[[--------------------------< I S _ V A L I D _ Y E A R >----------------------------------------------------
Function gets current year from the server and compares it to year from a citation parameter. Years more than one
year in the future are not acceptable.
Special case for |pmc-embargo-date=: years more than two years in the future are not acceptable
]]
local function is_valid_year (year, param)
if not is_set (year_limit) then
year_limit = tonumber(os.date("%Y"))+1; -- global variable so we only have to fetch it once
end
year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to number for the comparison
if year and (100 > year) then -- years less than 100 not supported
return false;
end
if 'pmc-embargo-date' == param then -- special case for |pmc-embargo-date=
return year and (year <= tonumber(os.date("%Y"))+2) or false; -- years more than two years in the future are not accepted
end
return year and (year <= year_limit) or false;
end
--[[--------------------------< I S _ V A L I D _ D A T E >----------------------------------------------------
Returns true if day is less than or equal to the number of days in month and year is no farther into the future
than next year; 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.
]]
local function is_valid_date (year, month, day, param)
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local month_length;
if not is_valid_year (year, param) then -- no farther into the future than next year except |pmc-embargo-date= no more than two years in the future
return false;
end
month = tonumber (month); -- required for YYYY-MM-DD dates
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 -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
else -- Gregorian calendar
if (0 == (year%4) and (0 ~= (year%100) or 0 == (year%400))) then -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
end
else
month_length = days_in_month[month] or 0; -- invalid month number is nil so default <month_length> to 0
end
if tonumber (day) > month_length then
return false;
end
return true;
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ R A N G E _ S T Y L E >--------------------------
Months in a range are expected to have the same style: Jan–Mar or October–December but not February–Mar or Jul–August.
This function looks in cfg.date_names{} to see if both month names are listed in the long subtable or both are
listed in the short subtable. When both have the same style (both are listed in the same table), returns true; false else
]]
local function is_valid_month_range_style (month1, month2)
if (cfg.date_names.en.long[month1] and cfg.date_names.en.long[month2]) or -- are both English names listed in the long subtable?
(cfg.date_names.en.short[month1] and cfg.date_names.en.short[month2]) or -- are both English names listed in the short subtable?
(cfg.date_names['local'].long[month1] and cfg.date_names['local'].long[month2]) or -- are both local names listed in the long subtable?
(cfg.date_names['local'].short[month1] and cfg.date_names['local'].short[month2]) then -- are both local names listed in the short subtable?
return true;
end
return false; -- names are mixed
end
--[[--------------------------< I S _ V A L I D _ M O N T H _ S E A S O N _ R A N G E >------------------------
Check a pair of months or seasons to see if both are valid members of a month or season pair.
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, hence treat as ok
]]
local function is_valid_month_season_range(range_start, range_end, param)
local range_start_number = get_month_number (range_start);
local range_end_number;
if 0 == range_start_number then -- is this a month range?
range_start_number = get_season_number (range_start, param); -- not a month; is it a season? get start season number
range_end_number = get_season_number (range_end, param); -- get end season number
if (0 ~= range_start_number) and (0 ~= range_end_number) and (range_start_number ~= range_end_number) then
return true; -- any season pairing is accepted except when both are the same
end
return false; -- range_start and/or range_end is not a season
end
-- here when range_start is a month
range_end_number = get_month_number (range_end); -- get end month number
if range_start_number < range_end_number and -- range_start is a month; does range_start precede range_end?
is_valid_month_range_style (range_start, range_end) then -- do months have the same style?
return true; -- proper order and same style
end
return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month
end
--[[--------------------------< M A K E _ C O I N S _ D A T E >------------------------------------------------
This function receives a table of date parts for one or two dates and an empty table reference declared in
Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is
determined to be a valid date format. The question of what to do with invalid date formats is not answered here.
The date parts in the input table are converted to an ISO 8601 conforming date string:
single whole dates: yyyy-mm-dd
month and year dates: yyyy-mm
year dates: yyyy
ranges: yyyy-mm-dd/yyyy-mm-dd
yyyy-mm/yyyy-mm
yyyy/yyyy
Dates in the Julian calendar are reduced to year or year/year so that we don't have to do calendar conversion from
Julian to Proleptic Gregorian.
The input table has:
year, year2 – always present; if before 1582, ignore months and days if present
month, month2 – 0 if not provided, 1-12 for months, 21-24 for seasons; 99 Christmas
day, day2 – 0 if not provided, 1-31 for days
the output table receives:
rftdate: an ISO 8601 formatted date
rftchron: a free-form version of the date, usually without year which is in rftdate (season ranges and proper-name dates)
rftssn: one of four season keywords: winter, spring, summer, fall (lowercase)
rftquarter: one of four values: 1, 2, 3, 4
]]
local function make_COinS_date (input, tCOinS_date)
local date; -- one date or first date in a range
local date2 = ''; -- end of range date
input.year = tonumber (input.year) or lang_object:parseFormattedNumber (input.year); -- language-aware tonumber()
input.year2 = tonumber (input.year2) or lang_object:parseFormattedNumber (input.year2); -- COinS dates are pseudo-ISO 8601 so convert to Arabic numerals
if ((1582 == input.year) and (10 > tonumber(input.month))) or (1582 > input.year) then -- if a Julian calendar date
tCOinS_date.rftdate = tostring (input.year); -- &rft.date gets year only
return; -- done
end
-- here for all forms of Gregorian dates
if 20 < tonumber (input.month) then -- if season, quarter, or proper-name date
date = input.year; -- &rft.date gets year only
if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year
date = string.format ('%.4d/%.4d', input.year, input.year2) -- assemble the date range
end
local season = {[24] = 'winter', [21] = 'spring', [22] = 'summer', [23] = 'fall', [33] = '1', [34] = '2', [35] = '3', [36] = '4', [98] = 'Easter', [99] = 'Christmas'}; -- seasons lowercase, no autumn; proper-names use title case
if 0 == input.month2 then -- single season, quarter, or proper-name date
if 40 < tonumber(input.month) then
tCOinS_date.rftchron = season[input.month]; -- proper-name date; used in journal metadata only
elseif 30 < tonumber(input.month) then
tCOinS_date.rftquarter = season[input.month]; -- quarter date; used in journal metadata only
else
tCOinS_date.rftssn = season[input.month]; -- season date; used in journal metadata only
end
else -- season ranges are lumped into &rft.chron; &rft.ssn and &rft.quarter are left blank
if input.year ~= input.year2 then -- season year – season year range or season year–year
if 0 ~= input.month2 then
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2); -- used in journal metadata only
end
else -- season–season year range
tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range; used in journal metadata only
end
end
tCOinS_date.rftdate = tostring (date);
return; -- done
end
-- here for gregorian calendar dates
if 0 ~= input.day then
date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date
elseif 0 ~= input.month then
date = string.format ('%s-%.2d', input.year, tonumber(input.month)); -- year and month
else
date = string.format ('%s', input.year); -- just year
end
if 0 ~= input.year2 then
if 0 ~= input.day2 then
date2 = string.format ('/%s-%.2d-%.2d', input.year2, tonumber(input.month2), tonumber(input.day2)); -- whole date
elseif 0 ~= input.month2 then
date2 = string.format ('/%s-%.2d', input.year2, tonumber(input.month2)); -- year and month
else
date2 = string.format ('/%s', input.year2); -- just year
end
end
tCOinS_date.rftdate = date .. date2; -- date2 has the '/' separator
return;
end
--[[--------------------------< P A T T E R N S _ T >----------------------------------------------------------
this is the list of patterns for date formats that this module recognizes. Approximately the first half of these
patterns represent formats that might be reformatted into another format. Those that might be reformatted have
'indicator' letters that identify the content of the matching capture: 'd' (day), 'm' (month), 'a' (anchor year),
'y' (year); second day, month, year have a '2' suffix.
These patterns are used for both date validation and for reformatting. This table should not be moved to ~/Configuration
because changes to this table require changes to check_date() and to reformatter() and reformat_date()
]]
local patterns_t = {
-- year-initial numerical year-month-day
['ymd'] = {'^([1-9]%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'},
-- month-initial: month day, year
['Mdy'] = {'^(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'a', 'y'},
-- month-initial day range: month day–day, year; days are separated by endash
['Md-dy'] = {'^(%D-) +([1-9]%d?)[%-–]([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'd2', 'a', 'y'},
-- day-initial: day month year
['dMy'] = {'^([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'a', 'y'},
-- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed; not supported at en.wiki
-- ['yMd'] = {'^(([1-9]%d%d%d?)%a?) +(%D-) +(%d%d?)$', 'a', 'y', 'm', 'd'},
-- day-range-initial: day–day month year; days are separated by endash
['d-dMy'] = {'^([1-9]%d?)[%-–]([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'd2', 'm', 'a', 'y'},
-- day initial month-day-range: day month - day month year; uses spaced endash
['dM-dMy'] = {'^([1-9]%d?) +(%D-) +[%-–] +([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'd2', 'm2', 'a', 'y'},
-- month initial month-day-range: month day – month day, year; uses spaced endash
['Md-Mdy'] = {'^(%D-) +([1-9]%d?) +[%-–] +(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$','m', 'd', 'm2', 'd2', 'a', 'y'},
-- day initial month-day-year-range: day month year - day month year; uses spaced endash
['dMy-dMy'] = {'^([1-9]%d?) +(%D-) +([1-9]%d%d%d?) +[%-–] +([1-9]%d?) +(%D-) +(([1-9]%d%d%d?)%a?)$', 'd', 'm', 'y', 'd2', 'm2', 'a', 'y2'},
-- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
['Mdy-Mdy'] = {'^(%D-) +([1-9]%d?), +([1-9]%d%d%d?) +[%-–] +(%D-) +([1-9]%d?), +(([1-9]%d%d%d?)%a?)$', 'm', 'd', 'y', 'm2', 'd2', 'a', 'y2'},
-- these date formats cannot be converted, per se, but month name can be rendered short or long
-- month/season year - month/season year; separated by spaced endash
['My-My'] = {'^(%D-) +([1-9]%d%d%d?) +[%-–] +(%D-) +(([1-9]%d%d%d?)%a?)$', 'm', 'y', 'm2', 'a', 'y2'},
-- month/season range year; months separated by endash
['M-My'] = {'^(%D-)[%-–](%D-) +(([1-9]%d%d%d?)%a?)$', 'm', 'm2', 'a', 'y'},
-- month/season year or proper-name year; quarter year when First Quarter YYYY etc.
['My'] = {'^([^%d–]-) +(([1-9]%d%d%d?)%a?)$', 'm', 'a', 'y'}, -- this way because endash is a member of %D; %D- will match January–March 2019 when it shouldn't
-- these date formats cannot be converted
['Sy4-y2'] = {'^(%D-) +(([1-9]%d)%d%d)[%-–]((%d%d)%a?)$'}, -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
['Sy-y'] = {'^(%D-) +([1-9]%d%d%d?)[%-–](([1-9]%d%d%d?)%a?)$'}, -- special case Winter/Summer year-year; year separated with unspaced endash
['y-y'] = {'^([1-9]%d%d%d?)[%-–](([1-9]%d%d%d?)%a?)$'}, -- year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
['y4-y2'] = {'^(([1-9]%d)%d%d)[%-–]((%d%d)%a?)$'}, -- year range: YYYY–YY; separated by unspaced endash
['y'] = {'^(([1-9]%d%d%d?)%a?)$'}, -- year; here accept either YYY or YYYY
}
--[[--------------------------< I S _ V A L I D _ E M B A R G O _ D A T E >------------------------------------
returns true and date value if that value has proper dmy, mdy, ymd format.
returns false and 9999 (embargoed forever) when date value is not proper format; assumes that when |pmc-embargo-date= is
set, the editor intended to embargo a PMC but |pmc-embargo-date= does not hold a single date.
]]
local function is_valid_embargo_date (v)
if v:match (patterns_t['ymd'][1]) or -- ymd
v:match (patterns_t['Mdy'][1]) or -- dmy
v:match (patterns_t['dMy'][1]) then -- mdy
return true, v;
end
return false, '9999'; -- if here not good date so return false and set embargo date to long time in future
end
--[[--------------------------< C H E C K _ D A T E >----------------------------------------------------------
Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only
allowed range separator is endash. 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. Future years beyond next year are not allowed.
If the date fails the format tests, this function returns false and does not return values for anchor_year and
COinS_date. When this happens, the date parameter is (DEBUG: not?) used in the COinS metadata and the CITEREF identifier gets
its year from the year parameter if present otherwise CITEREF does not get a date value.
Inputs:
date_string - date string from date-holding parameters (date, year, publication-date, access-date, pmc-embargo-date, archive-date, lay-date)
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 ISO 8601 format date; see make_COInS_date()
]]
local function check_date (date_string, param, tCOinS_date)
local year; -- assume that year2, months, and days are not used;
local year2 = 0; -- second year in a year range
local month = 0;
local month2 = 0; -- second month in a month range
local day = 0;
local day2 = 0; -- second day in a day range
local anchor_year;
local coins_date;
if date_string:match (patterns_t['ymd'][1]) then -- year-initial numerical year month day format
year, month, day = date_string:match (patterns_t['ymd'][1]);
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;
elseif mw.ustring.match(date_string, patterns_t['Mdy'][1]) then -- month-initial: month day, year
month, day, anchor_year, year = mw.ustring.match(date_string, patterns_t['Mdy'][1]);
month = get_month_number (month);
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, patterns_t['Md-dy'][1]) then -- month-initial day range: month day–day, year; days are separated by endash
month, day, day2, anchor_year, year = mw.ustring.match(date_string, patterns_t['Md-dy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2=month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dMy'][1]) then -- day-initial: day month year
day, month, anchor_year, year = mw.ustring.match(date_string, patterns_t['dMy'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
--[[ NOT supported at en.wiki
elseif mw.ustring.match(date_string, patterns_t['yMd'][1]) then -- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed
anchor_year, year, month, day = mw.ustring.match(date_string, patterns_t['yMd'][1]);
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
-- end NOT supported at en.wiki ]]
elseif mw.ustring.match(date_string, patterns_t['d-dMy'][1]) then -- day-range-initial: day–day month year; days are separated by endash
day, day2, month, anchor_year, year = mw.ustring.match(date_string, patterns_t['d-dMy'][1]);
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
month2 = month; -- for metadata
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dM-dMy'][1]) then -- day initial month-day-range: day month - day month year; uses spaced endash
day, month, day2, month2, anchor_year, year = mw.ustring.match(date_string, patterns_t['dM-dMy'][1]);
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end -- date range order is left to right: earlier to later;
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['Md-Mdy'][1]) 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, patterns_t['Md-Mdy'][1]);
if (not is_valid_month_season_range(month, month2, param)) or not is_valid_year(year) then return false; end
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['dMy-dMy'][1]) 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, patterns_t['dMy-dMy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number (month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns_t['Mdy-Mdy'][1]) then -- month initial month-day-year-range: month day, year – month day, year; uses spaced endash
month, day, year, month2, day2, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Mdy-Mdy'][1]);
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
month = get_month_number (month); -- for metadata
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end -- both must be valid
elseif mw.ustring.match(date_string, patterns_t['Sy4-y2'][1]) then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
local century;
month, year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Sy4-y2'][1]);
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
year2 = century..year2; -- add the century to year2 for comparisons
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
month = get_season_number(month, param);
elseif mw.ustring.match(date_string, patterns_t['Sy-y'][1]) then -- special case Winter/Summer year-year; year separated with unspaced endash
month, year, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['Sy-y'][1]);
month = get_season_number (month, param); -- <month> can only be winter or summer; also for metadata
if (month ~= cfg.date_names['en'].season['Winter']) and (month ~= cfg.date_names['en'].season['Summer']) then
return false; -- not Summer or Winter; abandon
end
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns_t['My-My'][1]) then -- month/season year - month/season year; separated by spaced endash
month, year, month2, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['My-My'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor_year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if 0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2) then -- both must be month year, same month style
month = get_month_number(month);
month2 = get_month_number(month2);
elseif 0 ~= get_season_number(month, param) and 0 ~= get_season_number(month2, param) then -- both must be season year, not mixed
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
else
return false;
end
elseif mw.ustring.match(date_string, patterns_t['M-My'][1]) then -- month/season range year; months separated by endash
month, month2, anchor_year, year = mw.ustring.match(date_string, patterns_t['M-My'][1]);
if (not is_valid_month_season_range(month, month2, param)) or (not is_valid_year(year)) then return false; end
if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
month = get_month_number(month);
month2 = get_month_number(month2);
if 0 == month or 0 == month2 then return false; end
else
month = get_season_number(month, param);
month2 = get_season_number(month2, param);
end
year2 = year;
elseif mw.ustring.match(date_string, patterns_t['My'][1]) then -- month/season/quarter/proper-name year
month, anchor_year, year = mw.ustring.match(date_string, patterns_t['My'][1]);
if not is_valid_year(year) then return false; end
month = get_element_number(month, param); -- get month season quarter proper-name number or nil
if not month then return false; end -- not valid whatever it is
elseif mw.ustring.match(date_string, patterns_t['y-y'][1]) then -- Year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999
year, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['y-y'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
elseif mw.ustring.match(date_string, patterns_t['y4-y2'][1]) then -- Year range: YYYY–YY; separated by unspaced endash
local century;
year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns_t['y4-y2'][1]);
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years
if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003
year2 = century .. year2; -- add the century to year2 for comparisons
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year
if in_array (param, {'date', 'publication-date', 'year'}) then -- here when 'valid' abbreviated year range; if one of these parameters
add_prop_cat ('year-range-abbreviated'); -- add properties cat
end
elseif mw.ustring.match(date_string, patterns_t['y'][1]) then -- year; here accept either YYY or YYYY
anchor_year, year = mw.ustring.match(date_string, patterns_t['y'][1]);
if false == is_valid_year(year) then
return false;
end
else
return false; -- date format not one of the MOS:DATE approved formats
end
if param ~= 'date' then -- CITEREF disambiguation only allowed in |date=; |year= & |publication-date= promote to date
if anchor_year:match ('%l$') then
return false;
end
end
if 'access-date' == param then -- test access-date here because we have numerical date parts
if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2 then -- none of these; access-date must not be a range
if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then
return false; -- return false when access-date out of bounds
end
else
return false; -- return false when access-date is a range of two dates
end
end
if 'archive-date' == param then -- test archive-date here because we have numerical date parts
if not (0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required
0 == year2 and 0 == month2 and 0 == day2) then -- none of these; archive-date must not be a range
return false; -- return false when archive-date is a range of two dates
end
end
local result=true; -- check whole dates for validity; assume true because not all dates will go through this test
if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date)
result = is_valid_date (year, month, day, param); -- <param> for |pmc-embargo-date=
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 ~= day2 then -- YMD-d (day range)
result = is_valid_date (year, month, day);
result = result and is_valid_date (year, month, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-md (day month range)
result = is_valid_date (year, month, day);
result = result and is_valid_date (year, month2, day2);
elseif 0 ~= year and 0 ~= month and 0 ~= day and 0 ~= year2 and 0 ~= month2 and 0 ~= day2 then -- YMD-ymd (day month year range)
result = is_valid_date(year, month, day);
result = result and is_valid_date(year2, month2, day2);
end
if false == result then return false; end
if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values
make_COinS_date ({year = year, month = month, day = day, year2 = year2, month2 = month2, day2 = day2}, tCOinS_date); -- make an ISO 8601 date string for COinS
end
return true, anchor_year; -- format is good and date string represents a real date
end
--[[--------------------------< D A T E S >--------------------------------------------------------------------
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. The |date= parameter test is unique, it is the only date holding parameter from which values for anchor_year (used in CITEREF identifiers) and COinS_date (used in
the COinS metadata) are derived. The |date= parameter 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,
parameters with errors are added to the <error_list> sequence table as the dates are tested.
]]
local function dates(date_parameters_list, tCOinS_date, error_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 embargo_date; -- if embargo date is a good dmy, mdy, ymd date then holds original value else reset to 9999
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.val) then -- if the parameter has a value
v.val = mw.ustring.gsub(v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9
if v.val:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
local year = v.val:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested
if 'date' == k then
anchor_year, COinS_date = v.val:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
good_date = is_valid_year(year);
elseif 'year' == k then
good_date = is_valid_year(year);
else
good_date = false;
end
elseif 'date' == k then -- if the parameter is |date=
if v.val:match("^n%.d%.%a?$") then -- ToDo: I18N -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((n%.d%.)%a?)"); -- ToDo: I18N -- "n.d."; no error when date parameter is set to no date
elseif v.val:match("^nd%a?$") then -- ToDo: I18N -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((nd)%a?)"); -- ToDo: I18N -- "nd"; no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v.val, k, tCOinS_date); -- go test the date
end
elseif 'year' == k then -- if the parameter is |year= it should hold only a year value
if v.val:match("^[1-9]%d%d%d?%a?$") then -- if |year = 3 or 4 digits only with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)");
else
good_date = false;
end
elseif 'pmc-embargo-date' == k then -- if the parameter is |pmc-embargo-date=
good_date = check_date (v.val, k); -- go test the date
if true == good_date then -- if the date is a valid date
good_date, embargo_date = is_valid_embargo_date (v.val); -- is |pmc-embargo-date= date a single dmy, mdy, or ymd formatted date? yes: returns embargo date; no: returns 9999
end
else -- any other date-holding parameter
good_date = check_date (v.val, k); -- go test the date
end
if false == good_date then -- assemble one error message so we don't add the tracking category multiple times
table.insert (error_list, wrap_style ('parameter', v.name)); -- make parameter name suitable for error message list
end
end
end
return anchor_year, embargo_date; -- and done
end
--[[--------------------------< Y E A R _ C H E C K >----------------------------------------------------------
Temporary function to test |year= for acceptable values:
YYY, YYYY, year-only ranges, their circa forms, with or without CITEREF disambiguators.
When |year= holds some form of date that is not one of these year-only dates, emit a maintenance message.
This function necessary because many non-cs1|2 templates have a |year= parameter so cirrus searches are more-or-
less useless
]]
local function year_check (year)
year = year:gsub ('c%. *', ''); -- remove circa annotation (if present) before testing <year>
for _, index in ipairs ({'y-y', 'y4-y2', 'y'}) do -- spin through these indexes into patterns_t
if mw.ustring.match (year, patterns_t[index][1]) then
return; -- if a match then |year= holds a valid 'year'
end
end
set_message ('maint_year'); -- if here, |year= value is not an accepted value; add a maint cat
end
--[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------
Compare the value provided in |year= with the year value(s) provided in |date=. This function sets a local numeric value:
0 - year value does not match the year value in date
1 - (default) year value matches the year value in date or one of the year values when date contains two years
2 - year value matches the year value in date when date is in the form YYYY-MM-DD and year is disambiguated (|year=YYYYx)
the numeric value in <result> determines the 'output' if any from this function:
0 – adds error message to error_list sequence table
1 – adds maint cat
2 – does nothing
]]
local function year_date_check (year_string, year_origin, date_string, date_origin, error_list)
local year;
local date1;
local date2;
local result = 1; -- result of the test; assume that the test passes
year = year_string:match ('(%d%d%d%d?)');
if date_string:match ('%d%d%d%d%-%d%d%-%d%d') then --special case where both date and year are required YYYY-MM-DD and YYYYx
date1 = date_string:match ('(%d%d%d%d)');
year = year_string:match ('(%d%d%d%d)');
if year ~= date1 then
result = 0; -- years don't match
elseif year_string:match ('%d%d%d%d%a') then
result = 2; -- years match; but because disambiguated, don't add to maint cat
end
elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard range formats of date with two three- or four-digit years
date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)");
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif mw.ustring.match(date_string, "%d%d%d%d[%-–]%d%d") then -- YYYY-YY date ranges
local century;
date1, century, date2 = mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]+(%d%d)");
date2 = century..date2; -- convert YY to YYYY
if year ~= date1 and year ~= date2 then
result = 0;
end
elseif date_string:match ("%d%d%d%d?") then -- any of the standard formats of date with one year
date1 = date_string:match ("(%d%d%d%d?)");
if year ~= date1 then
result = 0;
end
else -- should never get here; this function called only when no other date errors
result = 0; -- no recognizable year in date
end
if 0 == result then -- year / date mismatch
table.insert (error_list, substitute (cfg.messages['mismatch'], {year_origin, date_origin})); -- add error message to error_list sequence table
elseif 1 == result then -- redundant year / date
set_message ('maint_date_year'); -- add a maint cat
end
end
--[[--------------------------< R E F O R M A T T E R >--------------------------------------------------------
reformat 'date' into new format specified by format_param if pattern_idx (the current format of 'date') can be
reformatted. Does the grunt work for reformat_dates().
The table re_formats maps pattern_idx (current format) and format_param (desired format) to a table that holds:
format string used by string.format()
identifier letters ('d', 'm', 'y', 'd2', 'm2', 'y2') that serve as indexes into a table t{} that holds captures
from mw.ustring.match() for the various date parts specified by patterns_t[pattern_idx][1]
Items in patterns_t{} have the general form:
['ymd'] = {'^(%d%d%d%d)%-(%d%d)%-(%d%d)$', 'y', 'm', 'd'}, where:
['ymd'] is pattern_idx
patterns_t['ymd'][1] is the match pattern with captures for mw.ustring.match()
patterns_t['ymd'][2] is an indicator letter identifying the content of the first capture
patterns_t['ymd'][3] ... the second capture etc.
when a pattern matches a date, the captures are loaded into table t{} in capture order using the idemtifier
characters as indexes into t{} For the above, a ymd date is in t{} as:
t.y = first capture (year), t.m = second capture (month), t.d = third capture (day)
To reformat, this function is called with the pattern_idx that matches the current format of the date and with
format_param set to the desired format. This function loads table t{} as described and then calls string.format()
with the format string specified by re_format[pattern_idx][format_param][1] using values taken from t{} according
to the capture identifier letters specified by patterns_t[pattern_idx][format_param][n] where n is 2..
]]
local re_formats = {
['ymd'] = { -- date format is ymd; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Mdy'] = { -- date format is Mdy; reformat to:
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['dMy'] = { -- date format is dMy; reformat to:
['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- ['yMd'] = {'%s %s %s', 'y', 'm', 'd'}, -- |df=yMd; not supported at en.wiki
},
['Md-dy'] = { -- date format is Md-dy; reformat to:
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- |df=dmy -> d-dMy
},
['d-dMy'] = { -- date format is d-d>y; reformat to:
['dmy'] = {'%s–%s %s %s', 'd', 'd2', 'm', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s–%s, %s', 'm', 'd', 'd2', 'y'}, -- |df=mdy -> Md-dy
},
['dM-dMy'] = { -- date format is dM-dMy; reformat to:
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- for long/short reformatting
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- |df=mdy -> Md-Mdy
},
['Md-Mdy'] = { -- date format is Md-Mdy; reformat to:
['mdy'] = {'%s %s – %s %s, %s', 'm', 'd', 'm2', 'd2', 'y'}, -- for long/short reformatting
['dmy'] = {'%s %s – %s %s %s', 'd', 'm', 'd2', 'm2', 'y'}, -- |df=dmy -> dM-dMy
},
['dMy-dMy'] = { -- date format is dMy-dMy; reformat to:
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- for long/short reformatting
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- |df=mdy -> Mdy-Mdy
},
['Mdy-Mdy'] = { -- date format is Mdy-Mdy; reformat to:
['mdy'] = {'%s %s, %s – %s %s, %s', 'm', 'd', 'y', 'm2', 'd2', 'y2'}, -- for long/short reformatting
['dmy'] = {'%s %s %s – %s %s %s', 'd', 'm', 'y', 'd2', 'm2', 'y2'}, -- |df=dmy -> dMy-dMy
},
['My-My'] = { -- these for long/short reformatting
['any'] = {'%s %s – %s %s', 'm', 'y', 'm2', 'y2'}, -- dmy/mdy agnostic
},
['M-My'] = { -- these for long/short reformatting
['any'] = {'%s–%s %s', 'm', 'm2', 'y'}, -- dmy/mdy agnostic
},
['My'] = { -- these for long/short reformatting
['any'] = {'%s %s', 'm', 'y'}, -- dmy/mdy agnostic
},
-- ['yMd'] = { -- not supported at en.wiki
-- ['mdy'] = {'%s %s, %s', 'm', 'd', 'y'}, -- |df=mdy
-- ['dmy'] = {'%s %s %s', 'd', 'm', 'y'}, -- |df=dmy
-- ['ymd'] = {'%s-%s-%s', 'y', 'm', 'd'}, -- |df=ymd
-- },
}
local function reformatter (date, pattern_idx, format_param, mon_len)
if not in_array (pattern_idx, {'ymd', 'Mdy', 'Md-dy', 'dMy', 'yMd', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- not in this set of date format patterns_t then not a reformattable date
end
if 'ymd' == format_param and in_array (pattern_idx, {'ymd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy', 'My-My', 'M-My', 'My'}) then
return; -- ymd date ranges not supported at en.wiki; no point in reformatting ymd to ymd
end
if in_array (pattern_idx, {'My', 'M-My', 'My-My'}) then -- these are not dmy/mdy so can't be 'reformatted' into either
format_param = 'any'; -- so format-agnostic
end
-- yMd is not supported at en.wiki; when yMd is supported at your wiki, uncomment the next line
-- if 'yMd' == format_param and in_array (pattern_idx, {'yMd', 'Md-dy', 'd-dMy', 'dM-dMy', 'Md-Mdy', 'dMy-dMy', 'Mdy-Mdy'}) then -- these formats not convertable; yMd not supported at en.wiki
if 'yMd' == format_param then -- yMd not supported at en.wiki; when yMd is supported at your wiki, remove or comment-out this line
return; -- not a reformattable date
end
local c1, c2, c3, c4, c5, c6, c7; -- these hold the captures specified in patterns_t[pattern_idx][1]
c1, c2, c3, c4, c5, c6, c7 = mw.ustring.match (date, patterns_t[pattern_idx][1]); -- get the captures
local t = { -- table that holds k/v pairs of date parts from the captures and patterns_t[pattern_idx][2..]
[patterns_t[pattern_idx][2]] = c1; -- at minimum there is always one capture with a matching indicator letter
[patterns_t[pattern_idx][3] or 'x'] = c2; -- patterns_t can have a variable number of captures; each capture requires an indicator letter;
[patterns_t[pattern_idx][4] or 'x'] = c3; -- where there is no capture, there is no indicator letter so n in patterns_t[pattern_idx][n] will be nil;
[patterns_t[pattern_idx][5] or 'x'] = c4; -- the 'x' here spoofs an indicator letter to prevent 'table index is nil' error
[patterns_t[pattern_idx][6] or 'x'] = c5;
[patterns_t[pattern_idx][7] or 'x'] = c6;
[patterns_t[pattern_idx][8] or 'x'] = c7;
};
if t.a then -- if this date has an anchor year capture (all convertable date formats except ymd)
if t.y2 then -- for year range date formats
t.y2 = t.a; -- use the anchor year capture when reassembling the date
else -- here for single date formats (except ymd)
t.y = t.a; -- use the anchor year capture when reassembling the date
end
end
if tonumber(t.m) then -- if raw month is a number (converting from ymd)
if 's' == mon_len then -- if we are to use abbreviated month names
t.m = cfg.date_names['inv_local_short'][tonumber(t.m)]; -- convert it to a month name
else
t.m = cfg.date_names['inv_local_long'][tonumber(t.m)]; -- convert it to a month name
end
t.d = t.d:gsub ('0(%d)', '%1'); -- strip leading '0' from day if present
elseif 'ymd' == format_param then -- when converting to ymd
t.y = t.y:gsub ('%a', ''); -- strip CITREF disambiguator if present; anchor year already known so process can proceed; TODO: maint message?
if 1582 > tonumber (t.y) then -- ymd format dates not allowed before 1582
return;
end
t.m = string.format ('%02d', get_month_number (t.m)); -- make sure that month and day are two digits
t.d = string.format ('%02d', t.d);
elseif mon_len then -- if mon_len is set to either 'short' or 'long'
for _, mon in ipairs ({'m', 'm2'}) do -- because there can be two month names, check both
if t[mon] then
t[mon] = get_month_number (t[mon]); -- get the month number for this month (is length agnostic)
if 0 == t[mon] then return; end -- seasons and named dates can't be converted
t[mon] = (('s' == mon_len) and cfg.date_names['inv_local_short'][t[mon]]) or cfg.date_names['inv_local_long'][t[mon]]; -- fetch month name according to length
end
end
end
local new_date = string.format (re_formats[pattern_idx][format_param][1], -- format string
t[re_formats[pattern_idx][format_param][2]], -- named captures from t{}
t[re_formats[pattern_idx][format_param][3]],
t[re_formats[pattern_idx][format_param][4]],
t[re_formats[pattern_idx][format_param][5]],
t[re_formats[pattern_idx][format_param][6]],
t[re_formats[pattern_idx][format_param][7]],
t[re_formats[pattern_idx][format_param][8]]
);
return new_date;
end
--[[-------------------------< R E F O R M A T _ D A T E S >--------------------------------------------------
Reformats existing dates into the format specified by format.
format is one of several manual keywords: dmy, dmy-all, mdy, mdy-all, ymd, ymd-all. The -all version includes
access- and archive-dates; otherwise these dates are not reformatted.
This function allows automatic date formatting. In ~/Configuration, the article source is searched for one of
the {{use xxx dates}} templates. If found, xxx becomes the global date format as xxx-all. If |cs1-dates= in
{{use xxx dates}} has legitimate value then that value determines how cs1|2 dates will be rendered. Legitimate
values for |cs1-dates= are:
l - all dates are rendered with long month names
ls - publication dates use long month names; access-/archive-dates use abbreviated month names
ly - publication dates use long month names; access-/archive-dates rendered in ymd format
s - all dates are rendered with abbreviated (short) month names
sy - publication dates use abbreviated month names; access-/archive-dates rendered in ymd format
y - all dates are rendered in ymd format
the format argument for automatic date formatting will be the format specified by {{use xxx dates}} with the
value supplied by |cs1-dates so one of: xxx-l, xxx-ls, xxx-ly, xxx-s, xxx-sy, xxx-y, or simply xxx (|cs1-dates=
empty, omitted, or invalid) where xxx shall be either of dmy or mdy.
dates are extracted from date_parameters_list, reformatted (if appropriate), and then written back into the
list in the new format. Dates in date_parameters_list are presumed here to be valid (no errors). This function
returns true when a date has been reformatted, false else. Actual reformatting is done by reformatter().
]]
local function reformat_dates (date_parameters_list, format)
local all = false; -- set to false to skip access- and archive-dates
local len_p = 'l'; -- default publication date length shall be long
local len_a = 'l'; -- default access-/archive-date length shall be long
local result = false;
local new_date;
if format:match('%a+%-all') then -- manual df keyword; auto df keyword when length not specified in {{use xxx dates}};
format = format:match('(%a+)%-all'); -- extract the format
all = true; -- all dates are long format dates because this keyword doesn't specify length
elseif format:match('%a+%-[lsy][sy]?') then -- auto df keywords; internal only
all = true; -- auto df applies to all dates; use length specified by capture len_p for all dates
format, len_p, len_a = format:match('(%a+)%-([lsy])([sy]?)'); -- extract the format and length keywords
if 'y' == len_p then -- because allowed by MOS:DATEUNIFY (sort of) range dates and My dates not reformatted
format = 'ymd'; -- override {{use xxx dates}}
elseif (not is_set(len_a)) or (len_p == len_a) then -- no access-/archive-date length specified or same length as publication dates then
len_a = len_p; -- in case len_a not set
end
end -- else only publication dates and they are long
for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) then -- if the parameter has a value
if not (not all and in_array (param_name, {'access-date', 'archive-date'})) then -- skip access- or archive-date unless format is xxx-all; yeah, ugly; TODO: find a better way
for pattern_idx, pattern in pairs (patterns_t) do
if mw.ustring.match (param_val.val, pattern[1]) then
if all and in_array (param_name, {'access-date', 'archive-date'}) then -- if this date is an access- or archive-date
new_date = reformatter (param_val.val, pattern_idx, (('y' == len_a) and 'ymd') or format, len_a); -- choose ymd or dmy/mdy according to len_a setting
else -- all other dates
new_date = reformatter (param_val.val, pattern_idx, format, len_p);
end
if new_date then -- set when date was reformatted
date_parameters_list[param_name].val = new_date; -- update date in date list
result = true; -- and announce that changes have been made
break;
end
end -- if
end -- for
end -- if
end -- if
end -- for
return result; -- declare boolean result and done
end
--[[--------------------------< D A T E _ H Y P H E N _ T O _ D A S H >----------------------------------------
Loops through the list of date-holding parameters and converts any hyphen to an ndash. Not called if the cs1|2
template has any date errors.
Modifies the date_parameters_list and returns true if hyphens are replaced, else returns false.
]]
local function date_hyphen_to_dash (date_parameters_list)
local result = false;
local n;
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set (param_val.val) and
not mw.ustring.match (param_val.val, patterns_t.ymd[1]) then -- for those that are not ymd dates (ustring because here digits may not be Western)
param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash
if 0 ~= n then
date_parameters_list[param_name].val = param_val.val; -- update the list
result = true;
end
end
end
return result; -- so we know if any hyphens were replaced
end
--[[-------------------------< D A T E _ N A M E _ X L A T E >------------------------------------------------
Attempts to translate English date names to local-language date names using names supplied by MediaWiki's
date parser function. This is simple name-for-name replacement and may not work for all languages.
if xlat_dig is true, this function will also translate Western (English) digits to the local language's digits.
This will also translate ymd dates.
]]
local function date_name_xlate (date_parameters_list, xlt_dig)
local xlate;
local mode; -- long or short month names
local modified = false;
local date;
local sources_t = {
{cfg.date_names.en.long, cfg.date_names.inv_local_long}, -- for translating long English month names to long local month names
{cfg.date_names.en.short, cfg.date_names.inv_local_short}, -- short month names
{cfg.date_names.en.quarter, cfg.date_names.inv_local_quarter}, -- quarter date names
{cfg.date_names.en.season, cfg.date_names.inv_local_season}, -- season date nam
{cfg.date_names.en.named, cfg.date_names.inv_local_named}, -- named dates
}
local function is_xlateable (month) -- local function to get local date name that replaces existing English-language date name
for _, date_names_t in ipairs (sources_t) do -- for each sequence table in date_names_t
if date_names_t[1][month] then -- if date name is English month (long or short), quarter, season or named and
if date_names_t[2][date_names_t[1][month]] then -- if there is a matching local date name
return date_names_t[2][date_names_t[1][month]]; -- return the local date name
end
end
end
end
for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set(param_val.val) then -- if the parameter has a value
date = param_val.val;
for month in mw.ustring.gmatch (date, '[%a ]+') do -- iterate through all date names in the date (single date or date range)
month = mw.text.trim (month); -- this because quarterly dates contain whitespace
xlate = is_xlateable (month); -- get translate <month>; returns translation or nil
if xlate then
date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
if xlt_dig then -- shall we also translate digits?
date = date:gsub ('%d', cfg.date_names.xlate_digits); -- translate digits from Western to 'local digits'
date_parameters_list[param_name].val = date; -- save the translated date
modified = true;
end
end
end
return modified;
end
--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------
Sets local imported functions table to same (live or sandbox) as that used by the other modules.
]]
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
add_prop_cat = utilities_page_ptr.add_prop_cat ; -- import functions from selected Module:Citation/CS1/Utilities module
is_set = utilities_page_ptr.is_set;
in_array = utilities_page_ptr.in_array;
set_message = utilities_page_ptr.set_message;
substitute = utilities_page_ptr.substitute;
wrap_style = utilities_page_ptr.wrap_style;
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration
end
--[[--------------------------< A R C H I V E _ D A T E _ C H E C K >------------------------------------------
Compare value in |archive-date= with the timestamp in Wayback machine urls. Emits an error message with suggested
date from the |archive-url= timestamp in an appropriate format when the value in |archive-date= does not match
the timestamp.
this function never called when any date in a cs1|2 template has errors
error message suggests new |archive-date= value in an appropriate format specified by <df>. <df> is either
|df= or cfg.global_df in that order. If <df> is nil, suggested date has format from |archive-date=. There is
a caveat: when |df=dmy or |df=mdy, the reformatter leaves |access-date= and |archive-date= formats as they are.
The error message suggested date is passed to the formatter as YYYY-MM-DD so when |df=dmy or |df=mdy, the format
is not changed.
]]
local function archive_date_check (archive_date, archive_url_timestamp, df)
local archive_date_format = 'dmy-y'; -- holds the date format of date in |archive-date; default to ymd; 'dmy' used here to spoof reformat_dates()
for _, v_t in ipairs ({{'dMy', 'dmy-all'}, {'Mdy', 'mdy-all'}}) do -- is |archive-date= format dmy or mdy?
if archive_date:match (patterns_t[v_t[1]][1]) then -- does the pattern match?
archive_date_format = cfg.keywords_xlate[v_t[2]]; -- get appropriate |df= supported keyword from the i18n translator table
break;
end
end
local dates_t = {};
dates_t['archive-date'] = {val=archive_date, name=''}; -- setup to call reformat_dates(); never called when errors so <name> unset as not needed
reformat_dates (dates_t, 'dmy-y'); -- reformat |archive-date= to ymd; 'dmy' used here to spoof reformat_dates()
local archive_url_date = archive_url_timestamp:gsub ('(%d%d%d%d)(%d%d)(%d%d)%d*', '%1-%2-%3'); -- make ymd format date from timestamp
if dates_t['archive-date'].val == archive_url_date then -- are the two dates the same
return; -- yes, done
else
dates_t['archive-date'] = {val=archive_url_date, name=''}; -- setup to call reformat_dates() with the timestamp date
reformat_dates (dates_t, df or archive_date_format); -- reformat timestamp to format specified by <df> or format used in |archive-date=
archive_url_date = dates_t['archive-date'].val;
set_message ('err_archive_date_url_ts_mismatch', archive_url_date); -- emit an error message
end
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return { -- return exported functions
archive_date_check = archive_date_check,
date_hyphen_to_dash = date_hyphen_to_dash,
date_name_xlate = date_name_xlate,
dates = dates,
is_valid_date = is_valid_date,
reformat_dates = reformat_dates,
set_selected_modules = set_selected_modules,
year_check = year_check,
year_date_check = year_date_check,
}
039z8dc7ugbbv8w4tsnejz5bfud8dgw
တမ်းပလိတ်:Country data AUT
10
3778
17574
2026-03-29T11:59:49Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဩစတြီးယားနိုင်ငံ | shortname alias = ဩစတြီးယား | flag alias = Flag of Austria.svg | flag alias-empire = Flag of the Habsburg Monarchy.svg | flag alias-state = Flag of Austria (state).svg | flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg | size = {{{size|}}} | name = {{{name|}}} | altlink = {{{altlink|}}} | variant = {{{variant|}}} <..."
17574
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဩစတြီးယားနိုင်ငံ
| shortname alias = ဩစတြီးယား
| flag alias = Flag of Austria.svg
| flag alias-empire = Flag of the Habsburg Monarchy.svg
| flag alias-state = Flag of Austria (state).svg
| flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = empire
| var2 = state
| var3 = war
| redir1 = AUT
| redir2 = Archduchy of Austria
| redir3 = Austria
| related1 = Austria-Hungary
</noinclude>
}}
j3cbse2x02x56aenw2ykty6acpagath
တမ်းပလိတ်:Country data Archduchy of Austria
10
3779
17575
2026-03-29T12:00:35Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဩစတြီးယားနိုင်ငံ | shortname alias = ဩစတြီးယား | flag alias = Flag of Austria.svg | flag alias-empire = Flag of the Habsburg Monarchy.svg | flag alias-state = Flag of Austria (state).svg | flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg | size = {{{size|}}} | name = {{{name|}}} | altlink = {{{altlink|}}} | variant = {{{variant|}}} <..."
17575
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဩစတြီးယားနိုင်ငံ
| shortname alias = ဩစတြီးယား
| flag alias = Flag of Austria.svg
| flag alias-empire = Flag of the Habsburg Monarchy.svg
| flag alias-state = Flag of Austria (state).svg
| flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = empire
| var2 = state
| var3 = war
| redir1 = AUT
| redir2 = Archduchy of Austria
| redir3 = Austria
| related1 = Austria-Hungary
</noinclude>
}}
j3cbse2x02x56aenw2ykty6acpagath
တမ်းပလိတ်:Country data Austria
10
3780
17576
2026-03-29T12:00:54Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဩစတြီးယားနိုင်ငံ | shortname alias = ဩစတြီးယား | flag alias = Flag of Austria.svg | flag alias-empire = Flag of the Habsburg Monarchy.svg | flag alias-state = Flag of Austria (state).svg | flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg | size = {{{size|}}} | name = {{{name|}}} | altlink = {{{altlink|}}} | variant = {{{variant|}}} <..."
17576
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဩစတြီးယားနိုင်ငံ
| shortname alias = ဩစတြီးယား
| flag alias = Flag of Austria.svg
| flag alias-empire = Flag of the Habsburg Monarchy.svg
| flag alias-state = Flag of Austria (state).svg
| flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = empire
| var2 = state
| var3 = war
| redir1 = AUT
| redir2 = Archduchy of Austria
| redir3 = Austria
| related1 = Austria-Hungary
</noinclude>
}}
j3cbse2x02x56aenw2ykty6acpagath
တမ်းပလိတ်:Country data Austria-Hungary
10
3781
17577
2026-03-29T12:03:25Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = Austria-Hungary | flag alias = Flag of Austria-Hungary (1867–1918).svg | flag alias-cisleithania = Flag of Austria-Hungary (1867–1918).svg | flag alias-transleithania = Civil Ensign of Hungary.svg | flag alias-merchant navy = Civil ensign of Austria Hungary.png | flag alias-civil = Civil ensign of Austria Hungary.png | flag alias-naval = Archduchy of Austria flag.svg | link alias-naval = Austro-Hungarian Na..."
17577
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = Austria-Hungary
| flag alias = Flag of Austria-Hungary (1867–1918).svg
| flag alias-cisleithania = Flag of Austria-Hungary (1867–1918).svg
| flag alias-transleithania = Civil Ensign of Hungary.svg
| flag alias-merchant navy = Civil ensign of Austria Hungary.png
| flag alias-civil = Civil ensign of Austria Hungary.png
| flag alias-naval = Archduchy of Austria flag.svg
| link alias-naval = Austro-Hungarian Navy
| flag alias-navy = Archduchy of Austria flag.svg
| link alias-navy = Austro-Hungarian Navy
| flag alias-army = Austrian Imperial Standard - Infantry pattern mix early 19th century.svg
| link alias-army = Austro-Hungarian Army
| link alias-military = Austro-Hungarian Armed Forces
| link alias-air force = Austro-Hungarian Aviation Troops
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| altvar = {{{altvar|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = cisleithania
| var2 = transleithania
| var3 = merchant navy
| var4 = civil
| redir1 = Austro-Hungary
</noinclude>
}}
g653n64smzn2iyiwmh1cp19cowba4xu
တမ်းပလိတ်:Country data နိုင်ငံ စာရင်းအင်း Austria
10
3782
17578
2026-03-29T12:04:55Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဩစတြီးယားနိုင်ငံ | shortname alias = ဩစတြီးယား | flag alias = Flag of Austria.svg | flag alias-empire = Flag of the Habsburg Monarchy.svg | flag alias-state = Flag of Austria (state).svg | flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg | size = {{{size|}}} | name = {{{name|}}} | altlink = {{{altlink|}}} | variant = {{{variant|}}} <..."
17578
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဩစတြီးယားနိုင်ငံ
| shortname alias = ဩစတြီးယား
| flag alias = Flag of Austria.svg
| flag alias-empire = Flag of the Habsburg Monarchy.svg
| flag alias-state = Flag of Austria (state).svg
| flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = empire
| var2 = state
| var3 = war
| redir1 = AUT
| redir2 = Archduchy of Austria
| redir3 = Austria
| related1 = Austria-Hungary
</noinclude>
}}
j3cbse2x02x56aenw2ykty6acpagath
တမ်းပလိတ်:နိုင်ငံ စာရင်းအင်း Austria
10
3783
17579
2026-03-29T12:05:10Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဩစတြီးယားနိုင်ငံ | shortname alias = ဩစတြီးယား | flag alias = Flag of Austria.svg | flag alias-empire = Flag of the Habsburg Monarchy.svg | flag alias-state = Flag of Austria (state).svg | flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg | size = {{{size|}}} | name = {{{name|}}} | altlink = {{{altlink|}}} | variant = {{{variant|}}} <..."
17579
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဩစတြီးယားနိုင်ငံ
| shortname alias = ဩစတြီးယား
| flag alias = Flag of Austria.svg
| flag alias-empire = Flag of the Habsburg Monarchy.svg
| flag alias-state = Flag of Austria (state).svg
| flag alias-war = Austria-Hungary-flag-1869-1914-naval-1786-1869-merchant.svg
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = empire
| var2 = state
| var3 = war
| redir1 = AUT
| redir2 = Archduchy of Austria
| redir3 = Austria
| related1 = Austria-Hungary
</noinclude>
}}
j3cbse2x02x56aenw2ykty6acpagath
တမ်းပလိတ်:Country data BHR
10
3784
17580
2026-03-29T12:07:10Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဘာရိန်းနိုင်ငံ | shortname alias = ဘာရိန်း | flag alias = Flag of Bahrain.svg | flag alias-old = Flag of Bahrain (before 1820).svg | flag alias-1820 = Flag of Bahrain (1820-1932).svg | flag alias-1932 = Flag of Bahrain (1932 to 1972).svg | flag alias-1972 = Flag of Bahrain (1972-2002).svg | link alias-naval = တော်ဝင်ဘာရိန်းရီတပ် | s..."
17580
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဘာရိန်းနိုင်ငံ
| shortname alias = ဘာရိန်း
| flag alias = Flag of Bahrain.svg
| flag alias-old = Flag of Bahrain (before 1820).svg
| flag alias-1820 = Flag of Bahrain (1820-1932).svg
| flag alias-1932 = Flag of Bahrain (1932 to 1972).svg
| flag alias-1972 = Flag of Bahrain (1972-2002).svg
| link alias-naval = တော်ဝင်ဘာရိန်းရီတပ်
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = 1972
| var2 = 1932
| var3 = 1820
| var4 = old
| redir1 = BHR
| redir2 = Bahrain
</noinclude>
}}
a7hgs8wz3j338lpvna310j36myld4hd
တမ်းပလိတ်:Country data Bahrain
10
3785
17581
2026-03-29T12:07:30Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဘာရိန်းနိုင်ငံ | shortname alias = ဘာရိန်း | flag alias = Flag of Bahrain.svg | flag alias-old = Flag of Bahrain (before 1820).svg | flag alias-1820 = Flag of Bahrain (1820-1932).svg | flag alias-1932 = Flag of Bahrain (1932 to 1972).svg | flag alias-1972 = Flag of Bahrain (1972-2002).svg | link alias-naval = တော်ဝင်ဘာရိန်းရီတပ် | s..."
17581
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဘာရိန်းနိုင်ငံ
| shortname alias = ဘာရိန်း
| flag alias = Flag of Bahrain.svg
| flag alias-old = Flag of Bahrain (before 1820).svg
| flag alias-1820 = Flag of Bahrain (1820-1932).svg
| flag alias-1932 = Flag of Bahrain (1932 to 1972).svg
| flag alias-1972 = Flag of Bahrain (1972-2002).svg
| link alias-naval = တော်ဝင်ဘာရိန်းရီတပ်
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = 1972
| var2 = 1932
| var3 = 1820
| var4 = old
| redir1 = BHR
| redir2 = Bahrain
</noinclude>
}}
a7hgs8wz3j338lpvna310j36myld4hd
တမ်းပလိတ်:Country data နိုင်ငံ စာရင်းအင်း Bahrain
10
3786
17582
2026-03-29T12:07:50Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဘာရိန်းနိုင်ငံ | shortname alias = ဘာရိန်း | flag alias = Flag of Bahrain.svg | flag alias-old = Flag of Bahrain (before 1820).svg | flag alias-1820 = Flag of Bahrain (1820-1932).svg | flag alias-1932 = Flag of Bahrain (1932 to 1972).svg | flag alias-1972 = Flag of Bahrain (1972-2002).svg | link alias-naval = တော်ဝင်ဘာရိန်းရီတပ် | s..."
17582
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဘာရိန်းနိုင်ငံ
| shortname alias = ဘာရိန်း
| flag alias = Flag of Bahrain.svg
| flag alias-old = Flag of Bahrain (before 1820).svg
| flag alias-1820 = Flag of Bahrain (1820-1932).svg
| flag alias-1932 = Flag of Bahrain (1932 to 1972).svg
| flag alias-1972 = Flag of Bahrain (1972-2002).svg
| link alias-naval = တော်ဝင်ဘာရိန်းရီတပ်
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = 1972
| var2 = 1932
| var3 = 1820
| var4 = old
| redir1 = BHR
| redir2 = Bahrain
</noinclude>
}}
a7hgs8wz3j338lpvna310j36myld4hd
တမ်းပလိတ်:နိုင်ငံ စာရင်းအင်း Bahrain
10
3787
17583
2026-03-29T12:08:07Z
YaThaWinTha
42
Created page with "{{ {{{1<noinclude>|country showdata</noinclude>}}} | alias = ဘာရိန်းနိုင်ငံ | shortname alias = ဘာရိန်း | flag alias = Flag of Bahrain.svg | flag alias-old = Flag of Bahrain (before 1820).svg | flag alias-1820 = Flag of Bahrain (1820-1932).svg | flag alias-1932 = Flag of Bahrain (1932 to 1972).svg | flag alias-1972 = Flag of Bahrain (1972-2002).svg | link alias-naval = တော်ဝင်ဘာရိန်းရီတပ် | s..."
17583
wikitext
text/x-wiki
{{ {{{1<noinclude>|country showdata</noinclude>}}}
| alias = ဘာရိန်းနိုင်ငံ
| shortname alias = ဘာရိန်း
| flag alias = Flag of Bahrain.svg
| flag alias-old = Flag of Bahrain (before 1820).svg
| flag alias-1820 = Flag of Bahrain (1820-1932).svg
| flag alias-1932 = Flag of Bahrain (1932 to 1972).svg
| flag alias-1972 = Flag of Bahrain (1972-2002).svg
| link alias-naval = တော်ဝင်ဘာရိန်းရီတပ်
| size = {{{size|}}}
| name = {{{name|}}}
| altlink = {{{altlink|}}}
| variant = {{{variant|}}}
<noinclude>
| var1 = 1972
| var2 = 1932
| var3 = 1820
| var4 = old
| redir1 = BHR
| redir2 = Bahrain
</noinclude>
}}
a7hgs8wz3j338lpvna310j36myld4hd
တမ်းပလိတ်:Edit
10
3788
17584
2026-03-29T16:08:32Z
YaThaWinTha
42
Created page with "<span class="noprint plainlinks">[{{fullurl:{{#if:{{{1|}}}|{{{1}}}|{{FULLPAGENAME}}}}|action=edit{{#if:{{{section|}}}|§ion={{{section}}}}}{{#if:{{{editintro|}}}|&editintro={{urlencode:{{{editintro}}}|wiki}}}}{{#if:{{{preload|}}}|&preload={{urlencode:{{{preload}}}|wiki}}}}{{#if:{{{preloadtitle|}}}|&preloadtitle={{urlencode:{{{preloadtitle}}}}}}}}} {{{2|ပြင်ဆင်ရန်}}}]</span><noinclude> {{documentation}} </noinclude>"
17584
wikitext
text/x-wiki
<span class="noprint plainlinks">[{{fullurl:{{#if:{{{1|}}}|{{{1}}}|{{FULLPAGENAME}}}}|action=edit{{#if:{{{section|}}}|§ion={{{section}}}}}{{#if:{{{editintro|}}}|&editintro={{urlencode:{{{editintro}}}|wiki}}}}{{#if:{{{preload|}}}|&preload={{urlencode:{{{preload}}}|wiki}}}}{{#if:{{{preloadtitle|}}}|&preloadtitle={{urlencode:{{{preloadtitle}}}}}}}}} {{{2|ပြင်ဆင်ရန်}}}]</span><noinclude>
{{documentation}}
</noinclude>
1zpdj2s277zshlw2381vtxygbpc05v1
တမ်းပလိတ်:Editnotice
10
3789
17585
2026-03-29T16:09:06Z
YaThaWinTha
42
Created page with "{{#ifeq:{{FULLROOTPAGENAME}}|Template:Editnotices |{{Editnotice/notice |expiry={{{expiry|¬}}} }} }}{{#ifexpr:{{#ifeq:{{FULLROOTPAGENAME}}|Template:Editnotices |1 |0 }}+{{#switch:{{{expiry|¬}}} |indefinite = 1 | |¬ = 1 <!-- Expiry not specified --> |#default = {{#iferror:{{#time:U|{{{expiry}}}}} |0 <!-- Invalid expiry time --> |{{#ifexpr:{{#time:U|{{{expiry}}}}}-{{#time:U|{{CURRENTTIMESTAMP}}}}>0 |1 <!-- Notice current --> |0 <..."
17585
wikitext
text/x-wiki
{{#ifeq:{{FULLROOTPAGENAME}}|Template:Editnotices
|{{Editnotice/notice
|expiry={{{expiry|¬}}}
}}
}}{{#ifexpr:{{#ifeq:{{FULLROOTPAGENAME}}|Template:Editnotices
|1
|0
}}+{{#switch:{{{expiry|¬}}}
|indefinite = 1
|
|¬ = 1 <!-- Expiry not specified -->
|#default = {{#iferror:{{#time:U|{{{expiry}}}}}
|0 <!-- Invalid expiry time -->
|{{#ifexpr:{{#time:U|{{{expiry}}}}}-{{#time:U|{{CURRENTTIMESTAMP}}}}>0
|1 <!-- Notice current -->
|0 <!-- Notice expired -->
}}
}}
}}
|{{fmbox
|type = {{{type|editnotice}}}
|id = {{{id|}}}
|textstyle = {{{textstyle|}}}
|style = {{{style|}}}
|class = {{{class|}}}
|image = {{#if:{{{image|}}}
|{{#invoke:InfoboxImage|InfoboxImage|image={{{image}}}|size={{{imagesize|}}}|sizedefault=40x40px}}
|none
}}
|imageright= {{#if:{{{imageright|}}}
|{{#invoke:InfoboxImage|InfoboxImage|image={{{imageright}}}|size={{{imagerightsize|}}}|sizedefault=40x40px}}
}}
|text = {{#if:{{{header|}}}
|<div style="font-weight: bold; {{{headerstyle|}}}">{{{header}}}</div>
}}
{{{text|{{{1}}}}}}
}}
}}{{#ifeq:{{FULLROOTPAGENAME}}|Template:Editnotices|{{#switch:{{{expiry|¬}}}
|indefinite
|
|¬ = <!-- Expiry not specified -->
|#default = {{#iferror:{{#time:U|{{{expiry}}}}}
| <!-- Invalid expiry time -->
|{{#ifexpr:{{#time:U|{{{expiry}}}}}-{{#time:U|{{CURRENTTIMESTAMP}}}}>0
| <!-- Notice current -->
|[[Category:Expired editnotices]] <!-- Notice expired -->
}}
}}
}}
}}<noinclude>
{{documentation}}
</noinclude>
6dxewt3dlpqf6uj03tqrt4wg3kcwxqb
တမ်းပလိတ်:Fmbox
10
3790
17586
2026-03-29T16:09:25Z
YaThaWinTha
42
Created page with "{{#invoke:Message box|fmbox}}<noinclude> {{documentation}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude>"
17586
wikitext
text/x-wiki
{{#invoke:Message box|fmbox}}<noinclude>
{{documentation}}
<!-- Add categories and interwikis to the /doc subpage, not here! -->
</noinclude>
q4qfnrd9je1n71bknyj9gdhs02g2rws
တမ်းပလိတ်:En icon
10
3791
17587
2026-03-29T16:09:52Z
YaThaWinTha
42
Created page with "{{Language icon|en|အင်္ဂလိပ်}}<noinclude> {{documentation}}<!-- Add cats and interwikis to the /doc subpage, not here. --></noinclude>"
17587
wikitext
text/x-wiki
{{Language icon|en|အင်္ဂလိပ်}}<noinclude>
{{documentation}}<!-- Add cats and interwikis to the /doc subpage, not here. --></noinclude>
hyhqns0c7ts5gx9snhhqupfv1fgbli4
တမ်းပလိတ်:ISO 639 name en
10
3792
17588
2026-03-29T16:10:17Z
YaThaWinTha
42
Created page with "အင်္ဂလိပ်<noinclude> {{ISO 639 name conversion template doc|explicitly cited English|en}} </noinclude>"
17588
wikitext
text/x-wiki
အင်္ဂလိပ်<noinclude>
{{ISO 639 name conversion template doc|explicitly cited English|en}}
</noinclude>
gxg2uwcm379t1uh5vweuftp377dpnp9
တမ်းပလိတ်:Extinct
10
3793
17589
2026-03-29T16:11:11Z
YaThaWinTha
42
Created page with "<span title="Extinct">{{noitalic|{{nobold|†}}}}</span><noinclude> {{documentation}} </noinclude>"
17589
wikitext
text/x-wiki
<span title="Extinct">{{noitalic|{{nobold|†}}}}</span><noinclude>
{{documentation}}
</noinclude>
ac0x1kottv5isvdopxu6tw2285rq575
တမ်းပလိတ်:Noitalic
10
3794
17590
2026-03-29T16:11:31Z
YaThaWinTha
42
Created page with "<span style="font-style:normal;">{{{1}}}</span><noinclude> {{documentation}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS TO THE /doc SUBPAGE, THANKS --> </noinclude>"
17590
wikitext
text/x-wiki
<span style="font-style:normal;">{{{1}}}</span><noinclude>
{{documentation}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS TO THE /doc SUBPAGE, THANKS -->
</noinclude>
gthkczmvzrkqtqwsi8thy1il8wm1ddj
တမ်းပလိတ်:Flagdeco
10
3795
17591
2026-03-29T16:12:05Z
YaThaWinTha
42
Created page with "{{နိုင်ငံ စာရင်းအင်း {{{1|}}}|flagdeco/core|variant={{{variant|{{{2|}}}}}}|size={{{size|}}}}}<noinclude>{{documentation}}</noinclude>"
17591
wikitext
text/x-wiki
{{နိုင်ငံ စာရင်းအင်း {{{1|}}}|flagdeco/core|variant={{{variant|{{{2|}}}}}}|size={{{size|}}}}}<noinclude>{{documentation}}</noinclude>
c143idz9945meqmm3kudk4locbjrnv7
တမ်းပလိတ်:Flagdeco/core
10
3796
17592
2026-03-29T16:12:28Z
YaThaWinTha
42
Created page with "<span class="flagicon">[[File:{{{flag alias-{{{variant}}}|{{{flag alias}}}}}}|{{#if:{{{size|}}}|{{{size}}}|23x15px}}|{{{border-{{{variant}}}|{{{border|border}}}}}} |alt=|link=]]</span><noinclude>{{documentation}}</noinclude>"
17592
wikitext
text/x-wiki
<span class="flagicon">[[File:{{{flag alias-{{{variant}}}|{{{flag alias}}}}}}|{{#if:{{{size|}}}|{{{size}}}|23x15px}}|{{{border-{{{variant}}}|{{{border|border}}}}}} |alt=|link=]]</span><noinclude>{{documentation}}</noinclude>
tk032eok3t36isurchip22z9pk19ifz
တမ်းပလိတ်:Fnote
10
3797
17593
2026-03-29T16:13:30Z
YaThaWinTha
42
Created page with "[[Help:Footnotes|{{#ifeq:{{{lc}}}|{{{lc|}}}|footnotes|Footnotes}}]]<noinclude> {{Documentation}} </noinclude>"
17593
wikitext
text/x-wiki
[[Help:Footnotes|{{#ifeq:{{{lc}}}|{{{lc|}}}|footnotes|Footnotes}}]]<noinclude>
{{Documentation}}
</noinclude>
3chlcadmzopy14bunnzskz78mq1shel
တမ်းပလိတ်:Fossilrange
10
3798
17594
2026-03-29T16:14:34Z
YaThaWinTha
42
Created page with "<includeonly><span style="display:inline-block;">{{{prefix|}}}</span><span style="display:inline-block;">{{{3|{{{text|{{{1}}}{{#if:{{{2|}}}|–{{{2|}}}}}{{#iferror:{{#expr:{{{1}}}}}|| [[:en:Megaannum|Ma]]}}}}}}}}</span>{{{ref|{{{reference|{{{refs|{{{references|}}}}}}}}}}}} <span style="display:inline-block;">{{{PS|{{{ps|}}}}}}</span>{{Phanerozoic 220px}}<!-- Fossil range marker --><div name=Range style="margin:0 auto; line-height:0; clear:both; width:220px; paddin..."
17594
wikitext
text/x-wiki
<includeonly><span style="display:inline-block;">{{{prefix|}}}</span><span style="display:inline-block;">{{{3|{{{text|{{{1}}}{{#if:{{{2|}}}|–{{{2|}}}}}{{#iferror:{{#expr:{{{1}}}}}|| [[:en:Megaannum|Ma]]}}}}}}}}</span>{{{ref|{{{reference|{{{refs|{{{references|}}}}}}}}}}}} <span style="display:inline-block;">{{{PS|{{{ps|}}}}}}</span>{{Phanerozoic 220px}}<!--
Fossil range marker
--><div name=Range style="margin:0 auto; line-height:0; clear:both; width:220px; padding:0px; height:8px; overflow:visible; background-color:transparent; position:relative; top:-4px; z-index:100;">{{fossil range/marker|{{#if:{{{earliest|}}}|{{#iferror:{{#expr:{{{earliest}}}}}|{{period start|{{{earliest}}}}}|{{{earliest}}}}}|{{#iferror:{{#expr:{{{1}}}}}|{{period start|{{{1}}}}}|{{{1}}}}}}}|{{#if:{{{latest|}}}|{{#iferror:{{#expr:{{{latest}}}}}|{{period end|{{{latest}}}}}|{{{latest}}}}}|{{#iferror:{{#expr:{{{2|{{{1}}}}}}}}|{{period end|{{{2|{{{1}}}}}}}}|{{{2|{{{1}}}}}}}}}}|42<!-- This determines the opacity of the bar-->}}
{{fossil range/marker|{{#iferror:{{#expr:{{{1}}}}}|{{period start|{{{1}}}}}|{{{1}}}}}|{{#iferror:{{#expr:{{{2|{{{1}}}}}}}}|{{period end|{{{2|{{{1}}}}}}}}|{{{2|{{{1}}}}}}}}}}
</div Range>
</div Timeline-row></includeonly><noinclude>{{template doc}}</noinclude>
3iy2mgtwwxx0lcqm8s7lsb093iukm16
တမ်းပလိတ်:Gain
10
3799
17595
2026-03-29T16:15:00Z
YaThaWinTha
42
Created page with "<span title="{{{1|Increase}}}">[[File:Increase2.svg|11px|alt={{{1|Increase}}}|link=]]</span><noinclude> {{documentation}} </noinclude>"
17595
wikitext
text/x-wiki
<span title="{{{1|Increase}}}">[[File:Increase2.svg|11px|alt={{{1|Increase}}}|link=]]</span><noinclude>
{{documentation}}
</noinclude>
aeki9q9jwwmrj85gula9dqt00plinfr
တမ်းပလိတ်:GeorgiaPhysiology
10
3800
17596
2026-03-29T16:15:27Z
YaThaWinTha
42
Created page with "''Essentials of Human Physiology'' by Thomas M. Nosek. Section {{{1}}}.<noinclude> {{Documentation}} </noinclude>"
17596
wikitext
text/x-wiki
''Essentials of Human Physiology'' by Thomas M. Nosek. Section {{{1}}}.<noinclude>
{{Documentation}}
</noinclude>
g05k54n8dnc1b5qgzrowu17q2ts7at3
တမ်းပလိတ်:High-use/num
10
3801
17597
2026-03-29T16:17:24Z
YaThaWinTha
42
Created page with "{{#iferror:{{#expr:0+{{{1}}}*1}}|များစွာသော|{{sigfig|{{{1}}}|2}} အပါးမှာခန့်}}"
17597
wikitext
text/x-wiki
{{#iferror:{{#expr:0+{{{1}}}*1}}|များစွာသော|{{sigfig|{{{1}}}|2}} အပါးမှာခန့်}}
ipj8ant892iio4ima7rdevimmcmst7k
တမ်းပလိတ်:High-use
10
3802
17598
2026-03-29T16:17:42Z
YaThaWinTha
42
Created page with "{{Ombox | type = style | image = [[File:Ambox warning yellow.svg|40px|alt=Warning|link=]] | text = '''ဒေ {{#switch:{{NAMESPACE}}|Module=Lua module|#default=တိမ်းပလိတ်ကို}} [https://tools.wmflabs.org/templatecount/index.php?lang=en&namespace={{NAMESPACENUMBER:{{FULLPAGENAME}}}}&name={{urlencode:{{ #switch: {{SUBPAGENAME}} | doc | sandbox = {{BASEPAGENAME}} | #default = {{PAGENAME}} }}}} {{High-use/num|1={{formatnum:{{#ifeq:{{str ends..."
17598
wikitext
text/x-wiki
{{Ombox
| type = style
| image = [[File:Ambox warning yellow.svg|40px|alt=Warning|link=]]
| text =
'''ဒေ {{#switch:{{NAMESPACE}}|Module=Lua module|#default=တိမ်းပလိတ်ကို}} [https://tools.wmflabs.org/templatecount/index.php?lang=en&namespace={{NAMESPACENUMBER:{{FULLPAGENAME}}}}&name={{urlencode:{{
#switch: {{SUBPAGENAME}}
| doc | sandbox = {{BASEPAGENAME}}
| #default = {{PAGENAME}}
}}}} {{High-use/num|1={{formatnum:{{#ifeq:{{str endswith|{{{1}}}|+}}|yes|{{str crop|{{{1}}}|1}}|{{{1}}}}}|R}}}} စာမျက်နှာ]'''၌ အသုံးပြုထားရေ၊ ယင်းအတွက်နန့် ပြောင်းလဲမှုမှန်သမျှစွာ ကျေပြန့်စွာ သတိပြုမိဖို့ဖြစ်တေ။ ကျေးဇူးပြုပြီးကေ ပြောင်းလဲမှုတိကို {{#switch:{{NAMESPACE}}|Module=module's|#default=တိမ်းပလိတ်ဧ့}} [[{{#switch: {{SUBPAGENAME}}
| doc | သဲပုံး = {{SUBJECTSPACE}}:{{BASEPAGENAME}}
| #default = {{SUBJECTPAGENAME}}
}}/sandbox|/sandbox]] သို့မဟုတ် [[{{#switch: {{SUBPAGENAME}}
| doc | sandbox = {{SUBJECTSPACE}}:{{BASEPAGENAME}}
| #default = {{SUBJECTPAGENAME}}
}}/testcases|/testcases]] စာမျက်နှာခွဲတိ {{#switch:{{NAMESPACE}}|Module=.|#default= သို့မဟုတ် သင်၏ကိုယ်ပိုင် [[Wikipedia:Subpages#How to create user subpages|အသုံးပြုသူ စာမျက်နှာခွဲ]]မာ စမ်းသပ်ပါ။}} ပြုပျင်မှု မလုပ်ဆောင်ခင် {{#if:{{{2|}}}|၌ [[{{{2}}}]]|ကျေးဇူးပြုပြီးကေ [[{{#switch: {{SUBPAGENAME}}
| doc | sandbox = {{TALKSPACE}}:{{BASEPAGENAME}}
| #default = {{TALKPAGENAME}}
}}|ဆွီးနွီးချက် စာမျက်နှာ]]}}မာ ဆွီးနွီးရန် စိုင်းစားပါ။
}}<noinclude>
{{Documentation}}
<!-- Add categories to the /doc subpage; interwiki links go to Wikidata, thank you! -->
</noinclude>
dktdg54blxhkufgypaj839a72zk3oxf
တမ်းပလိတ်:High use
10
3803
17599
2026-03-29T16:18:21Z
YaThaWinTha
42
Created page with "{{Ombox | type = style | image = [[File:Ambox warning yellow.svg|40px|alt=Warning|link=]] | text = '''ဒေ {{#switch:{{NAMESPACE}}|Module=Lua module|#default=တိမ်းပလိတ်ကို}} [https://tools.wmflabs.org/templatecount/index.php?lang=en&namespace={{NAMESPACENUMBER:{{FULLPAGENAME}}}}&name={{urlencode:{{ #switch: {{SUBPAGENAME}} | doc | sandbox = {{BASEPAGENAME}} | #default = {{PAGENAME}} }}}} {{High-use/num|1={{formatnum:{{#ifeq:{{str ends..."
17599
wikitext
text/x-wiki
{{Ombox
| type = style
| image = [[File:Ambox warning yellow.svg|40px|alt=Warning|link=]]
| text =
'''ဒေ {{#switch:{{NAMESPACE}}|Module=Lua module|#default=တိမ်းပလိတ်ကို}} [https://tools.wmflabs.org/templatecount/index.php?lang=en&namespace={{NAMESPACENUMBER:{{FULLPAGENAME}}}}&name={{urlencode:{{
#switch: {{SUBPAGENAME}}
| doc | sandbox = {{BASEPAGENAME}}
| #default = {{PAGENAME}}
}}}} {{High-use/num|1={{formatnum:{{#ifeq:{{str endswith|{{{1}}}|+}}|yes|{{str crop|{{{1}}}|1}}|{{{1}}}}}|R}}}} စာမျက်နှာ]'''၌ အသုံးပြုထားရေ၊ ယင်းအတွက်နန့် ပြောင်းလဲမှုမှန်သမျှစွာ ကျေပြန့်စွာ သတိပြုမိဖို့ဖြစ်တေ။ ကျေးဇူးပြုပြီးကေ ပြောင်းလဲမှုတိကို {{#switch:{{NAMESPACE}}|Module=module's|#default=တိမ်းပလိတ်ဧ့}} [[{{#switch: {{SUBPAGENAME}}
| doc | သဲပုံး = {{SUBJECTSPACE}}:{{BASEPAGENAME}}
| #default = {{SUBJECTPAGENAME}}
}}/sandbox|/sandbox]] သို့မဟုတ် [[{{#switch: {{SUBPAGENAME}}
| doc | sandbox = {{SUBJECTSPACE}}:{{BASEPAGENAME}}
| #default = {{SUBJECTPAGENAME}}
}}/testcases|/testcases]] စာမျက်နှာခွဲတိ {{#switch:{{NAMESPACE}}|Module=.|#default= သို့မဟုတ် သင်၏ကိုယ်ပိုင် [[Wikipedia:Subpages#How to create user subpages|အသုံးပြုသူ စာမျက်နှာခွဲ]]မာ စမ်းသပ်ပါ။}} ပြုပျင်မှု မလုပ်ဆောင်ခင် {{#if:{{{2|}}}|၌ [[{{{2}}}]]|ကျေးဇူးပြုပြီးကေ [[{{#switch: {{SUBPAGENAME}}
| doc | sandbox = {{TALKSPACE}}:{{BASEPAGENAME}}
| #default = {{TALKPAGENAME}}
}}|ဆွီးနွီးချက် စာမျက်နှာ]]}}မာ ဆွီးနွီးရန် စိုင်းစားပါ။
}}<noinclude>
{{Documentation}}
<!-- Add categories to the /doc subpage; interwiki links go to Wikidata, thank you! -->
</noinclude>
dktdg54blxhkufgypaj839a72zk3oxf
တမ်းပလိတ်:IPA-sa
10
3804
17600
2026-03-29T16:19:47Z
YaThaWinTha
42
Created page with "<onlyinclude><small>{{#switch: {{{2}}}|IPA=IPA: |lang=သင်္သကရိုက်: |langcl=Classical Sanskrit: |langvd=Vedic Sanskrit: |pron=pronounced |cl=Classical Sanskrit pronunciation: |vd=Vedic Sanskrit pronunciation: |=|သင်္သကရိုက် အသံထွက်: }}</small>{{IPA|[[Help:IPA/Sanskrit|[{{{1}}}]]]}}{{#if:{{{3|}}}|{{IPA audio link|{{{3}}} }} }}</onlyinclude> <noinclude>{{documentation}}</noincl..."
17600
wikitext
text/x-wiki
<onlyinclude><small>{{#switch: {{{2}}}|IPA=IPA: |lang=သင်္သကရိုက်: |langcl=Classical Sanskrit: |langvd=Vedic Sanskrit: |pron=pronounced |cl=Classical Sanskrit pronunciation: |vd=Vedic Sanskrit pronunciation: |=|သင်္သကရိုက် အသံထွက်: }}</small>{{IPA|[[Help:IPA/Sanskrit|[{{{1}}}]]]}}{{#if:{{{3|}}}|{{IPA audio link|{{{3}}} }} }}</onlyinclude>
<noinclude>{{documentation}}</noinclude>
oa1oq041cs176l4iu7jpobn7exjvi6q
တမ်းပလိတ်:ISO639-2
10
3805
17601
2026-03-29T16:20:56Z
YaThaWinTha
42
Created page with "<span class="plainlinks">[https://www.loc.gov/standards/iso639-2/php/langcodes_name.php?code_ID={{#switch:{{{1|}}} |aar=1 |abk=2 |ace=3 |ach=4 |ada=5 |ady=6 |afa=7 |afh=8 |afr=9 |ain=10 |aka=11 |akk=12 |alb=14 |ale=15 |alg=16 |alt=17 |amh=18 |ang=19 |anp=20 |apa=21 |ara=22 |arc=23 |arg=24 |arm=26 |arn=27 |arp=28 |art=29 |arw=30 |asm=31 |ast=32 |ath=33 |aus=34 |ava=35 |ave=36 |awa=37 |aym=38 |aze=39 |bad=40 |bai=41 |bak=42 |bal=43 |bam=44 |ban=45 |baq=47 |bas=48 |bat=49 |..."
17601
wikitext
text/x-wiki
<span class="plainlinks">[https://www.loc.gov/standards/iso639-2/php/langcodes_name.php?code_ID={{#switch:{{{1|}}}
|aar=1
|abk=2
|ace=3
|ach=4
|ada=5
|ady=6
|afa=7
|afh=8
|afr=9
|ain=10
|aka=11
|akk=12
|alb=14
|ale=15
|alg=16
|alt=17
|amh=18
|ang=19
|anp=20
|apa=21
|ara=22
|arc=23
|arg=24
|arm=26
|arn=27
|arp=28
|art=29
|arw=30
|asm=31
|ast=32
|ath=33
|aus=34
|ava=35
|ave=36
|awa=37
|aym=38
|aze=39
|bad=40
|bai=41
|bak=42
|bal=43
|bam=44
|ban=45
|baq=47
|bas=48
|bat=49
|bej=50
|bel=51
|bem=52
|ben=53
|ber=54
|bho=55
|bih=56
|bik=57
|bin=58
|bis=59
|bla=60
|bnt=61
|bod=447
|bos=62
|bra=63
|bre=64
|btk=65
|bua=66
|bug=67
|bul=68
|bur=70
|byn=71
|cad=72
|cai=73
|car=74
|cat=75
|cau=76
|ceb=77
|cel=78
|ces=107
|cha=79
|chb=80
|che=81
|chg=82
|chi=84
|chk=85
|chm=86
|chn=87
|cho=88
|chp=89
|chr=90
|chu=91
|chv=92
|chy=93
|cmc=94
|cnr=515
|cop=95
|cor=96
|cos=97
|cpe=98
|cpf=99
|cpp=100
|cre=101
|crh=102
|crp=103
|csb=104
|cus=105
|cym=487
|cze=107
|dak=108
|dan=109
|dar=110
|day=111
|del=112
|den=113
|deu=160
|dgr=114
|din=115
|div=116
|doi=117
|dra=118
|dsb=119
|dua=120
|dum=121
|dut=123
|dyu=124
|dzo=125
|efi=126
|egy=127
|eka=128
|ell=175
|elx=129
|eng=130
|enm=131
|epo=132
|est=133
|eus=47
|ewe=134
|ewo=135
|fan=136
|fao=137
|fas=357
|fat=138
|fij=139
|fil=140
|fin=141
|fiu=142
|fon=143
|fra=145
|fre=145
|frm=146
|fro=147
|frr=148
|frs=149
|fry=150
|ful=151
|fur=152
|gaa=153
|gay=154
|gba=155
|gem=156
|geo=158
|ger=160
|gez=161
|gil=162
|gla=163
|gle=164
|glg=165
|glv=166
|gmh=167
|goh=168
|gon=169
|gor=170
|got=171
|grb=172
|grc=173
|gre=175
|grn=176
|gsw=177
|guj=178
|gwi=179
|hai=180
|hat=181
|hau=182
|haw=183
|heb=184
|her=185
|hil=186
|him=187
|hin=188
|hit=189
|hmn=190
|hmo=191
|hrv=394
|hsb=192
|hun=193
|hup=194
|hye=26
|iba=195
|ibo=196
|ice=198
|ido=199
|iii=200
|ijo=201
|iku=202
|ile=203
|ilo=204
|ina=205
|inc=206
|ind=207
|ine=208
|inh=209
|ipk=210
|ira=211
|iro=212
|isl=198
|ita=213
|jav=214
|jbo=215
|jpn=216
|jpr=217
|jrb=218
|kaa=219
|kab=220
|kac=221
|kal=222
|kam=223
|kan=224
|kar=225
|kas=226
|kat=158
|kau=227
|kaw=228
|kaz=229
|kbd=230
|kha=231
|khi=232
|khm=233
|kho=234
|kik=235
|kin=236
|kir=237
|kmb=238
|kok=239
|kom=240
|kon=241
|kor=242
|kos=243
|kpe=244
|krc=245
|krl=246
|kro=247
|kru=248
|kua=249
|kum=250
|kur=251
|kut=252
|lad=253
|lah=254
|lam=255
|lao=256
|lat=257
|lav=258
|lez=259
|lim=260
|lin=261
|lit=262
|lol=263
|loz=264
|ltz=265
|lua=266
|lub=267
|lug=268
|lui=269
|lun=270
|luo=271
|lus=272
|mac=274
|mad=275
|mag=276
|mah=277
|mai=278
|mak=279
|mal=280
|man=281
|mao=283
|map=284
|mar=285
|mas=286
|may=288
|mdf=289
|mdr=290
|men=291
|mga=292
|mic=293
|min=294
|mis=295
|mkd=274
|mkh=296
|mlg=297
|mlt=298
|mnc=299
|mni=300
|mno=301
|moh=302
|mon=304
|mos=305
|mri=283
|msa=288
|mul=306
|mun=307
|mus=308
|mwl=309
|mwr=310
|mya=70
|myn=311
|myv=312
|nah=313
|nai=314
|nap=315
|nau=316
|nav=317
|nbl=318
|nde=319
|ndo=320
|nds=321
|nep=322
|new=323
|nia=324
|nic=325
|niu=326
|nld=123
|nno=327
|nob=328
|nog=329
|non=330
|nor=331
|nqo=506
|nso=332
|nub=333
|nwc=334
|nya=335
|nym=336
|nyn=337
|nyo=338
|nzi=339
|oci=340
|oji=341
|ori=342
|orm=343
|osa=344
|oss=345
|ota=346
|oto=347
|paa=348
|pag=349
|pal=350
|pam=351
|pan=352
|pap=353
|pau=354
|peo=355
|per=357
|phi=358
|phn=359
|pli=360
|pol=361
|pon=362
|por=363
|pra=364
|pro=365
|pus=366
|qaa-qtz=367
|que=368
|raj=369
|rap=370
|rar=371
|roa=372
|roh=373
|rom=374
|ron=376
|rum=376
|run=377
|rup=378
|rus=379
|sad=380
|sag=381
|sah=382
|sai=383
|sal=384
|sam=385
|san=386
|sas=387
|sat=388
|scn=391
|sco=392
|sel=395
|sem=396
|sga=397
|sgn=398
|shn=399
|sid=400
|sin=401
|sio=402
|sit=403
|sla=404
|slk=406
|slo=406
|slv=407
|sma=408
|sme=409
|smi=410
|smj=411
|smn=412
|smo=413
|sms=414
|sna=415
|snd=416
|snk=417
|sog=418
|som=419
|son=420
|sot=421
|spa=422
|sqi=14
|srd=423
|srn=424
|srp=390
|srr=425
|ssa=426
|ssw=427
|suk=428
|sun=429
|sus=430
|sux=431
|swa=432
|swe=433
|syc=511
|syr=434
|tah=435
|tai=436
|tam=437
|tat=438
|tel=439
|tem=440
|ter=441
|tet=442
|tgk=443
|tgl=444
|tha=445
|tib=447
|tig=448
|tir=449
|tiv=450
|tkl=451
|tlh=452
|tli=453
|tmh=454
|tog=455
|ton=456
|tpi=457
|tsi=458
|tsn=459
|tso=460
|tuk=461
|tum=462
|tup=463
|tur=464
|tut=465
|tvl=466
|twi=467
|tyv=468
|udm=469
|uga=470
|uig=471
|ukr=472
|umb=473
|und=474
|urd=475
|uzb=476
|vai=477
|ven=478
|vie=479
|vol=480
|vot=481
|wak=482
|wal=483
|war=484
|was=485
|wel=487
|wen=488
|wln=489
|wol=490
|xal=491
|xho=492
|yao=493
|yap=494
|yid=495
|yor=496
|ypk=497
|zap=498
|zbl=512
|zen=499
|zgh=514
|zha=500
|zho=84
|znd=501
|zul=502
|zun=503
|zxx=504
|zza=510
}} {{{2|{{{1}}}}}}]</span><noinclude>
{{Documentation}}
</noinclude>
5lgt35fsbbu5jjz7hm5dspaa95e3544
တမ်းပလိတ်:ISO 639 name th
10
3806
17602
2026-03-29T16:22:12Z
YaThaWinTha
42
Created page with "ထိုင်း<noinclude> {{ISO 639 name conversion template doc|{{ISO 639 name th}}|th}}</noinclude>"
17602
wikitext
text/x-wiki
ထိုင်း<noinclude>
{{ISO 639 name conversion template doc|{{ISO 639 name th}}|th}}</noinclude>
4xgtyovr01d5tr9mih1rftvc285dj58
တမ်းပလိတ်:Ill
10
3807
17603
2026-03-29T16:22:47Z
YaThaWinTha
42
Created page with "<includeonly>[[{{{1}}}{{{{{|safesubst:}}}#if:{{{lt|}}}|{{{{{|safesubst:}}}!}}{{{lt}}}}}]]{{{{{|safesubst:}}}#ifeq:{{subst:Substcheck}}|SUBST||{{#if:{{#ifexist:{{{1|}}}|{{#invoke:redirect|isRedirect|{{{1|}}}}}|1}}{{{preserve|{{{display|}}}}}} |<{{#switch:{{{vertical-align|}}}|sup|super=sup|sub=sub|span}} class="noprint" style="{{#switch:{{{vertical-align|}}}|sup|super|sub=|font-size:85%;}} font-style: normal; {{#if:{{{nobold|}}}|font-weight: normal;}}">{{#switch:{{{verti..."
17603
wikitext
text/x-wiki
<includeonly>[[{{{1}}}{{{{{|safesubst:}}}#if:{{{lt|}}}|{{{{{|safesubst:}}}!}}{{{lt}}}}}]]{{{{{|safesubst:}}}#ifeq:{{subst:Substcheck}}|SUBST||{{#if:{{#ifexist:{{{1|}}}|{{#invoke:redirect|isRedirect|{{{1|}}}}}|1}}{{{preserve|{{{display|}}}}}}
|<{{#switch:{{{vertical-align|}}}|sup|super=sup|sub=sub|span}} class="noprint" style="{{#switch:{{{vertical-align|}}}|sup|super|sub=|font-size:85%;}} font-style: normal; {{#if:{{{nobold|}}}|font-weight: normal;}}">{{#switch:{{{vertical-align|}}}|sup|super=[| (}}{{#if:{{{WD|}}}
| [[d:{{{WD}}}#sitelinks-wikipedia|<span title=""{{{1}}}" in other languages">Wikidata</span>]]<!--
-->{{#if:{{{reasonator|}}}|<nowiki />; [//tools.wmflabs.org/reasonator/?q={{urlencode:{{{WD}}}}} Reasonator]}}
| {{Separated entries|separator=; 
| {{#if:{{{2|}}}|[[:{{{2}}}:{{#if:{{{3|}}}|{{{3}}}|{{{1}}}}}|{{{2}}}]][[Category:Interlanguage link template link number|A]]}}
| {{#if:{{{4|}}}|[[:{{{4}}}:{{#if:{{{5|}}}|{{{5}}}|{{{1}}}}}|{{{4}}}]][[Category:Interlanguage link template link number|B]]}}
| {{#if:{{{6|}}}|[[:{{{6}}}:{{#if:{{{7|}}}|{{{7}}}|{{{1}}}}}|{{{6}}}]][[Category:Interlanguage link template link number|C]]}}
| {{#if:{{{8|}}}{{{10|}}}{{{12|}}}|{{Separated entries|separator=; 
| {{#if:{{{8|}}}|[[:{{{8}}}:{{#if:{{{9|}}}|{{{9}}}|{{{1}}}}}|{{{8}}}]][[Category:Interlanguage link template link number|D]]}}
| {{#if:{{{10|}}}|[[:{{{10}}}:{{#if:{{{11|}}}|{{{11}}}|{{{1}}}}}|{{{10}}}]][[Category:Interlanguage link template link number|E]]}}
| {{#if:{{{12|}}}|[[:{{{12}}}:{{#if:{{{13|}}}|{{{13}}}|{{{1}}}}}|{{{12}}}]][[Category:Interlanguage link template link number|F]]}}
| {{#if:{{{14|}}}|[[:{{{14}}}:{{#if:{{{15|}}}|{{{15}}}|{{{1}}}}}|{{{14}}}]][[Category:Interlanguage link template link number|G]]}}
| {{#if:{{{16|}}}|[[:{{{16}}}:{{#if:{{{17|}}}|{{{17}}}|{{{1}}}}}|{{{16}}}]][[Category:Interlanguage link template link number|H]]}}
| {{#if:{{{18|}}}|[[:{{{18}}}:{{#if:{{{19|}}}|{{{19}}}|{{{1}}}}}|{{{18}}}]][[Category:Interlanguage link template link number|I]]}}
| {{#if:{{{20|}}}|[[:{{{20}}}:{{#if:{{{21|}}}|{{{21}}}|{{{1}}}}}|{{{20}}}]][[Category:Interlanguage link template link number|J]]}}
| {{#if:{{{22|}}}|[[:{{{22}}}:{{#if:{{{23|}}}|{{{23}}}|{{{1}}}}}|{{{22}}}]][[Category:Interlanguage link template link number|K]]}}
| {{#if:{{{24|}}}|[[:{{{24}}}:{{#if:{{{25|}}}|{{{25}}}|{{{1}}}}}|{{{24}}}]][[Category:Interlanguage link template link number|L]]}}
}}}}
| {{#if:{{{reasonator|}}}|[//tools.wmflabs.org/reasonator/test/?find={{urlencode:{{{1}}}}} Reasonator search]}}
}}}}{{#switch:{{{vertical-align|}}}|sup|super=]|)}}</{{#switch:{{{vertical-align|}}}|sup|super=sup|sub=sub|span}}>
| [[Category:Interlanguage link template existing link]]<nowiki />
}}}}</includeonly><noinclude>
{{documentation}}
</noinclude>
jr2kv1ej8p541scy6xhf68e6l8j82j2
Module:Infobox mapframe
828
3808
17604
2026-03-29T16:24:39Z
YaThaWinTha
42
Created page with "local mf = require('Module:Mapframe') local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local infoboxImage = require('Module:InfoboxImage').InfoboxImage -- Defaults local DEFAULT_FRAME_WIDTH = "270" local DEFAULT_FRAME_HEIGHT = "200" local DEFAULT_ZOOM = 10 local DEFAULT_GEOMASK_STROKE_WIDTH = "1" local DEFAULT_GEOMASK_STROKE_COLOR = "#777777" local DEFAULT_GEOMASK_FILL = "#888888" local DEFAULT_GEOMASK_FILL_OPACITY = "0.5" local..."
17604
Scribunto
text/plain
local mf = require('Module:Mapframe')
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local infoboxImage = require('Module:InfoboxImage').InfoboxImage
-- Defaults
local DEFAULT_FRAME_WIDTH = "270"
local DEFAULT_FRAME_HEIGHT = "200"
local DEFAULT_ZOOM = 10
local DEFAULT_GEOMASK_STROKE_WIDTH = "1"
local DEFAULT_GEOMASK_STROKE_COLOR = "#777777"
local DEFAULT_GEOMASK_FILL = "#888888"
local DEFAULT_GEOMASK_FILL_OPACITY = "0.5"
local DEFAULT_SHAPE_STROKE_WIDTH = "3"
local DEFAULT_SHAPE_STROKE_COLOR = "#FF0000"
local DEFAULT_SHAPE_FILL = "#606060"
local DEFAULT_SHAPE_FILL_OPACITY = "0.5"
local DEFAULT_LINE_STROKE_WIDTH = "5"
local DEFAULT_LINE_STROKE_COLOR = "#FF0000"
local DEFAULT_MARKER_COLOR = "#5E74F3"
-- Trim whitespace from args, and remove empty args
function trimArgs(argsTable)
local cleanArgs = {}
for key, val in pairs(argsTable) do
if type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val ~= '' then
cleanArgs[key] = val
end
else
cleanArgs[key] = val
end
end
return cleanArgs
end
function getBestStatement(item_id, property_id)
if not(item_id) or not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then
return false
end
local statements = mw.wikibase.getBestStatements(item_id, property_id)
if not statements or #statements == 0 then
return false
end
local hasNoValue = ( statements[1].mainsnak and statements[1].mainsnak.snaktype == 'novalue' )
if hasNoValue then
return false
end
return statements[1]
end
function hasWikidataProperty(item_id, property_id)
return getBestStatement(item_id, property_id) and true or false
end
function getStatementValue(statement)
return statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value or nil
end
function relatedEntity(item_id, property_id)
local value = getStatementValue( getBestStatement(item_id, property_id) )
return value and value.id or false
end
function idType(id)
if not id then
return nil
elseif mw.ustring.match(id, "[Pp]%d+") then
return "property"
elseif mw.ustring.match(id, "[Qq]%d+") then
return "item"
else
return nil
end
end
function getZoom(value, unit)
local length_km
if unit == 'km' then
length_km = tonumber(value)
elseif unit == 'mi' then
length_km = tonumber(value)*1.609344
elseif unit == 'km2' then
length_km = math.sqrt(tonumber(value))
elseif unit == 'mi2' then
length_km = math.sqrt(tonumber(value))*1.609344
end
-- max for zoom 2 is 6400km, for zoom 3 is 3200km, for zoom 4 is 1600km, etc
local zoom = math.floor(8 - (math.log10(length_km) - 2)/(math.log10(2)))
-- limit to values below 17
zoom = math.min(17, zoom)
-- take off 1 when calculated from area, to account for unusual shapes
if unit == 'km2' or unit == 'mi2' then
zoom = zoom - 1
end
-- minimum value is 1
return math.max(1, zoom)
end
function shouldAutoRun(frame)
-- Check if should be running
local explicitlyOn = yesno(mw.text.trim(frame.getParent(frame).args.mapframe or "")) -- true of false or nil
local onByDefault = (explicitlyOn == nil) and yesno(mw.text.trim(frame.args.onByDefault or ""), false) -- true or false
return explicitlyOn or onByDefault
end
function argsFromAuto(frame)
-- Get args from the frame (invoke call) and the parent (template call).
-- Frame arguments are default values which are overridden by parent values
-- when both are present
local args = getArgs(frame, {parentFirst = true})
-- Discard args not prefixed with "mapframe-", remove that prefix from those that remain
local fixedArgs = {}
for name, val in pairs(args) do
local fixedName = string.match(name, "^mapframe%-(.+)$" )
if fixedName then
fixedArgs[fixedName] = val
-- allow coord, coordinates, etc to be unprefixed
elseif name == "coordinates" or name == "coord" or name == "coordinate" and not fixedArgs.coord then
fixedArgs.coord = val
-- allow id, qid to be unprefixed, map to id (if not already present)
elseif name == "id" or name == "qid" and not fixedArgs.id then
fixedArgs.id = val
end
end
return fixedArgs
end
local p = {}
p.autocaption = function(frame)
if not shouldAutoRun(frame) then return "" end
local args = argsFromAuto(frame)
if args.caption then
return args.caption
elseif args.switcher then
return ""
end
local maskItem
local maskType = idType(args.geomask)
if maskType == 'item' then
maskItem = args.geomask
elseif maskType == "property" then
maskItem = relatedEntity(args.id or mw.wikibase.getEntityIdForCurrentPage(), args.geomask)
end
local maskItemLabel = maskItem and mw.wikibase.getLabel( maskItem )
return maskItemLabel and "Location in "..maskItemLabel or ""
end
function parseCustomWikitext(customWikitext)
-- infoboxImage will format an image if given wikitext containing an
-- image, or else pass through the wikitext unmodified
return infoboxImage({
args = {
image = customWikitext
}
})
end
p.auto = function(frame)
if not shouldAutoRun(frame) then return "" end
local args = argsFromAuto(frame)
if args.custom then
return frame:preprocess(parseCustomWikitext(args.custom))
end
local mapframe = p._main(args)
return frame:preprocess(mapframe)
end
p.main = function(frame)
local parent = frame.getParent(frame)
local parentArgs = parent.args
local mapframe = p._main(parentArgs)
return frame:preprocess(mapframe)
end
p._main = function(_config)
-- `config` is the args passed to this module
local config = trimArgs(_config)
-- Require wikidata item, or specified coords
local wikidataId = config.id or mw.wikibase.getEntityIdForCurrentPage()
if not(wikidataId) and not(config.coord) then
return ''
end
-- Require coords (specified or from wikidata), so that map will be centred somewhere
-- (P625 = coordinate location)
local hasCoordinates = hasWikidataProperty(wikidataId, 'P625') or config.coordinates or config.coord
if not hasCoordinates then
return ''
end
-- `args` is the arguments which will be passed to the mapframe module
local args = {}
-- Some defaults/overrides for infobox presentation
args.display = "inline"
args.frame = "yes"
args.plain = "yes"
args["frame-width"] = config["frame-width"] or config.width or DEFAULT_FRAME_WIDTH
args["frame-height"] = config["frame-height"] or config.height or DEFAULT_FRAME_HEIGHT
args["frame-align"] = "center"
args["frame-coord"] = config["frame-coordinates"] or config["frame-coord"] or ""
-- Note: config["coordinates"] or config["coord"] should not be used for the alignment of the frame;
-- see talk page ( https://en.wikipedia.org/wiki/Special:Diff/876492931 )
-- deprecated lat and long parameters
args["frame-lat"] = config["frame-lat"] or config["frame-latitude"] or ""
args["frame-long"] = config["frame-long"] or config["frame-longitude"] or ""
-- Calculate zoom from length or area (converted to km or km2)
if config.length_km then
args.zoom = getZoom(config.length_km, 'km')
elseif config.length_mi then
args.zoom = getZoom(config.length_mi, 'mi')
elseif config.area_km2 then
args.zoom = getZoom(config.area_km2, 'km2')
elseif config.area_mi2 then
args.zoom = getZoom(config.area_mi2, 'mi2')
else
args.zoom = config.zoom or DEFAULT_ZOOM
end
-- Conditionals: whether point, geomask should be shown
local hasOsmRelationId = hasWikidataProperty(wikidataId, 'P402') -- P402 is OSM relation ID
local shouldShowPointMarker;
if config.point == "on" then
shouldShowPointMarker = true
elseif config.point == "none" then
shouldShowPointMarker = false
else
shouldShowPointMarker = not(hasOsmRelationId) or (config.marker and config.marker ~= 'none') or (config.coordinates or config.coord)
end
local shouldShowShape = config.shape ~= 'none'
local shapeType = config.shape == 'inverse' and 'shape-inverse' or 'shape'
local shouldShowLine = config.line ~= 'none'
local maskItem
local useWikidata = wikidataId and true or false -- Use shapes/lines based on wikidata id, if there is one
-- But do not use wikidata when local coords are specified (and not turned off), unless explicitly set
if useWikidata and config.coord and shouldShowPointMarker then
useWikidata = config.wikidata and true or false
end
-- Switcher
if config.switcher == "zooms" then
-- switching between zoom levels
local maxZoom = math.max(tonumber(args.zoom), 3) -- what zoom would have otherwise been (if 3 or more, otherwise 3)
local minZoom = 1 -- completely zoomed out
local midZoom = math.floor((maxZoom + minZoom)/2) -- midway between maxn and min
args.switch = "zoomed in, zoomed midway, zoomed out"
args.zoom = string.format("SWITCH:%d,%d,%d", maxZoom, midZoom, minZoom)
elseif config.switcher == "auto" then
-- switching between P276 and P131 areas with recursive lookup, e.g. item's city,
-- that city's state, and that state's country
args.zoom = nil -- let kartographer determine the zoom
local maskLabels = {}
local maskItems = {}
local maskItemId = relatedEntity(wikidataId, "P276") or relatedEntity(wikidataId, "P131")
local maskLabel = mw.wikibase.getLabel(maskItemId)
while maskItemId and maskLabel and mw.text.trim(maskLabel) ~= "" do
table.insert(maskLabels, maskLabel)
table.insert(maskItems, maskItemId)
maskItemId = maskItemId and relatedEntity(maskItemId, "P131")
maskLabel = maskItemId and mw.wikibase.getLabel(maskItemId)
end
if #maskLabels > 1 then
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
elseif #maskLabels == 1 then
maskItem = maskItemId[1]
end
elseif config.switcher == "geomasks" and config.geomask then
-- switching between items in geomask parameter
args.zoom = nil -- let kartographer determine the zoom
local separator = (mw.ustring.find(config.geomask, "###", 0, true ) and "###") or
(mw.ustring.find(config.geomask, ";", 0, true ) and ";") or ","
local pattern = "%s*"..separator.."%s*"
local maskItems = mw.text.split(mw.ustring.gsub(config.geomask, "SWITCH:", ""), pattern)
local maskLabels = {}
if #maskItems > 1 then
for i, item in ipairs(maskItems) do
table.insert(maskLabels, mw.wikibase.getLabel(item))
end
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
end
end
-- resolve geomask item id (if not using geomask switcher)
if not maskItem then --
local maskType = idType(config.geomask)
if maskType == 'item' then
maskItem = config.geomask
elseif maskType == "property" then
maskItem = relatedEntity(wikidataId, config.geomask)
end
end
-- Keep track of arg numbering
local argNumber = ''
local function incrementArgNumber()
if argNumber == '' then
argNumber = 2
else
argNumber = argNumber + 1
end
end
-- Geomask
if maskItem then
args["type"..argNumber] = "shape-inverse"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = config["geomask-stroke-width"] or DEFAULT_GEOMASK_STROKE_WIDTH
args["stroke-color"..argNumber] = config["geomask-stroke-color"] or config["geomask-stroke-colour"] or DEFAULT_GEOMASK_STROKE_COLOR
args["fill"..argNumber] = config["geomask-fill"] or DEFAULT_GEOMASK_FILL
args["fill-opacity"..argNumber] = config["geomask-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
-- Let kartographer determine zoom and position, unless it is explicitly set in config
if not config.zoom and not config.switcher then
args.zoom = nil
args["frame-coord"] = nil
args["frame-lat"] = nil
args["frame-long"] = nil
local maskArea = getStatementValue( getBestStatement(maskItem, 'P2046') )
end
incrementArgNumber()
-- Hack to fix phab:T255932
if not args.zoom then
args["type"..argNumber] = "line"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = 0
incrementArgNumber()
end
end
-- Shape (or shape-inverse)
if useWikidata and shouldShowShape then
args["type"..argNumber] = shapeType
if config.id then args["id"..argNumber] = config.id end
args["stroke-width"..argNumber] = config["shape-stroke-width"] or config["stroke-width"] or DEFAULT_SHAPE_STROKE_WIDTH
args["stroke-color"..argNumber] = config["shape-stroke-color"] or config["shape-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_SHAPE_STROKE_COLOR
args["fill"..argNumber] = config["shape-fill"] or DEFAULT_SHAPE_FILL
args["fill-opacity"..argNumber] = config["shape-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
incrementArgNumber()
end
-- Line
if useWikidata and shouldShowLine then
args["type"..argNumber] = "line"
if config.id then args["id"..argNumber] = config.id end
args["stroke-width"..argNumber] = config["line-stroke-width"] or config["stroke-width"] or DEFAULT_LINE_STROKE_WIDTH
args["stroke-color"..argNumber] = config["line-stroke-color"] or config["line-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_LINE_STROKE_COLOR
incrementArgNumber()
end
-- Point
if shouldShowPointMarker then
args["type"..argNumber] = "point"
if config.id then args["id"..argNumber] = config.id end
if config.coord then args["coord"..argNumber] = config.coord end
if config.marker then args["marker"..argNumber] = config.marker end
args["marker-color"..argNumber] = config["marker-color"] or config["marker-colour"] or DEFAULT_MARKER_COLOR
incrementArgNumber()
end
local mapframe = args.switch and mf.multi(args) or mf._main(args)
local tracking = hasOsmRelationId and '' or '[[Category:Infobox mapframe without OSM relation ID on Wikidata]]'
return mapframe .. tracking
end
return p
ogyzfveb3a6b3weluchwwadbwte98kk
Module:Mapframe
828
3809
17605
2026-03-29T16:25:35Z
YaThaWinTha
42
Created page with "-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe --[[---------------------------------------------------------------------------- ##### Localisation (L10n) settings ##### Replace values in quotes ("") with localised values ----------------------------------------------------------------------------]]-- local L10n = {} local wb = mw.wikibase -- Modue dependencies local transcluder -- local copy of https://www.mediawiki...."
17605
Scribunto
text/plain
-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe
--[[----------------------------------------------------------------------------
##### Localisation (L10n) settings #####
Replace values in quotes ("") with localised values
----------------------------------------------------------------------------]]--
local L10n = {}
local wb = mw.wikibase
-- Modue dependencies
local transcluder -- local copy of https://www.mediawiki.org/wiki/Module:Transcluder loaded lazily
-- "strict" should not be used, at least until all other modules which require this module are not using globals.
-- Template parameter names (unnumbered versions only)
-- Specify each as either a single string, or a table of strings (aliases)
-- Aliases are checked left-to-right, i.e. `{ "one", "two" }` is equivalent to using `{{{one| {{{two|}}} }}}` in a template
L10n.para = {
display = "display",
type = "type",
id = { "id", "ids" },
from = "from",
raw = "raw",
title = "title",
description = "description",
strokeColor = { "stroke-color", "stroke-colour" },
strokeWidth = "stroke-width",
strokeOpacity = "stroke-opacity",
fill = "fill",
fillOpacity = "fill-opacity",
coord = "coord",
marker = "marker",
markerColor = { "marker-color", "marker-colour" },
markerSize = "marker-size",
radius = { "radius", "radius_m" },
radiusKm = "radius_km",
radiusFt = "radius_ft",
radiusMi = "radius_mi",
edges = "edges",
text = "text",
icon = "icon",
zoom = "zoom",
frame = "frame",
plain = "plain",
frameWidth = "frame-width",
frameHeight = "frame-height",
frameCoordinates= { "frame-coordinates", "frame-coord" },
frameLatitude = { "frame-lat", "frame-latitude" },
frameLongitude = { "frame-long", "frame-longitude" },
frameAlign = "frame-align",
switch = "switch",
overlay = "overlay",
overlayBorder = "overlay-border",
overlayHorizontalAlignment = "overlay-horizontal-alignment",
overlayVerticalAlignment = "overlay-vertical-alignment",
overlayHorizontalOffset = "overlay-horizontal-offset",
overlayVerticalOffset = "overlay-vertical-offset"
}
-- Names of other templates this module can extract coordinates from
L10n.template = {
templates = { -- The coord template, as well as templates with output that contains {{coord}}
"Coord", "Coord/sandbox",
"NRHP row", "NRHP row/sandbox",
"WikidataCoord", "WikidataCoord/sandbox", "Wikidatacoord", "Wikidata coord"
},
modules = { -- The coordinates module, as well as modules with output that contains {{coord}}
"Coordinates", "Coordinates/sandbox",
"WikidataCoord", "WikidataCoord/sandbox"
}
}
-- Error messages
L10n.error = {
badDisplayPara = "Invalid display parameter",
noCoords = "Coordinates must be specified on Wikidata or in |" .. ( type(L10n.para.coord)== 'table' and L10n.para.coord[1] or L10n.para.coord ) .. "=",
wikidataCoords = "Coordinates not found on Wikidata",
noCircleCoords = "Circle centre coordinates must be specified, or available via Wikidata",
negativeRadius = "Circle radius must be a positive number",
noRadius = "Circle radius must be specified",
negativeEdges = "Circle edges must be a positive number",
noSwitchPara = "Found only one switch value in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
oneSwitchLabel = "Found only one label in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
noSwitchLists = "At least one parameter must have a SWITCH: list",
switchMismatches = "All SWITCH: lists must have the same number of values",
-- "%s" and "%d" tokens will be replaced with strings and numbers when used
oneSwitchValue = "Found only one switch value in |%s=",
fewerSwitchLabels = "Found %d switch values but only %d labels in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
noNamedCoords = "No named coordinates found in %s"
}
-- Other strings
L10n.str = {
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)
inline = "inline",
title = "title",
dsep = ",", -- separator between inline and title (comma in the example above)
-- valid values for type parameter
line = "line", -- geoline feature (e.g. a road)
shape = "shape", -- geoshape feature (e.g. a state or province)
shapeInverse = "shape-inverse", -- geomask feature (the inverse of a geoshape)
data = "data", -- geoJSON data page on Commons
point = "point", -- single point feature (coordinates)
circle = "circle", -- circular area around a point
named = "named", -- all named coordinates in an article or section
-- Keyword to indicate a switch list. Must NOT use the special characters ^$()%.[]*+-?
switch = "SWITCH",
-- valid values for icon, frame, and plain parameters
affirmedWords = ' '..table.concat({
"add",
"added",
"affirm",
"affirmed",
"include",
"included",
"on",
"true",
"yes",
"y"
}, ' ')..' ',
declinedWords = ' '..table.concat({
"decline",
"declined",
"exclude",
"excluded",
"false",
"none",
"not",
"no",
"n",
"off",
"omit",
"omitted",
"remove",
"removed"
}, ' ')..' '
}
-- Default values for parameters
L10n.defaults = {
display = L10n.str.inline,
text = "Map",
frameWidth = "300",
frameHeight = "200",
frameAlign = "right",
markerColor = "5E74F3",
markerSize = nil,
strokeColor = "#ff0000",
strokeWidth = 6,
edges = 32, -- number of edges used to approximate a circle
overlayBorder = "1px solid white",
overlayHorizontalAlignment = "right",
overlayHorizontalOffset = "0",
overlayVerticalAlignment = "bottom",
overlayVerticalOffset = "0"
}
-- #### End of L10n settings ####
--[[----------------------------------------------------------------------------
Utility methods
----------------------------------------------------------------------------]]--
local util = {}
--[[
Looks up a parameter value based on the id (a key from the L10n.para table) and
optionally a suffix, for parameters that can be suffixed (e.g. type2 is type
with suffix 2).
@param {table} args key-value pairs of parameter names and their values
@param {string} param_id id for parameter name (key from the L10n.para table)
@param {string} [suffix] suffix for parameter name
@returns {string|nil} parameter value if found, or nil if not found
]]--
function util.getParameterValue(args, param_id, suffix)
suffix = suffix or ''
if type( L10n.para[param_id] ) ~= 'table' then
return args[L10n.para[param_id]..suffix]
end
for _i, paramAlias in ipairs(L10n.para[param_id]) do
if args[paramAlias..suffix] then
return args[paramAlias..suffix]
end
end
return nil
end
--[[
Trim whitespace from args, and remove empty args. Also fix control characters.
@param {table} argsTable
@returns {table} trimmed args table
]]--
function util.trimArgs(argsTable)
local cleanArgs = {}
for key, val in pairs(argsTable) do
if type(key) == 'string' and type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val ~= '' then
-- control characters inside json need to be escaped, but stripping them is simpler
-- See also T214984
-- However, *don't* strip control characters from wikitext (text or description parameters) or you'll break strip markers
-- Alternatively it might be better to only strip control char from raw parameter content
if util.matchesParam('text', key) or util.matchesParam('description', key, key:gsub('^%D+(%d+)$', '%1') ) then
cleanArgs[key] = val
else
cleanArgs[key] = val:gsub('%c',' ')
end
end
else
cleanArgs[key] = val
end
end
return cleanArgs
end
--[[
Check if a parameter name matches an unlocalized parameter key
@param {string} key - the unlocalized parameter name to search through
@param {string} name - the localized parameter name to check
@param {string|nil} - an optional suffix to apply to the value(s) from the localization key
@returns {boolean} true if the name matches the parameter, false otherwise
]]--
function util.matchesParam(key, name, suffix)
local param = L10n.para[key]
suffix = suffix or ''
if type(param) == 'table' then
for _, v in pairs(param) do
if (v .. suffix) == name then return true end
end
return false
end
return ((param .. suffix) == name)
end
--[[
Check if a value is affirmed (one of the values in L10n.str.affirmedWords)
@param {string} val Value to be checked
@returns {boolean} true if affirmed, false otherwise
]]--
function util.isAffirmed(val)
if not(val) then return false end
return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false
end
--[[
Check if a value is declined (one of the values in L10n.str.declinedWords)
@param {string} val Value to be checked
@returns {boolean} true if declined, false otherwise
]]--
function util.isDeclined(val)
if not(val) then return false end
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false
end
--[[
Check if the name of a template matches the known coord templates or wrappers
(in L10n.template.templates and L10n.template.modules). The name is normalised
when checked, so e.g. the names "Coord", "coord", and " Coord" all return true.
@param {string} name
@returns {boolean} true if it is a coord template or wrapper, false otherwise
]]--
function util.isCoordTemplateOrWrapper(name)
name = mw.text.trim(name)
local modName = mw.ustring.gsub(name, '#invoke:', '')
local inputTitle = mw.title.new(modName, (name ~= modName) and 'Module' or 'Template')
if not inputTitle then
return false
end
-- Create (or reuse) mw.title objects for each known coord template/wrapper.
-- Stored in L10n.template.title so that they don't need to be recreated
-- each time this function is called
if not L10n.template.titles then
L10n.template.titles = {}
for _, v in pairs(L10n.template.templates) do
table.insert(L10n.template.titles, mw.title.new(v, 'Template'))
end
for _, v in pairs(L10n.template.modules) do
table.insert(L10n.template.titles, mw.title.new(v, 'Module'))
end
end
for _, templateTitle in pairs(L10n.template.titles) do
if mw.title.equals(inputTitle, templateTitle) then
return true
end
end
return false
end
--[[
Recursively extract coord templates which have a name parameter.
@param {string} wikitext
@returns {table} table sequence of coord templates
]]--
function util.extractCoordTemplates(wikitext)
local output = {}
local templates = mw.ustring.gmatch(wikitext, '{%b{}}')
for template in templates do
local templateName = mw.ustring.match(template, '{{([^}|]+)')
local nameParam = mw.ustring.match(template, "|%s*name%s*=%s*[^}|]+")
if util.isCoordTemplateOrWrapper(templateName) then
if nameParam then table.insert(output, template) end
elseif mw.ustring.find(mw.ustring.sub(template, 2), "{{") then
local subOutput = util.extractCoordTemplates(mw.ustring.sub(template, 2))
for _, t in pairs(subOutput) do
table.insert(output, t)
end
end
end
-- ensure coords are not using title display
for k, v in pairs(output) do
output[k] = mw.ustring.gsub(v, "|%s*display%s*=[^|}]+", "|display=inline")
end
return output
end
--[[
Gets all named coordiates from a page or a section of a page.
@param {string|nil} page Page name, or name#section, to get named coordinates
from. If the name is omitted, i.e. #section or nil or empty string, then
the current page will be used.
@returns {table} sequence of {coord, name, description} tables where coord is
the coordinates in a format suitable for #util.parseCoords, name is a string,
and description is a string (coordinates in a format suitable for displaying
to the reader). If for some reason the name can't be found, the description
is nil and the name contains display-format coordinates.
@throws {L10n.error.noNamedCoords} if no named coordinates are found.
]]--
function util.getNamedCoords(page)
if transcluder == nil then
-- load [[Module:Transcluder]] lazily so it is only transcluded on pages that
-- actually use named coordinates
transcluder = require("Module:Transcluder")
end
local parts = mw.text.split(page or "", "#", true)
local name = parts[1] == "" and mw.title.getCurrentTitle().prefixedText or parts[1]
local section = parts[2]
local pageWikitext = transcluder.get(section and name.."#"..section or name)
local coordTemplates = util.extractCoordTemplates(pageWikitext)
if #coordTemplates == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end
local frame = mw.getCurrentFrame()
local sep = "________"
local expandedContent = frame:preprocess(table.concat(coordTemplates, sep))
local expandedTemplates = mw.text.split(expandedContent, sep)
local namedCoords = {}
for _, expandedTemplate in pairs(expandedTemplates) do
local coord = mw.ustring.match(expandedTemplate, "<span class=\"geo%-dec\".->(.-)</span>")
if coord then
local coordname = (
-- name specified by a wrapper template, e.g [[Article|Name]]
mw.ustring.match(expandedTemplate, "<span class=\"mapframe%-coord%-name\">(.-)</span>") or
-- name passed into coord template
mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or
-- default to the coordinates if the name can't be retrieved
coord
)
local description = coordname ~= coord and coord
table.insert(namedCoords, {
coord=mw.ustring.gsub(coord, "[° ]", "_"),
name=coordname, description=description
})
end
end
if #namedCoords == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end
return namedCoords
end
--[[
Parse coordinate values from the params passed in a GeoHack url (such as
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1_2_N_3_4_W_ or
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1.23_S_4.56_E_ )
or non-url string in the same format (such as `1_2_N_3_4_W_` or `1.23_S_4.56_E_`)
@param {string} coords string containing coordinates
@returns {number, number} latitude, longitude
]]--
function util.parseCoords(coords)
local coordsPatt
if mw.ustring.find(coords, "params=", 1, true) then
-- prevent false matches from page name, e.g. ?pagename=Lorem_S._Ipsum
coordsPatt = 'params=([_%.%d]+[NS][_%.%d]+[EW])'
else
-- not actually a geohack url, just the same format
coordsPatt = '[_%.%d]+[NS][_%.%d]+[EW]'
end
local parts = mw.text.split((mw.ustring.match(coords, coordsPatt) or ''), '_')
local lat_d = tonumber(parts[1])
assert(lat_d, "Unable to get latitude from input '"..coords.."'.")
local lat_m = tonumber(parts[2]) -- nil if coords are in decimal format
local lat_s = lat_m and tonumber(parts[3]) -- nil if coords are either in decimal format or degrees and minutes only
local lat = lat_d + (lat_m or 0)/60 + (lat_s or 0)/3600
if parts[#parts/2] == 'S' then
lat = lat * -1
end
local long_d = tonumber(parts[1+#parts/2])
assert(long_d, "Unable to get longitude from input '"..coords.."'.")
local long_m = tonumber(parts[2+#parts/2]) -- nil if coords are in decimal format
local long_s = long_m and tonumber(parts[3+#parts/2]) -- nil if coords are either in decimal format or degrees and minutes only
local long = long_d + (long_m or 0)/60 + (long_s or 0)/3600
if parts[#parts] == 'W' then
long = long * -1
end
return lat, long
end
--[[
Get coordinates from a Wikidata item
@param {string} item_id Wikidata item id (Q number)
@returns {number, number} latitude, longitude
@throws {L10n.error.noCoords} if item_id is invalid or the item does not exist
@throws {L10n.error.wikidataCoords} if the the item does not have a P625
statement (coordinates), or it is set to "no value"
]]--
function util.wikidataCoords(item_id)
if not (item_id and wb.isValidEntityId(item_id) and wb.entityExists(item_id)) then
error(L10n.error.noCoords, 0)
end
local coordStatements = wb.getBestStatements(item_id, 'P625')
if not coordStatements or #coordStatements == 0 then
error(L10n.error.wikidataCoords, 0)
end
local hasNoValue = ( coordStatements[1].mainsnak and (coordStatements[1].mainsnak.snaktype == 'novalue' or coordStatements[1].mainsnak.snaktype == 'somevalue') )
if hasNoValue then
error(L10n.error.wikidataCoords, 0)
end
local wdCoords = coordStatements[1]['mainsnak']['datavalue']['value']
return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude'])
end
--[[
Creates a polygon that approximates a circle
@param {number} lat Latitude
@param {number} long Longitude
@param {number} radius Radius in metres
@param {number} n Number of edges for the polygon
@returns {table} sequence of {latitude, longitude} table sequences, where
latitude and longitude are both numbers
]]--
function util.circleToPolygon(lat, long, radius, n) -- n is number of edges
-- Based on https://github.com/gabzim/circle-to-polygon, ISC licence
local function offset(cLat, cLon, distance, bearing)
local lat1 = math.rad(cLat)
local lon1 = math.rad(cLon)
local dByR = distance / 6378137 -- distance divided by 6378137 (radius of the earth) wgs84
local offet_lat = math.asin(
math.sin(lat1) * math.cos(dByR) +
math.cos(lat1) * math.sin(dByR) * math.cos(bearing)
)
local offet_lon = lon1 + math.atan2(
math.sin(bearing) * math.sin(dByR) * math.cos(lat1),
math.cos(dByR) - math.sin(lat1) * math.sin(offet_lat)
)
return {math.deg(offet_lon), math.deg(offet_lat)}
end
local coordinates = {};
local i = 0;
while i < n do
table.insert(coordinates,
offset(lat, long, radius, (2*math.pi*i*-1)/n)
)
i = i + 1
end
table.insert(coordinates, offset(lat, long, radius, 0))
return coordinates
end
--[[
Get the number of key-value pairs in a table, which might not be a sequence.
@param {table} t
@returns {number} count of key-value pairs
]]--
function util.tableCount(t)
local count = 0
for k, v in pairs(t) do
count = count + 1
end
return count
end
--[[
For a table where the values are all tables, returns either the util.tableCount
of the subtables if they are all the same, or nil if they are not all the same.
@param {table} t
@returns {number|nil} count of key-value pairs of subtable, or nil if subtables
have different counts
]]--
function util.subTablesCount(t)
local count = nil
for k, v in pairs(t) do
if count == nil then
count = util.tableCount(v)
elseif count ~= util.tableCount(v) then
return nil
end
end
return count
end
--[[
Splits a list into a table sequence. The items in the list may be separated by
commas, or by semicolons (if items may contain commas), or by "###" (if items
may contain semicolons).
@param {string} listString
@returns {table} sequence of list items
]]--
function util.tableFromList(listString)
if type(listString) ~= "string" or listString == "" then return nil end
local separator = (mw.ustring.find(listString, "###", 0, true ) and "###") or
(mw.ustring.find(listString, ";", 0, true ) and ";") or ","
local pattern = "%s*"..separator.."%s*"
return mw.text.split(listString, pattern)
end
-- Boolean in outer scope indicating if Kartographer should be able to
-- automatically calculate coordinates (see phab:T227402)
local coordsDerivedFromFeatures = false;
--[[----------------------------------------------------------------------------
Make methods: These take in a table of arguments, and return either a string
or a table to be used in the eventual output.
----------------------------------------------------------------------------]]--
local make = {}
--[[
Makes content to go inside the maplink or mapframe tag.
@param {table} args
@returns {string} tag content
]]--
function make.content(args)
if util.getParameterValue(args, 'raw') then
coordsDerivedFromFeatures = true -- Kartographer should be able to automatically calculate coords from raw geoJSON
return util.getParameterValue(args, 'raw')
end
local content = {}
local argsExpanded = {}
for k, v in pairs(args) do
local index = string.match( k, '^[^0-9]+([0-9]*)$' )
if index ~= nil then
local indexNumber
if index ~= '' then
indexNumber = tonumber(index)
else
indexNumber = 1
end
if argsExpanded[indexNumber] == nil then
argsExpanded[indexNumber] = {}
end
argsExpanded[indexNumber][ string.gsub(k, index, '') ] = v
end
end
for contentIndex, contentArgs in pairs(argsExpanded) do
local argType = util.getParameterValue(contentArgs, "type")
-- Kartographer automatically calculates coords if geolines/shapes are used (T227402)
if not coordsDerivedFromFeatures then
coordsDerivedFromFeatures = ( argType == L10n.str.line or argType == L10n.str.shape ) and true or false
end
if argType == L10n.str.named then
local namedCoords = util.getNamedCoords(util.getParameterValue(contentArgs, "from"))
local typeKey = type(L10n.para.type) == "table" and L10n.para.type[1] or L10n.para.type
local coordKey = type(L10n.para.coord) == "table" and L10n.para.coord[1] or L10n.para.coord
local titleKey = type(L10n.para.title) == "table" and L10n.para.title[1] or L10n.para.title
local descKey = type(L10n.para.description) == "table" and L10n.para.description[1] or L10n.para.description
for _, namedCoord in pairs(namedCoords) do
contentArgs[typeKey] = "point"
contentArgs[coordKey] = namedCoord.coord
contentArgs[titleKey] = namedCoord.name
contentArgs[descKey] = namedCoord.description
content[#content+1] = make.contentJson(contentArgs)
end
else
content[#content + 1] = make.contentJson(contentArgs)
end
end
--Single item, no array needed
if #content==1 then return content[1] end
--Multiple items get placed in a FeatureCollection
local contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]'
return contentArray
end
--[[
Make coordinates from the coord arg, or the id arg, or the current page's
Wikidata item.
@param {table} args
@param {boolean} [plainOutput]
@returns {Mixed} Either:
{number, number} latitude, longitude if plainOutput is true; or
{table} table sequence of longitude, then latitude (gives the required format
for GeoJSON when encoded)
]]--
function make.coords(args, plainOutput)
local coords, lat, long
local frame = mw.getCurrentFrame()
if util.getParameterValue(args, 'coord') then
coords = frame:preprocess( util.getParameterValue(args, 'coord') )
lat, long = util.parseCoords(coords)
else
lat, long = util.wikidataCoords(util.getParameterValue(args, 'id') or wb.getEntityIdForCurrentPage())
end
if plainOutput then
return lat, long
end
return {[0] = long, [1] = lat}
end
--[[
Makes a table of coordinates that approximate a circle.
@param {table} args
@returns {table} sequence of {latitude, longitude} table sequences, where
latitude and longitude are both numbers
@throws {L10n.error.noCircleCoords} if centre coordinates are not specified
@throws {L10n.error.noRadius} if radius is not specified
@throws {L10n.error.negativeRadius} if radius is negative or zero
@throws {L10n.error.negativeEdges} if edges is negative or zero
]]--
function make.circleCoords(args)
local lat, long = make.coords(args, true)
local radius = util.getParameterValue(args, 'radius')
if not radius then
radius = util.getParameterValue(args, 'radiusKm') and tonumber(util.getParameterValue(args, 'radiusKm'))*1000
if not radius then
radius = util.getParameterValue(args, 'radiusMi') and tonumber(util.getParameterValue(args, 'radiusMi'))*1609.344
if not radius then
radius = util.getParameterValue(args, 'radiusFt') and tonumber(util.getParameterValue(args, 'radiusFt'))*0.3048
end
end
end
local edges = util.getParameterValue(args, 'edges') or L10n.defaults.edges
if not lat or not long then
error(L10n.error.noCircleCoords, 0)
elseif not radius then
error(L10n.error.noRadius, 0)
elseif tonumber(radius) <= 0 then
error(L10n.error.negativeRadius, 0)
elseif tonumber(edges) <= 0 then
error(L10n.error.negativeEdges, 0)
end
return util.circleToPolygon(lat, long, radius, tonumber(edges))
end
--[[
Makes JSON data for a feature
@param contentArgs args for this feature. Keys must be the non-suffixed version
of the parameter names, i.e. use type, stroke, fill,... rather than type3,
stroke3, fill3,...
@returns {string} JSON encoded data
]]--
function make.contentJson(contentArgs)
local data = {}
if util.getParameterValue(contentArgs, 'type') == L10n.str.point or util.getParameterValue(contentArgs, 'type') == L10n.str.circle then
local isCircle = util.getParameterValue(contentArgs, 'type') == L10n.str.circle
data.type = "Feature"
data.geometry = {
type = isCircle and "LineString" or "Point",
coordinates = isCircle and make.circleCoords(contentArgs) or make.coords(contentArgs)
}
data.properties = {
title = util.getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle()
}
if isCircle then
-- TODO: This is very similar to below, should be extracted into a function
data.properties.stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor
data.properties["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity')
if strokeOpacity then
data.properties['stroke-opacity'] = tonumber(strokeOpacity)
end
local fill = util.getParameterValue(contentArgs, 'fill')
if fill then
data.properties.fill = fill
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity')
data.properties['fill-opacity'] = fillOpacity and tonumber(fillOpacity) or 0.6
end
else -- is a point
local markerSymbol = util.getParameterValue(contentArgs, 'marker') or L10n.defaults.marker
-- allow blank to be explicitly specified, for overriding infoboxes or other templates with a default value
if markerSymbol ~= "blank" then
data.properties["marker-symbol"] = markerSymbol
end
data.properties["marker-color"] = util.getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor
data.properties["marker-size"] = util.getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSize
end
else
data.type = "ExternalData"
if util.getParameterValue(contentArgs, 'type') == L10n.str.data or util.getParameterValue(contentArgs, 'from') then
data.service = "page"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.line then
data.service = "geoline"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shape then
data.service = "geoshape"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then
data.service = "geomask"
end
if util.getParameterValue(contentArgs, 'id') or (not (util.getParameterValue(contentArgs, 'from')) and wb.getEntityIdForCurrentPage()) then
data.ids = util.getParameterValue(contentArgs, 'id') or wb.getEntityIdForCurrentPage()
else
data.title = util.getParameterValue(contentArgs, 'from')
end
data.properties = {
stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor,
["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth
}
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity')
if strokeOpacity then
data.properties['stroke-opacity'] = tonumber(strokeOpacity)
end
local fill = util.getParameterValue(contentArgs, 'fill')
if fill and (data.service == "geoshape" or data.service == "geomask") then
data.properties.fill = fill
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity')
if fillOpacity then
data.properties['fill-opacity'] = tonumber(fillOpacity)
end
end
end
data.properties.title = util.getParameterValue(contentArgs, 'title') or mw.title.getCurrentTitle().text
if util.getParameterValue(contentArgs, 'description') then
data.properties.description = util.getParameterValue(contentArgs, 'description')
end
return mw.text.jsonEncode(data)
end
--[[
Makes attributes for the maplink or mapframe tag.
@param {table} args
@param {boolean} [isTitle] Tag is to be displayed in the title of page rather
than inline
@returns {table<string,string>} key-value pairs of attribute names and values
]]--
function make.tagAttribs(args, isTitle)
local attribs = {}
if util.getParameterValue(args, 'zoom') then
attribs.zoom = util.getParameterValue(args, 'zoom')
end
if util.isDeclined(util.getParameterValue(args, 'icon')) then
attribs.class = "no-icon"
end
if util.getParameterValue(args, 'type') == L10n.str.point and not coordsDerivedFromFeatures then
local lat, long = make.coords(args, 'plainOutput')
attribs.latitude = tostring(lat)
attribs.longitude = tostring(long)
end
if util.isAffirmed(util.getParameterValue(args, 'frame')) and not(isTitle) then
attribs.width = util.getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth
attribs.height = util.getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight
if util.getParameterValue(args, 'frameCoordinates') then
local frameLat, frameLong = util.parseCoords(util.getParameterValue(args, 'frameCoordinates'))
attribs.latitude = frameLat
attribs.longitude = frameLong
else
if util.getParameterValue(args, 'frameLatitude') then
attribs.latitude = util.getParameterValue(args, 'frameLatitude')
end
if util.getParameterValue(args, 'frameLongitude') then
attribs.longitude = util.getParameterValue(args, 'frameLongitude')
end
end
if not attribs.latitude and not attribs.longitude and not coordsDerivedFromFeatures then
local success, lat, long = pcall(util.wikidataCoords, util.getParameterValue(args, 'id') or wb.getEntityIdForCurrentPage())
if success then
attribs.latitude = tostring(lat)
attribs.longitude = tostring(long)
end
end
if util.getParameterValue(args, 'frameAlign') then
attribs.align = util.getParameterValue(args, 'frameAlign')
end
if util.isAffirmed(util.getParameterValue(args, 'plain')) then
attribs.frameless = "1"
else
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text
end
else
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text
end
return attribs
end
--[[
Makes maplink wikitext that will be located in the top-right of the title of the
page (the same place where coords with |display=title are positioned).
@param {table} args
@param {string} tagContent Content for the maplink tag
@returns {string}
]]--
function make.titleOutput(args, tagContent)
local titleTag = mw.text.tag('maplink', make.tagAttribs(args, true), tagContent)
local spanAttribs = {
style = "font-size: small;",
id = "mapframe-coordinates"
}
local indicatorContent = mw.text.tag('span', spanAttribs, titleTag)
return mw.getCurrentFrame():extensionTag {
name = "indicator",
content = indicatorContent,
args = {
name = "zzz-mapframe" --zzz: show as last indicator
}
}
end
--[[
Makes maplink or mapframe wikitext that will be located inline.
@param {table} args
@param {string} tagContent Content for the maplink tag
@returns {string}
]]--
function make.inlineOutput(args, tagContent)
local tagName = 'maplink'
if util.getParameterValue(args, 'frame') then
tagName = 'mapframe'
end
return mw.text.tag(tagName, make.tagAttribs(args), tagContent)
end
--[[
Makes the HTML required for the swicther to work, including the templatestyles
tag.
@param {table} params table sequence of {map, label} tables
@param {string} params{}.map Wikitext for mapframe map
@param {string} params{}.label Label text for swicther option
@param {table} options
@param {string} options.alignment "left" or "center" or "right"
@param {boolean} options.isThumbnail Display in a thumbnail
@param {string} options.width Width of frame, e.g. "200"
@param {string} [options.caption] Caption wikitext for thumnail
@retruns {string} swicther HTML
]]--
function make.switcherHtml(params, options)
options = options or {}
local frame = mw.getCurrentFrame()
local styles = frame:extensionTag{
name = "templatestyles",
args = {src = "Template:Maplink/styles-multi.css"}
}
local container = mw.html.create("div")
:addClass("switcher-container")
:addClass("mapframe-multi-container")
if options.alignment == "left" or options.alignment == "right" then
container:addClass("float"..options.alignment)
else -- alignment is "center"
container:addClass("center")
end
for i = 1, #params do
container
:tag("div")
:wikitext(params[i].map)
:tag("span")
:addClass("switcher-label")
:css("display", "none")
:wikitext(mw.text.trim(params[i].label))
end
if not options.isThumbnail then
return styles .. tostring(container)
end
local classlist = container:getAttr("class")
classlist = mw.ustring.gsub(classlist, "%a*"..options.alignment, "")
container:attr("class", classlist)
local outerCountainer = mw.html.create("div")
:addClass("mapframe-multi-outer-container")
:addClass("mw-kartographer-container")
:addClass("thumb")
if options.alignment == "left" or options.alignment == "right" then
outerCountainer:addClass("t"..options.alignment)
else -- alignment is "center"
outerCountainer
:addClass("tnone")
:addClass("center")
end
outerCountainer
:tag("div")
:addClass("thumbinner")
:css("width", options.width.."px")
:node(container)
:node(options.caption and mw.html.create("div")
:addClass("thumbcaption")
:wikitext(options.caption)
)
return styles .. tostring(outerCountainer)
end
--[[
Makes the HTML required for an overlay map to work
tag.
@param {string} overlayMap wikitext for the overlay map
@param {string} baseMap wikitext for the base map
@param {table} options various styling/display options
@param {string} options.align "left" or "center" or "right"
@param {string|number} options.width Width of the base map, e.g. "300"
@param {string|number} options.width Height of the base map, e.g. "200"
@param {string} options.border Border style for the overlayed map, e.g. "1px solid white"
@param {string} options.horizontalAlignment Horizontal alignment for overlay map, "left" or "right"
@param {string|number} options.horizontalOffset Horizontal offset in pixels from the alignment edge, e.g "10"
@param {string} options.verticalAlignment Vertical alignment for overlay map, "top" or "bottom"
@param {string|number} options.verticalOffset Vertical offset in pixels from the alignment edge, e.g. is "10"
@param {boolean} options.isThumbnail Display in a thumbnail
@param {string} [options.caption] Caption wikitext for thumnail
@retruns {string} HTML for basemap with overlay
]]--
function make.overlayHtml(overlayMap, baseMap, options)
options = options or {}
local containerFloatClass = "float"..(options.align or "none")
if options.align == "center" then
containerFloatClass = "center"
end
local containerStyle = {
position = "relative",
width = options.width .. "px",
height = options.height .. "px",
overflow = "hidden" -- mobile/minerva tends to add scrollbars for a couple of pixels
}
if options.align == "center" then
containerStyle["margin-left"] = "auto"
containerStyle["margin-right"] = "auto"
end
local container = mw.html.create("div")
:addClass("mapframe-withOverlay-container")
:addClass(containerFloatClass)
:addClass("noresize")
:css(containerStyle)
local overlayStyle = {
position = "absolute",
["z-index"] = "1",
border = options.border or "1px solid white"
}
if options.horizontalAlignment == "right" then
overlayStyle.right = options.horizontalOffset .. "px"
else
overlayStyle.left = options.horizontalOffset .. "px"
end
if options.verticalAlignment == "bottom" then
overlayStyle.bottom = options.verticalOffset .. "px"
else
overlayStyle.top = options.verticalOffset .. "px"
end
local overlayDiv = mw.html.create("div")
:css(overlayStyle)
:wikitext(overlayMap)
container
:node(overlayDiv)
:wikitext(baseMap)
if not options.isThumbnail then
return tostring(container)
end
local classlist = container:getAttr("class")
classlist = mw.ustring.gsub(classlist, "%a*"..options.align, "")
container:attr("class", classlist)
local outerCountainer = mw.html.create("div")
:addClass("mapframe-withOverlay-outerContainer")
:addClass("mw-kartographer-container")
:addClass("thumb")
if options.align == "left" or options.align == "right" then
outerCountainer:addClass("t"..options.align)
else -- alignment is "center"
outerCountainer
:addClass("tnone")
:addClass("center")
end
outerCountainer
:tag("div")
:addClass("thumbinner")
:css("width", options.width.."px")
:node(container)
:node(options.caption and mw.html.create("div")
:addClass("thumbcaption")
:wikitext(options.caption)
)
return tostring(outerCountainer)
end
--[[----------------------------------------------------------------------------
Package to be exported, i.e. methods which will available to templates and
other modules.
----------------------------------------------------------------------------]]--
local p = {}
-- Entry point for templates
function p.main(frame)
local parent = frame.getParent(frame)
-- Check for overlay option
local overlay = util.getParameterValue(parent.args, 'overlay')
local hasOverlay = overlay and mw.text.trim(overlay) ~= ""
-- Check for switch option
local switch = util.getParameterValue(parent.args, 'switch')
local isMulti = switch and mw.text.trim(switch) ~= ""
-- Create output by choosing method to suit options
local output
if hasOverlay then
output = p.withOverlay(parent.args)
elseif isMulti then
output = p.multi(parent.args)
else
output = p._main(parent.args)
end
-- Preprocess output before returning it
return frame:preprocess(output)
end
-- Entry points for modules
function p._main(_args)
local args = util.trimArgs(_args)
local tagContent = make.content(args)
local display = mw.text.split(util.getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*')
local displayInTitle = display[1] == L10n.str.title or display[2] == L10n.str.title
local displayInline = display[1] == L10n.str.inline or display[2] == L10n.str.inline
local output
if displayInTitle and displayInline then
output = make.titleOutput(args, tagContent) .. make.inlineOutput(args, tagContent)
elseif displayInTitle then
output = make.titleOutput(args, tagContent)
elseif displayInline then
output = make.inlineOutput(args, tagContent)
else
error(L10n.error.badDisplayPara)
end
return output
end
function p.multi(_args)
local args = util.trimArgs(_args)
if not args[L10n.para.switch] then error(L10n.error.noSwitchPara, 0) end
local switchParamValue = util.getParameterValue(args, 'switch')
local switchLabels = util.tableFromList(switchParamValue)
if #switchLabels == 1 then error(L10n.error.oneSwitchLabel, 0) end
local mapframeArgs = {}
local switchParams = {}
for name, val in pairs(args) do
-- Copy to mapframeArgs, if not the switch labels or a switch parameter
if val ~= switchParamValue and not string.match(val, "^"..L10n.str.switch..":") then
mapframeArgs[name] = val
end
-- Check if this is a param to switch. If so, store the name and switch
-- values in switchParams table.
local switchList = string.match(val, "^"..L10n.str.switch..":(.+)")
if switchList ~= nil then
local values = util.tableFromList(switchList)
if #values == 1 then
error(string.format(L10n.error.oneSwitchValue, name), 0)
end
switchParams[name] = values
end
end
if util.tableCount(switchParams) == 0 then
error(L10n.error.noSwitchLists, 0)
end
local switchCount = util.subTablesCount(switchParams)
if not switchCount then
error(L10n.error.switchMismatches, 0)
elseif switchCount > #switchLabels then
error(string.format(L10n.error.fewerSwitchLabels, switchCount, #switchLabels), 0)
end
-- Ensure a plain frame will be used (thumbnail will be built by the
-- make.switcherHtml function if required, so that switcher options are
-- inside the thumnail)
mapframeArgs.plain = "yes"
local switcher = {}
for i = 1, switchCount do
local label = switchLabels[i]
for name, values in pairs(switchParams) do
mapframeArgs[name] = values[i]
end
table.insert(switcher, {
map = p._main(mapframeArgs),
label = "Show "..label
})
end
return make.switcherHtml(switcher, {
alignment = args["frame-align"] or "right",
isThumbnail = (args.frame and not args.plain) and true or false,
width = args["frame-width"] or L10n.defaults.frameWidth,
caption = args.text
})
end
function p.withOverlay(_args)
-- Get and trim wikitext for overlay map
local overlayMap = _args.overlay
if type(overlayMap) == 'string' then
overlayMap = overlayMap:match('^%s*(.-)%s*$')
end
local isThumbnail = (util.getParameterValue(_args, "frame") and not util.getParameterValue(_args, "plain")) and true or false
-- Get base map using the _main function, as a plain map
local args = util.trimArgs(_args)
args.plain = "yes"
local basemap = p._main(args)
-- Extract overlay options from args
local overlayOptions = {
width = util.getParameterValue(args, "frameWidth") or L10n.defaults.frameWidth,
height = util.getParameterValue(args, "frameHeight") or L10n.defaults.frameHeight,
align = util.getParameterValue(args, "frameAlign") or L10n.defaults.frameAlign,
border = util.getParameterValue(args, "overlayBorder") or L10n.defaults.overlayBorder,
horizontalAlignment = util.getParameterValue(args, "overlayHorizontalAlignment") or L10n.defaults.overlayHorizontalAlignment,
horizontalOffset = util.getParameterValue(args, "overlayHorizontalOffset") or L10n.defaults.overlayHorizontalOffset,
verticalAlignment = util.getParameterValue(args, "overlayVerticalAlignment") or L10n.defaults.overlayVerticalAlignment,
verticalOffset = util.getParameterValue(args, "overlayVerticalOffset") or L10n.defaults.overlayVerticalOffset,
isThumbnail = isThumbnail,
caption = util.getParameterValue(args, "text") or L10n.defaults.text
}
-- Make the HTML for the overlaying maps
return make.overlayHtml(overlayMap, basemap, overlayOptions)
end
-- Entry point for testcase tests
p.test = util
return p
scu6vpkoggodyf8lo3z2l8kc9bq10ex
Module:Check for conflicting parameters
828
3810
17606
2026-03-29T16:26:07Z
YaThaWinTha
42
Created page with "local p = {} local function trim(s) return s:match('^%s*(.-)%s*$') end local function isnotempty(s) return s and s:match('%S') end function p.check(frame) local args = frame.args local pargs = frame:getParent().args local checknested = isnotempty(args['nested']) local delimiter = isnotempty(args['delimiter']) and args['delimiter'] or ';' local argpairs = {} for k, v in pairs(args) do if type(k) == 'number' then local plist = mw.text.split(v, delimiter)..."
17606
Scribunto
text/plain
local p = {}
local function trim(s)
return s:match('^%s*(.-)%s*$')
end
local function isnotempty(s)
return s and s:match('%S')
end
function p.check(frame)
local args = frame.args
local pargs = frame:getParent().args
local checknested = isnotempty(args['nested'])
local delimiter = isnotempty(args['delimiter']) and args['delimiter'] or ';'
local argpairs = {}
for k, v in pairs(args) do
if type(k) == 'number' then
local plist = mw.text.split(v, delimiter)
local pfound = {}
local count = 0
for ii, vv in ipairs(plist) do
vv = trim(vv)
if checknested and pargs[vv] or isnotempty(pargs[vv]) then
count = count + 1
table.insert(pfound, vv)
end
end
if count > 1 then
table.insert(argpairs, pfound)
end
end
end
local warnmsg = {}
local res = ''
local cat = ''
if args['cat'] and mw.ustring.match(args['cat'],'^[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]:') then
cat = args['cat']
end
local template = args['template'] and ' in ' .. args['template'] or ''
if #argpairs > 0 then
for i, v in ipairs( argpairs ) do
table.insert(
warnmsg,
mw.ustring.format(
'Using more than one of the following parameters%s: <code>%s</code>.',
template,
table.concat(v, '</code>, <code>')
)
)
if cat ~= '' then
res = res .. '[[' .. cat .. '|' .. (v[1] == '' and ' ' or '') .. v[1] .. ']]'
end
end
end
if #warnmsg > 0 then
res = require('Module:If preview')._warning({
table.concat(warnmsg, '<br>')
}) .. res
end
return res
end
return p
59n770hna40q9pw4oa0dsp86euaks0u
တမ်းပလိတ်:Infobox settlement/impus
10
3811
17607
2026-03-29T16:28:19Z
YaThaWinTha
42
Created page with "<includeonly>{{formatnum:{{{impv}}}{{{s| }}}{{{impu|ft}}}{{#ifeq:{{{impv|0}}}|1||{{#ifeq:{{{s}}}|/||{{#ifeq:{{{impu}}}|acre|s}}}}}} ({{{metv}}}{{{s| }}}{{{metu|m}}})}}</includeonly><noinclude> {{documentation}} </noinclude>"
17607
wikitext
text/x-wiki
<includeonly>{{formatnum:{{{impv}}}{{{s| }}}{{{impu|ft}}}{{#ifeq:{{{impv|0}}}|1||{{#ifeq:{{{s}}}|/||{{#ifeq:{{{impu}}}|acre|s}}}}}} ({{{metv}}}{{{s| }}}{{{metu|m}}})}}</includeonly><noinclude>
{{documentation}}
</noinclude>
pw1awpwvm2hophvtlqxfvdh17t8vx6j
တမ်းပလိတ်:Korean/auto
10
3812
17608
2026-03-29T16:29:34Z
YaThaWinTha
42
Created page with "<includeonly>{{#invoke:Korean|ko}}</includeonly><noinclude> {{documentation}}</noinclude>"
17608
wikitext
text/x-wiki
<includeonly>{{#invoke:Korean|ko}}</includeonly><noinclude>
{{documentation}}</noinclude>
grs0hpmwgx42cz1raf926zclpcw1ayp
တမ်းပလိတ်:LSJ
10
3813
17609
2026-03-29T16:29:57Z
YaThaWinTha
42
Created page with "{{#switch:{{{4|{{{3|{{{2|}}}}}}}}} |mLSJ = [https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:1999.04.0058:entry={{{1}}} {{#switch:{{{2|}}}|cite|ref|longref|shortref|mLSJ|={{{1}}}|{{lang|grc|{{{2}}}}}}}]{{#switch:{{{3|{{{2|}}}}}}|cite|ref=. [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]]; ''[[:en:A Greek–English Lexicon|An Intermediate Greek–English Lexicon]]'' at the Perseus Project|longref= in Henry Lidd..."
17609
wikitext
text/x-wiki
{{#switch:{{{4|{{{3|{{{2|}}}}}}}}}
|mLSJ = [https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:1999.04.0058:entry={{{1}}} {{#switch:{{{2|}}}|cite|ref|longref|shortref|mLSJ|={{{1}}}|{{lang|grc|{{{2}}}}}}}]{{#switch:{{{3|{{{2|}}}}}}|cite|ref=. [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]]; ''[[:en:A Greek–English Lexicon|An Intermediate Greek–English Lexicon]]'' at the Perseus Project|longref= in [[Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]] (1889) ''An Intermediate Greek–English Lexicon'', Oxford. Clarendon Press. In the [[:en:Perseus Project|Perseus Digital Library]], Tufts University.|shortref= in Middle [[:en:Henry Liddell|Liddell]] and [[:en:Robert Scott (philologist)|Scott]]|mLSJ={{#switch:{{{2}}}|cite|ref=. [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]]; ''[[:en:A Greek–English Lexicon|An Intermediate Greek–English Lexicon]]'' at the Perseus Project|longref= in [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]] (1889) ''An Intermediate Greek–English Lexicon'', Oxford. Clarendon Press. In the [[:en:Perseus Project|Perseus Digital Library]], Tufts University.|shortref= in Middle [[:en:Henry Liddell|Liddell]] and [[:en:Robert Scott (philologist)|Scott]]|}}|}}
|#default = [https://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:1999.04.0057:entry={{{1}}} {{#switch:{{{2|}}}|cite|ref|longref|shortref|={{{1}}}|{{lang|grc|{{{2}}}}}}}]{{#switch:{{{3|{{{2|}}}}}}|cite|ref=. [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]]; ''A Greek–English Lexicon'' at the Perseus Project|longref= in [[:en:Henry Liddell|Liddell, Henry George]]; [[:en:Robert Scott (philologist)|Scott, Robert]] (1940) ''A Greek–English Lexicon'', revised and augmented throughout by [[:en:Henry Stuart Jones|Jones, Sir Henry Stuart]], with the assistance of McKenzie, Roderick. Oxford: Clarendon Press. In the [[:en:Perseus Project|Perseus Digital Library]], Tufts University.|shortref= in [[:en:Henry Liddell|Liddell]] and [[:en:Robert Scott (philologist)|Scott]]|}}}}<noinclude>
{{Documentation}}</noinclude>
f19shaki1d1pikymige6x4xgwer6jbo
တမ်းပလိတ်:Lang-la
10
3814
17610
2026-03-29T16:30:24Z
YaThaWinTha
42
Created page with "<includeonly>{{#invoke:lang|lang_xx_italic |code=la }}</includeonly><noinclude> {{Documentation|Template:Lang-x/doc}} [[Category:Italic multilingual support templates]] </noinclude>"
17610
wikitext
text/x-wiki
<includeonly>{{#invoke:lang|lang_xx_italic
|code=la
}}</includeonly><noinclude>
{{Documentation|Template:Lang-x/doc}}
[[Category:Italic multilingual support templates]]
</noinclude>
rbxqs1ck5rky5fq2sy1uhrw4o8km6p2
တမ်းပလိတ်:Lang-x
10
3815
17611
2026-03-29T16:32:15Z
YaThaWinTha
42
Created page with "__NOEDITSECTION__{{Documentation subpage|[[:Category:Lang-x တမ်းပလိတ်တိ]]}} {{COinS safe|n}} {{No subst}} <noinclude>{{Lua|Module:Lang/documentor tool}}</noinclude> {{#if:{{#invoke:Lang/documentor tool|uses_module|template={{ROOTPAGENAME}}}}|{{Lua|Module:Lang}}}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> == အသုံးပြုပုံ == {{#invoke:Lang/documentor tool|lang_xx_settings|template={{ROOTPAGENAME}}}..."
17611
wikitext
text/x-wiki
__NOEDITSECTION__{{Documentation subpage|[[:Category:Lang-x တမ်းပလိတ်တိ]]}}
{{COinS safe|n}}
{{No subst}}
<noinclude>{{Lua|Module:Lang/documentor tool}}</noinclude>
{{#if:{{#invoke:Lang/documentor tool|uses_module|template={{ROOTPAGENAME}}}}|{{Lua|Module:Lang}}}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
== အသုံးပြုပုံ ==
{{#invoke:Lang/documentor tool|lang_xx_settings|template={{ROOTPAGENAME}}}}
တမ်းပလိတ် {{Tlf|'''{{lcfirst:{{BASEPAGENAME}}}}'''|nolink=yes}} စွာ ဖတ်ရှုသူတိအား စာစု သို့ စကားလုံး တခုဧ့ မူရင်းဘာသာပုံစံကို {{#ifeq:{{FULLPAGENAME}}|Template:Lang-x/doc|နိုင်ငံခြား|{{#invoke:Lang|name_from_tag|link=yes|{{#invoke:String|sub|{{ROOTPAGENAME}}|6}}}}}} ဘာသာစကားနန့် ပြသပီးရေ။ ပြသထားရေ စာသားကို စာလုံးစောင်းနန့် ပြသပီးရေ။
တမ်းပလိတ်ကို ယေဘုယျအနိန်နန့် နိုင်ငံခြားစကားလုံး သို့ စာစုဧ့ အင်္ဂလိပ်ဘာသာပြန် နောက်မာ ထားဟိသင့်ရေ။
ပါရာမီတာ {{Para|links|no}} စွာ ဘာသာစကားနာမည်သို့ လင့်ခ်ချိတ်ဆက်ခြင်းက ကာကွယ်ပီးဖို့ ဖြစ်တေ။
ပါရာမီတာ {{Para|lit}} စွာ လုံးချင်းသဒ္ဒေချင့်ဇာသာပြန်အား ပြသပေးလီဖို့။
{{#if:{{#invoke:Lang/documentor tool|uses_module|template={{ROOTPAGENAME}}}}|
== ပါရာမီစွာတိ ==
{{#lst:Template:Lang-x/doc/parameters|lang_xx_parameters}}
}}
== ဥပမာတိ ==
အောက်ပါဥပမာတိမာ ဂျာမန်ဘာသာပြန်ပြထားခြင်း ဖြစ်တေ။
'''ရီးသားပုံ'''
* Weimar is located in the federal state of Thuringia (<code><nowiki>{{Lang-de|Thüringen}}</nowiki></code>).
* The Seafarers of Catan (<code><nowiki>{{Lang-de|Die Seefahrer von Catan}}</nowiki></code>) is an expansion of the board game ''The Settlers of Catan''.
* Albert the Bear (<code><nowiki>{{Lang-de|Albrecht der Bär|links=no}}</nowiki></code>)
*''All Quiet on the Western Front'' ({<code><nowiki>{lang-de|Im Westen nichts Neues|lit=In the West Nothing New}}</nowiki><code>) is a novel by Erich Maria Remarque.
'''ပြသပီးဖို့ စာသား'''
* Weimar is located in the federal state of Thuringia ({{Lang-de|Thüringen}}).
* The Seafarers of Catan ({{Lang-de|Die Seefahrer von Catan}}) is an expansion of the board game ''The Settlers of Catan''.
* Albert the Bear ({{Lang-de|Albrecht der Bär|links=no}})
*''All Quiet on the Western Front'' ({{lang-de|Im Westen nichts Neues|lit=In the West Nothing New}}) is a novel by Erich Maria Remarque.
== အခြားကြည့်ရန် ==
* {{Tl|Lang}}
* {{Tl|Language with name/for}}
* {{Tl|Link language}}
* {{Tl|{{#ifeq:0
|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{#ifeq:0|{{#ifexist:ISO 639:{{Str right|{{BASEPAGENAME}}|5}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|1}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|2}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|3}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|4}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|5}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|6}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|7}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|8}}}}|0|1}}
|{{Str right|{{BASEPAGENAME}}|5}}
|{{Str crop|{{Str right|{{BASEPAGENAME}}|5}}|9}}
}} icon}}
<includeonly>
<!-- CATEGORIES (which are not already covered in the individual lang-x templates) HERE, THANKS -->
{{#ifeq:0
|{{#ifexist:ISO 639:{{Str right|{{BASEPAGENAME}}|5}}|0|1}}
|[[Category:Lang-x တမ်းပလိတ်တိ]]
|{{#if:{{#invoke:Lang/documentor tool|uses_module|template={{ROOTPAGENAME}}}}|[[Category:Lang-x တမ်းပလိတ်တိ]]|[[Category:Lang-x templates with other than ISO 639]]}}
}}
</includeonly>
<noinclude>[[Category:Documentation shared content templates]]</noinclude>
m8vt2zlqqq9g6e163dxgjnzapmx2ubz
တမ်းပလိတ်:MSW3
10
3816
17612
2026-03-29T16:33:11Z
YaThaWinTha
42
Created page with "{{cite book | author = {{{author|}}} | chapter = {{{heading|}}} | chapter-url = {{ #if: {{{heading|}}} |http://www.departments.bucknell.edu/biology/resources/msw3/browse.asp{{ #if: {{{id|}}} |?id={{{id}}}|}} }} | editor-last = Wilson | editor-first = D.E. |editor1-link=:en:Don E. Wilson | editor2-last = Reeder | editor2-first = D.M. | year = ၂၀၀၅ | title = ကမ္ဘာထက်မာဟိရေ နို့တိုက်သတ္တမွားမျို..."
17612
wikitext
text/x-wiki
{{cite book
| author = {{{author|}}}
| chapter = {{{heading|}}}
| chapter-url = {{ #if: {{{heading|}}} |http://www.departments.bucknell.edu/biology/resources/msw3/browse.asp{{ #if: {{{id|}}} |?id={{{id}}}|}} }}
| editor-last = Wilson | editor-first = D.E. |editor1-link=:en:Don E. Wilson
| editor2-last = Reeder | editor2-first = D.M.
| year = ၂၀၀၅
| title = ကမ္ဘာထက်မာဟိရေ နို့တိုက်သတ္တမွားမျိုးစိတ်တိ: မျိုးရိုးခွဲခြားခြင်းနန့် ပထဝီမြီမျက်နှာပြင်ဆိုင်ရာ ရည်ညွှန်းကျမ်း
| url = http://www.{{ #if: {{{heading|}}} |google.com/books?id=JgAMbNSt8ikC&pg=PA{{{page|{{{pages|1}}} }}}|departments.bucknell.edu/biology/resources/msw3/browse.asp{{ #if: {{{id|}}} |?id={{{id}}}|}} }}
| edition = တတိယအကြိမ်
| publisher = ဂျွန်ဟော့ကင်းတက္ကသိုလ် ပုံနှိပ်တိုက်
| pages = {{{pages|}}}
| page = {{{page|}}}
| isbn= 978-0-8018-8221-0
| oclc= 62265494
| ref = {{{ref|harvid}}}
}}<noinclude>
{{documentation}}
</noinclude>
so4o2ze1yspnry3pbims46280olyw31
တမ်းပလိတ်:MSW3 Groves
10
3817
17617
2026-03-29T16:45:12Z
YaThaWinTha
42
Created page with "{{cite book | last = Groves | first = C.P. | authorlink = :en:Colin Groves | year = 2005 | chapter = {{{heading|}}} | chapter-url = {{ #if: {{{heading|}}} |http://www.bucknell.edu/msw3{{ #if: {{{id|}}} |/browse.asp?id={{{id}}}|}} }} | editor1-last=Wilson |editor1-first=D.E. |editor1-link=:en:Don E. Wilson | editor2-last=Reeder |editor2-first=D.M. | title = ကမ္ဘာထက်မာဟိရေ နို့တိုက်သတ္တမွားမျိုးစိ..."
17617
wikitext
text/x-wiki
{{cite book
| last = Groves | first = C.P. | authorlink = :en:Colin Groves
| year = 2005
| chapter = {{{heading|}}}
| chapter-url = {{ #if: {{{heading|}}} |http://www.bucknell.edu/msw3{{ #if: {{{id|}}} |/browse.asp?id={{{id}}}|}} }}
| editor1-last=Wilson |editor1-first=D.E. |editor1-link=:en:Don E. Wilson
| editor2-last=Reeder |editor2-first=D.M.
| title = ကမ္ဘာထက်မာဟိရေ နို့တိုက်သတ္တမွားမျိုးစိတ်တိ: မျိုးရိုးခွဲခြားခြင်းနန့် ပထဝီမြီမျက်နှာပြင်ဆိုင်ရာ ရည်ညွှန်းကျမ်း
| url = http://www.{{ #if: {{{heading|}}} |google.com/books?id=JgAMbNSt8ikC&pg=PA{{{page|{{{pages|1}}} }}}|bucknell.edu/msw3{{ #if: {{{id|}}} |/browse.asp?id={{{id}}}|}} }}
|page{{#ifeq:{{#invoke:String|find|source={{{pages|{{{page|}}}}}} |target=[,%-–] |plain=false}}|0||s}}={{{pages|{{{page|}}}}}}
| edition = တတိယအကြိမ်
| publisher = ဂျွန်ဟော့ကင်းတက္ကသိုလ် ပုံနှိပ်တိုက်
| location = Baltimore
| id = ISBN 0-801-88221-4
| oclc= 62265494
| ref = {{{ref|harvid}}}
}}<noinclude>
{{Documentation}}
</noinclude><noinclude>
[[ကဏ္ဍ:Mammal Species of the World citation templates]]
</noinclude>
1m0ooq6b54ezw8a9maowph89p4ts0xw
တမ်းပလိတ်:Ordered list
10
3818
17618
2026-03-29T16:47:04Z
YaThaWinTha
42
Created page with "{{<includeonly>safesubst:</includeonly>#invoke:list|ordered}}<noinclude> {{documentation}} <!-- Categories go on the /doc subpage, and interwikis go on Wikidata. --> </noinclude>"
17618
wikitext
text/x-wiki
{{<includeonly>safesubst:</includeonly>#invoke:list|ordered}}<noinclude>
{{documentation}}
<!-- Categories go on the /doc subpage, and interwikis go on Wikidata. -->
</noinclude>
n9z3yrhcknctpjb3o8a5r4mv3ke55up
တမ်းပလိတ်:Post-nominals/GBR
10
3819
17619
2026-03-29T16:47:29Z
YaThaWinTha
42
Created page with "{{#switch: {{{1}}} | AC = [[:en:Honorary Companion of the Order of Australia|AC]] | ACs = [[:en:Companion of the Order of Australia|AC]] | AcSS = [[:en:Academician of the Social Sciences|AcSS]] | ADC = [[:en:Aide de Camp|ADC]] | ADC Gen= [[:en:Aide-de-Camp General|ADC Gen]] | ADC(P) = [[:en:Personal Aide-de-Camp|ADC(P)]] | AE = [[:en:Air Efficiency Award|AE]] | AFC = [[:en:Air Force Cross (United Kingdom)|AFC]] | AFC* = :en:Air Force Cross and Bar..."
17619
wikitext
text/x-wiki
{{#switch: {{{1}}}
| AC = [[:en:Honorary Companion of the Order of Australia|AC]]
| ACs = [[:en:Companion of the Order of Australia|AC]]
| AcSS = [[:en:Academician of the Social Sciences|AcSS]]
| ADC = [[:en:Aide de Camp|ADC]]
| ADC Gen= [[:en:Aide-de-Camp General|ADC Gen]]
| ADC(P) = [[:en:Personal Aide-de-Camp|ADC(P)]]
| AE = [[:en:Air Efficiency Award|AE]]
| AFC = [[:en:Air Force Cross (United Kingdom)|AFC]]
| AFC* = [[:en:Air Force Cross and Bar (United Kingdom)|AFC*]]
| AFC** = [[:en:Air Force Cross and two Bars (United Kingdom)|AFC**]]
| AFC1 = [[:en:Air Force Cross and Bar (United Kingdom)|AFC*]]
| AFC2 = [[:en:Air Force Cross and two Bars (United Kingdom)|AFC**]]
| AFM = [[:en:Air Force Medal|AFM]]
| AK = [[:en:Knight of the Order of Australia|AK]]
| AKC = [[:en:Associate of King's College|AKC]]
| AM = [[:en:National Assembly of Wales|AM]]
| AMh = [[:en:Honorary Member of the Order of Australia|AM]]
| AMICE = [[:en:Associate Member of the Institution of Civil Engineers|AMICE]]
| AMInstCE = [[:en:Associate Member of the Institution of Civil Engineers|AMInstCE]]
| AMIMechE = [[:en:Associate Member of the Institution of Mechanical Engineers|AMIMechE]]
| AMIStructE = [[:en:Associate Member of the Institution of Structural Engineers|AMIStructE]]
| AMl = [[:en:London Assembly|AM]]
| AMRSB = [[:en:Associate Member of the Royal Society of Biology|AMRSB]]
| AMw = [[:en:National Assembly of Wales|AM]]
| AO = [[:en:Honorary Officer of the Order of Australia|AO]]
| ARA = [[:en:Associate Member of the Royal Academy|ARA]]
| ARIBA = [[:en:Royal Institute of British Architects|ARIBA]]
| ARCS = [[:en:Associate of the Royal College of Science|ARCS]]
| ARRC = [[:en:Royal Red Cross|ARRC]]
| AsstChStJ = [[:en:Assistant Chaplain of the Order of St John|AsstChStJ]]
| AsstChStJf = [[:en:Assistant Chaplain of the Order of St John|AsstChStJ]]
| BA = [[:en:Bachelor of Arts|BA]]
| Bart = [[:en:Baronet|Bart]]
| Barte = [[:en:Baronet|Bart]]
| Bartgb = [[:en:Baronet|Bart]]
| Barti = [[:en:Baronet|Bart]]
| Bartns = [[:en:Baronet|Bart]]
| BCh = [[:en:Bachelor of Surgery|BCh]]
| BD = [[:en:Bachelor of Divinity|BD]]
| BEM = [[:en:British Empire Medal|BEM]]
| BS = [[:en:Bachelor of Science|BS]]
| BSc = [[:en:Bachelor of Science|BSc]]
| Bt = [[:en:Baronet|Bt]]
| Bte = [[:en:Baronet|Bt]]
| Btgb = [[:en:Baronet|Bt]]
| Bti = [[:en:Baronet|Bt]]
| Btns = [[:en:Baronet|Bt]]
| Btss = [[:en:Baronetess|Btss]]
| Btsse = [[:en:Baronetess|Btss]]
| Btssgb = [[:en:Baronetess|Btss]]
| Btssi = [[:en:Baronetess|Btss]]
| Btssns = [[:en:Baronetess|Btss]]
| CB = [[:en:Companion of the Order of the Bath|CB]]
| CBh = [[:en:Honorary Companion of the Order of the Bath|CB]]
| CBE = [[:en:Commander of the Order of the British Empire|CBE]]
| CBEh = [[:en:Honorary Commander of the Order of the British Empire|CBE]]
| CC = [[:en:Companion of the Order of Canada|CC]]
| CCMI = [[:en:Companion of the Chartered Management Institute|CCMI]]
| CD = [[:en:Canadian Forces Decoration|CD]]
| CEng = [[:en:Chartered Engineer (UK)|CEng]]
| CGA = [[:en:Community of the Glorious Ascension|CGA]]
| CGC = [[:en:Conspicuous Gallantry Cross|CGC]]
| CGM = [[:en:Conspicuous Gallantry Medal|CGM]]
| CH = [[:en:Companion of Honour|CH]]
| ChStJ = [[:en:Chaplain of the Order of St John|ChStJ]]
| CI = [[:en:Companion of the Order of the Crown of India|CI]]
| CIE = [[:en:Companion of the Order of the Indian Empire|CIE]]
| CIEh = [[:en:Honorary Companion of the Order of the Indian Empire|CIE]]
| CM = [[:en:Member of the Order of Canada|CM]]
| CMG = [[:en:Companion of the Order of St Michael and St George|CMG]]
| CMGh = [[:en:Honorary Companion of the Order of St Michael and St George|CMG]]
| CMM = [[:en:Commander of the Order of Military Merit|CMM]]
| CPM = [[:en:Colonial Police Medal|CPM]]
| CR = [[:en:Community of the Resurrection|CR]]
| CSI = [[:en:Companion of the Order of the Star of India|CSI]]
| CSIh = [[:en:Honorary Companion of the Order of the Star of India|CSI]]
| CStJ = [[:en:Commander of the Order of St John|CStJ]]
| CVO = [[:en:Commander of the Royal Victorian Order|CVO]]
| CVOh = [[:en:Honorary Commander of the Royal Victorian Order|CVO]]
| DBE = [[:en:Dame Commander of the Order of the British Empire|DBE]]
| DBEh = [[:en:Honorary Dame Commander of the Order of the British Empire|DBE]]
| DCB = [[:en:Dame Commander of the Order of the Bath|DCB]]
| DCBh = [[:en:Honorary Dame Command of the Most Honorable Order of the Bath|DCB]]
| DCL = [[:en:Doctor of Civil Law|DCL]]
| DCM = [[:en:Distinguished Conduct Medal|DCM]]
| DCM* = [[:en:Distinguished Conduct Medal and Bar|DCM*]]
| DCM1 = [[:en:Distinguished Conduct Medal and Bar|DCM*]]
| DCMG = [[:en:Dame Commander of the Order of St Michael and St George|DCMG]]
| DCMGh = [[:en:Honorary Dame Commander of the Order of St Michael and St George|DCMG]]
| DCVO = [[:en:Dame Commander of the Royal Victorian Order|DCVO]]
| DCVOh = [[:en:Honorary Dame Commander of the Royal Victorian Order|DCVO]]
| DD = [[:en:Doctor of Divinity|DD]]
| DEng = [[:en:Doctor of Engineering|DEng]]
| DFC = [[:en:Distinguished Flying Cross (United Kingdom)|DFC]]
| DFC* = [[:en:Distinguished Flying Cross and Bar (United Kingdom)|DFC*]]
| DFC** = [[:en:Distinguished Flying Cross and two Bars (United Kingdom)|DFC**]]
| DFC1 = [[:en:Distinguished Flying Cross and Bar (United Kingdom)|DFC*]]
| DFC2 = [[:en:Distinguished Flying Cross and two Bars (United Kingdom)|DFC**]]
| DFM = [[:en:Distinguished Flying Medal|DFM]]
| DipMin = [[:en:Diploma|Dip]][[:en:Christian ministry|Min]]
| DLit = [[:en:Doctor of Letters|DLit]]
| DLitt = [[:en:Doctor of Letters|DLitt]]
| DL = [[:en:Deputy Lieutenant|DL]]
| DLi = [[:en:Deputy Lieutenant|DL]]
| DLni = [[:en:Deputy Lieutenant|DL]]
| DLs = [[:en:Deputy Lieutenant|DL]]
| DLw = [[:en:Deputy Lieutenant|DL]]
| DM-med = [[:en:Doctor of Medicine|DM]]
| DM-mus = [[:en:Doctor of Music|DM]]
| DMus = [[:en:Doctor of Music|DMus]]
| DPhil = [[:en:Doctor of Philosophy|DPhil]]
| DSC = [[:en:Distinguished Service Cross (United Kingdom)|DSC]]
| DSC* = [[:en:Distinguished Service Cross and Bar (United Kingdom)|DSC*]]
| DSC** = [[:en:Distinguished Service Cross and two Bars (United Kingdom)|DSC**]]
| DSC1 = [[:en:Distinguished Service Cross and Bar (United Kingdom)|DSC*]]
| DSC2 = [[:en:Distinguished Service Cross and two Bars (United Kingdom)|DSC**]]
| DSG = [[:en:Order of St. Gregory the Great|DSG]]
| DSM = [[:en:Distinguished Service Medal (United Kingdom)|DSM]]
| DSc = [[:en:Doctor of Science|DSc]]
| DSO = [[:en:Distinguished Service Order|DSO]]
| DSO* = [[:en:Distinguished Service Order and Bar|DSO*]]
| DSO** = [[:en:Distinguished Service Order and two Bars|DSO**]]
| DSO*** = [[:en:Distinguished Service Order and three Bars|DSO***]]
| DSO1 = [[:en:Distinguished Service Order and Bar|DSO*]]
| DSO2 = [[:en:Distinguished Service Order and two Bars|DSO**]]
| DSO3 = [[:en:Distinguished Service Order and three Bars|DSO***]]
| DStJ = [[:en:Dame of Justice of the Order of St John|DStJ]]
| DStJg = [[:en:Dame of Grace of the Order of St John|DStJ]]
| ED = [[:en:Efficiency Decoration|ED]]
| ERD = [[:en:Emergency Reserve Decoration|ERD]]
| EsqStJ = [[:en:Esquire of the Order of St John|EsqStJ]]
| FACS = [[:en:Fellow of the American College of Surgeons|FACS]]
| FAcSS = [[:en:Fellow of the Academy of Social Sciences|FAcSS]]
| FBA = [[:en:Fellow of the British Academy|FBA]]
| FBAM = [[:en:Fellow of the British Academy of Management|FBAM]]
| FBCS = [[:en:Fellow of the British Computer Society|FBCS]]
| FBPhS =[[:en:Fellow of the British Pharmacological Society|FBPhS]]
| FCMI = [[:en:Fellow of the Chartered Management Institute|FCMI]]
| FCS = [[:en:Fellow of the Chemical Society|FCS]]
| FEIS = [[:en:Fellow of the Educational Institute of Scotland|FEIS]]
| FGS = [[:en:Fellow of the Geological Society|FGS]]
| FFPM = [[:en:Faculty of Pharmaceutical Medicine|FFPM]]
| FHAS = [[:en:Fellow of the Royal Highland and Agricultural Society of Scotland|FHAS]]
| FHS = [[:en:Fellow of the Heraldry Society|FHS]]
| FFA = [[:en:Fellow of the Faculty of Actuaries|FFA]]
| FIA = [[:en:Fellow of the Institute of Actuaries|FIA]]
| FIBiol = [[:en:Fellow of the Institute of Biology|FIBiol]]
| FIC = [[:en:Fellow of the Institute of Chemistry|FIC]]
| FICE = [[:en:Fellow of the Institution of Civil Engineers|FICE]]
| FIEE = [[:en:Fellow of the Institution of Electrical Engineers|FIEE]]
| FIET = [[:en:Fellow of the Institution of Engineering and Technology|FIET]]
| FIMechE= [[:en:Fellow of the Institution of Mechanical Engineers|FIMechE]]
| FIStructE = [[:en:Fellow of the Institution of Structural Engineers|FIStructE]]
| FInstP = [[:en:Fellow of the Institute of Physics|FInstP]]
| FKC = [[:en:Fellow of King's College|FKC]]
| FLS = [[:en:Fellow of the Linnean Society of London|FLS]]
| FLSW = [[:en:Fellow of the Learned Society of Wales|FLSW]]
| FMedSci= [[:en:Fellow of the Academy of Medical Sciences|FMedSci]]
| FRAS = [[:en:Fellow of the Royal Astronomical Society|FRAS]]
| FRAeS = [[:en:Fellow of the Royal Aeronautical Society|FRAeS]]
| FRCGP = [[:en:Fellow of the Royal College of General Practitioners|FRCGP]]
| FRCM = [[:en:Fellow of the Royal College of Music|FRCM]]
| FRCO = [[:en:Fellow of the Royal College of Organists|FRCO]]
| FRCOG = [[:en:Fellow of the Royal College of Obstetricians and Gynaecologists|FRCOG]]
| FRCP = [[:en:Fellow of the Royal College of Physicians|FRCP]]
| FRCPath= [[:en:Fellow of the Royal College of Pathologists|FRCPath]]
| FRCPE = [[:en:Fellow of the Royal College of Physicians of Edinburgh|FRCPE]]
| FRCPGlas= [[:en:Fellow of the Royal College of Physicians and Surgeons of Glasgow|FRCPGlas]]
| FRCPI = [[:en:Fellow of the Royal College of Physicians of Ireland|FRCPI]]
| FRCR = [[:en:Fellow of the Royal College of Radiologists|FRCR]]
| FRCS = [[:en:Fellow of the Royal College of Surgeons|FRCS]]
| FRCSE = [[:en:Fellow of the Royal College of Surgeons of Edinburgh|FRCSE]]
| FRCSI = [[:en:Fellow of the Royal College of Surgeons of Ireland|FRCSI]]
| FRCVS = [[:en:Fellow of the Royal College of Veterinary Surgeons|FRCVS]]
| FREng = [[:en:Fellow of the Royal Academy of Engineering|FREng]]
| FRGS = [[:en:Fellow of the Royal Geographical Society|FRGS]]
| FRHistS= [[:en:Fellow of the Royal Historical Society|FRHistS]]
| FRIBA = [[:en:Fellow of the Royal Institute of British Architects|FRIBA]]
| FRICS = [[:en:Fellow of the Royal Institution of Chartered Surveyors|FRICS]]
| FRMS = [[:en:Fellow of the Royal Microscopical Society|FRMS]]
| FRPharmS = [[:en:Fellow of the Royal Pharmaceutical Society|FRPharmS]]
| FRS = [[:en:Fellow of the Royal Society|FRS]]
| FRSA = [[:en:Fellow of the Royal Society for the encouragement of Arts, Manufactures and Commerce|FRSA]]
| FSAS = [[:en:Fellow of the Society of Antiquaries of Scotland|FSAS]]
| FRSB = [[:en:Fellow of the Royal Society of Biology|FRSB]]
| FRSC = [[:en:Fellow of the Royal Society of Chemistry|FRSC]]
| FRSE = [[:en:Fellow of the Royal Society of Edinburgh|FRSE]]
| FRSf = [[:en:Fellow of the Royal Society|FRS]]
| FRSfh = [[:en:Honorary Fellow of the Royal Society|FRS]]
| FRSGS = [[:en:Fellow of the Royal Scottish Geographical Society|FRSGS]]
| FRSh = [[:en:Honorary Fellow of the Royal Society|FRS]]
| FRSL = [[:en:Fellow of the Royal Society of Literature|FRSL]]
| FRSr = [[:en:Royal Fellow of the Royal Society|FRS]]
| FRSS = [[:en:Fellow of the Royal Statistical Society|FRSS]]
| FRSSA = [[:en:Fellow of the Royal Scottish Society of Arts|FRSSA]]
| FSA = [[:en:Fellow of the Society of Antiquaries of London|FSA]]
| FSAs = [[:en:Fellow of the Society of Antiquaries of Scotland|FSA Scot]]
| FSB = [[:en:Fellow of The Society of Biology|FSB]]
| FSSc = [[:en:Fellow of the Society of Science, Letters and Art|FSSc]]
| FZS = [[:en:Fellow of the London Zoological Society|FZS]]
| GBE = [[:en:Knight Grand Cross of the Order of the British Empire|GBE]]
| GBEf = [[:en:Dame Grand Cross of the Order of the British Empire|GBE]]
| GBEfh = [[:en:Honorary Dame Grand Cross of the Order of the British Empire|GBE]]
| GBEh = [[:en:Honorary Knight Grand Cross of the Order of the British Empire|GBE]]
| GBEm = [[:en:Knight Grand Cross of the Order of the British Empire|GBE]]
| GBEmh = [[:en:Honorary Knight Grand Cross of the Order of the British Empire|GBE]]
| GC = [[:en:George Cross|GC]]
| GCB = [[:en:Knight Grand Cross of the Order of the Bath|GCB]]
| GCBf = [[:en:Dame Grand Cross of the Order of the Bath|GCB]]
| GCBfh = [[:en:Honorary Dame Grand Cross of the Order of the Bath|GCB]]
| GCBh = [[:en:Honorary Knight Grand Cross of the Order of the Bath|GCB]]
| GCBm = [[:en:Knight Grand Cross of the Order of the Bath|GCB]]
| GCBmh = [[:en:Honorary Knight Grand Cross of the Order of the Bath|GCB]]
| GCH = [[:en:Knight Grand Cross of the Royal Guelphic Order|GCH]]
| GCIE = [[:en:Knight Grand Commander of the Order of the Indian Empire|GCIE]]
| GCIEh = [[:en:Honorary Knight Grand Commander of the Order of the Indian Empire|GCIE]]
| GCL = [[:en:Grand Companion of the Order of Logohu|GCL]]
| GCMG = [[:en:Knight Grand Cross of the Order of St Michael and St George|GCMG]]
| GCMGf = [[:en:Dame Grand Cross of the Order of St Michael and St George|GCMG]]
| GCMGfh = [[:en:Honorary Dames Grand Cross of the Order of St Michael and St George|GCMG]]
| GCMGh = [[:en:Honorary Knight Grand Cross of the Order of St Michael and St George|GCMG]]
| GCMGm = [[:en:Knight Grand Cross of the Order of St Michael and St George|GCMG]]
| GCMGmh = [[:en:Honorary Knight Grand Cross of the Order of St Michael and St George|GCMG]]
| GCSI = [[:en:Knight Grand Commander of the Order of the Star of India|GCSI]]
| GCSIh = [[:en:Honorary Knight Grand Commander of the Order of the Star of India|GCSI]]
| GCStJ = [[:en:Bailiff Grand Cross of the Order of St John|GCStJ]]
| GCStJf = [[:en:Dame Grand Cross of the Order of St John|GCStJ]]
| GCVO = [[:en:Knight Grand Cross of the Royal Victorian Order|GCVO]]
| GCVOf = [[:en:Dame Grand Cross of the Royal Victorian Order|GCVO]]
| GCVOfh = [[:en:Honorary Dame Grand Cross of the Royal Victorian Order|GCVO]]
| GCVOh = [[:en:Honorary Knight Grand Cross of the Royal Victorian Order|GCVO]]
| GCVOm = [[:en:Knight Grand Cross of the Royal Victorian Order|GCVO]]
| GCVOmh = [[:en:Honorary Knight Grand Cross of the Royal Victorian Order|GCVO]]
| GM = [[:en:George Medal|GM]]
| GMB = [[:en:Great Master of the Order of the Bath|GMB]]
| IDSM = [[:en:Indian Distinguished Service Medal|IDSM]]
| IOM = [[:en:Indian Order of Merit|IOM]]
| ISO = [[:en:Imperial Service Order|ISO]]
| JP = [[:en:Justice of the Peace#United Kingdom|JP]]
| KB = [[:en:Knight of the Bath (1399–1725)|KB]]
| KB2 = [[:en:Knight Companion of the Order of the Bath (1725–1815)|KB]]
| KBE = [[:en:Knight Commander of the Order of the British Empire|KBE]]
| KBEh = [[:en:Honorary Knight Commander of the Order of the British Empire|KBE]]
| KC = [[:en:King's Counsel|KC]]
| KCB = [[:en:Knight Commander of the Order of the Bath|KCB]]
| KCBh = [[:en:Honorary Knight Commander of the Order of the Bath|KCB]]
| KCH = [[:en:Knight Commander of the Royal Guelphic Order|KCH]]
| KCIE = [[:en:Knight Commander of the Order of the Indian Empire|KCIE]]
| KCIEh = [[:en:Honorary Knight Commander of the Order of the Indian Empire|KCIE]]
| KCMG = [[:en:Knight Commander of the Order of St Michael and St George|KCMG]]
| KCMGh = [[:en:Honorary Knight Commander of the Order of St Michael and St George|KCMG]]
| KCSI = [[:en:Knight Commander of the Order of the Star of India|KCSI]]
| KCSIh = [[:en:Honorary Knight Commander of the Order of the Star of India|KCSI]]
| KCVO = [[:en:Knight Commander of the Royal Victorian Order|KCVO]]
| KCVOh = [[:en:Honorary Knight Commander of the Royal Victorian Order|KCVO]]
| KG = [[:en:Knight of the Order of the Garter|KG]]
| KGc = [[:en:Knight Companion of the Order of the Garter|KG]]
| KGe = [[:en:Extra Knight of the Order of the Garter|KG]]
| KGr = [[:en:Royal Knight Companion of the Order of the Garter|KG]]
| KH = [[:en:Knight of the Royal Guelphic Order|KH]]
| KHS = [[:en:Knight of the Holy Sepulchre|KHS]]
| KMT = [[:en:Knight of the Military Order of Maria Theresa|KMT]]
| KP = [[:en:Knight of the Order of St Patrick|KP]]
| KS = [[:en:Serjeant-at-law#King's or Queen's Serjeants|KS]]
| KSG = [[:en:Order of St. Gregory the Great|KSG]]
| KSI = [[:en:Knight Commander of the Order of the Star of India|KSI]]
| KSIh = [[:en:Honorary Knight Commander of the Order of the Star of India|KSI]]
| KSIp = [[:en:Knight Companion of the Order of the Star of India|KSI]]
| KSIph = [[:en:Honorary Knight Companion of the Order of the Star of India|KSI]]
| KStJ = [[:en:Knight of Justice of the Order of St John|KStJ]]
| KStJg = [[:en:Knight of Grace of the Order of St John|KStJ]]
| KT = [[:en:Knight Companion of the Order of the Thistle|KT]]
| KTh = [[:en:Honorary Knight Companion of the Order of the Thistle|KT]]
| Kt = [[:en:Knight Bachelor|Kt]]
| LG = [[:en:Lady of the Order of the Garter|LG]]
| LGc = [[:en:Lady Companion of the Order of the Garter|LG]]
| LGe = [[:en:Extra Lady of the Order of the Garter|LG]]
| LitD = [[:en:Doctor of Letters|LitD]]
| LittD = [[:en:Doctor of Letters|LittD]]
| LLB = [[:en:Bachelor of Laws|LLB]]
| LLD = [[:en:Legum Doctor|LLD]]
| LMSSA = [[:en:Licentiate in Medicine and Surgery of the Society of Apothecaries|LMSSA]]
| LRCP = [[:en:Licentiate of the Royal College of Physicians|LRCP]]
| LT = [[:en:Lady Companion of the Order of the Thistle|LT]]
| LVO = [[:en:Lieutenant of the Royal Victorian Order|LVO]]
| MA = [[:en:Master of Arts|MA]]
| MA(Camb) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Camb)]]
| MA(Cantab) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Cantab)]]
| MA(Dublin) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Dublin)]]
| MA(Oxf) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Oxf)]]
| MA(Oxon) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Oxon)]]
| MA(Trinity) = [[:en:Master of Arts (Oxbridge and Dublin)|MA(Trinity)]]
| MAsc = [[:en:Master of Arts (Scotland)|MA]]
| MB = [[:en:Bachelor of Medicine|MB]]
| MBBCh = [[:en:Bachelor of Medicine, Bachelor of Surgery|MBBCh]]
| MBChB = [[:en:Bachelor of Medicine, Bachelor of Surgery|MBChB]]
| MBE = [[:en:Member of the Order of the British Empire|MBE]]
| MBEh = [[:en:Honorary Member of the Order of the British Empire|MBE]]
| MC = [[:en:Military Cross|MC]]
| MC* = [[:en:Military Cross and Bar|MC*]]
| MC** = [[:en:Military Cross and two Bars|MC**]]
| MC1 = [[:en:Military Cross and Bar|MC*]]
| MC2 = [[:en:Military Cross and two Bars|MC**]]
| MD = [[:en:Doctor of Medicine|MD]]
| MEP = [[:en:Member of the European Parliament|MEP]]
| MIEE = [[:en:Member of the Institution of Electrical Engineers|MIEE]]
| MIET = [[:en:Member of the Institution of Engineering and Technology|MIET]]
| MICE = [[:en:Member of the Institution of Civil Engineers|MICE]]
| MIMechE = [[:en:Member of the Institution of Mechanical Engineers|MIMechE]]
| MIMM = [[:en:Member of the Institution of Mining and Metallurgy|MIMM]]
| MINA = [[:en:Member of the Institution of Naval Architects|MINA]]
| MInstCE = [[:en:Member of the Institution of Civil Engineers|MInstCE]]
| MIStructE = [[:en:Member of the Institution of Structural Engineers|MIStructE]]
| MLA = [[:en:Member of the Northern Ireland Assembly|MLA]]
| MLC = [[:en:Member of Legislative Council|MLC]]
| MM = [[:en:Military Medal|MM]]
| MM* = [[:en:Military Medal and Bar|MM*]]
| MM** = [[:en:Military Medal and two Bars|MM**]]
| MM1 = [[:en:Military Medal and Bar|MM*]]
| MM2 = [[:en:Military Medal and two Bars|MM**]]
| MMM = [[:en:Member of the Order of Military Merit|MMM]]
| MP = [[:en:Member of the British House of Commons|MP]]
| MPe = [[:en:Member of the British House of Commons|MP]]
| MPi = [[:en:Member of the British House of Commons|MP]]
| MPni = [[:en:Member of the British House of Commons|MP]]
| MPs = [[:en:Member of the British House of Commons|MP]]
| MPw = [[:en:Member of the British House of Commons|MP]]
| MRCS = [[:en:Member of the Royal College of Surgeons|MRCS]]
| MRCVS = [[:en:Member of the Royal College of Veterinary Surgeons|MRCVS]]
| MRIA = [[:en:Member of the Royal Irish Academy|MRIA]]
| MRIAh = [[:en:Honorary Member of the Royal Irish Academy|HonMRIA]]
| MRSB = [[:en:Member of the Royal Society of Biology|MRSB]]
| MSc = [[:en:Master of Science|MSc]]
| MSM = [[:en:Meritorious Service Medal (United Kingdom)|MSM]]
| MSP = [[:en:Member of the Scottish Parliament|MSP]]
| MStJ = [[:en:Member of the Order of St John|MStJ]] <noinclude>In use since 2008</noinclude>
| MSYP = [[:en:Member of Scottish Youth Parliament|MSYP]]
| MusD = [[:en:Doctor of Music|MusD]]
| MusDoc = [[:en:Doctor of Music|MusDoc]]
| MVO = [[:en:Member of the Royal Victorian Order|MVO]]
| MVOh = [[:en:Honorary Member of the Royal Victorian Order|MVO]]
| MYP = [[:en:Member of Youth Parliament|MYP]]
| OBE = [[:en:Officer of the Order of the British Empire|OBE]]
| OBEh = [[:en:Honorary Officer of the Order of the British Empire|OBE]]
| OBI = [[:en:Member of the Order of British India|OBI]]
| OBIb = [[:en:Bahadur of the Order of British India|OBI]]
| OBIs = [[:en:Sardar Bahadur of the Order of British India|OBI]]
| OC = [[:en:Officer of the Order of Canada|OC]]
| OCC = [[:en:Member of The Order of the Caribbean Community|OCC]]
| OE = [[:en:Member of the Order of Excellence of Guyana|OE]]
| OM = [[:en:Member of the Order of Merit|OM]]
| OMM = [[:en:Officer of the Order of Military Merit|OMM]]
| ONZ = [[:en:Honorary Member of the Order of New Zealand|ONZ]]
| ONZs = [[:en:Member of the Order of New Zealand|ONZ]]
| OStJ = [[:en:Officer of the Order of St John|OStJ]]
| PC = [[:en:Privy Council of the United Kingdom|PC]]
| PCc = [[:en:Queen's Privy Council for Canada|PC (Can)]]
| PCe = [[:en:Privy Counsellor (England)|PC]]
| PCgb = [[:en:Privy Counsellor (GB)|PC]]
| PCi = [[:en:Privy Council of Ireland|PC (Ire)]]
| PCs = [[:en:Privy Counsellor (Scotland)|PC]]
| PhD = [[:en:Doctor of Philosophy|PhD]]
| PRA = [[:en:President of the Royal Academy|PRA]]
| PRS = [[:en:President of the Royal Society|PRS]]
| QC = [[:en:Queen's Counsel|QC]]
| QC(Hon)= [[:en:Queen's Counsel Honoris Causa|QC (Hon.)]]
| QFSM = [[:en:Queen's Fire Service Medal|QFSM]]
| QGM = [[:en:Queen's Gallantry Medal|QGM]]
| QHC = [[:en:Honorary Chaplain to The Queen|QHC]]
| QHDS = [[:en:Honorary Dental Surgeon to The Queen|QHDS]]
| QHNS = [[:en:Honorary Nursing Sister to The Queen|QHNS]]
| QHP = [[:en:Honorary Physician to The Queen|QHP]]
| QHS = [[:en:Honorary Surgeon to The Queen|QHS]]
| QPM = [[:en:Queen's Police Medal|QPM]]
| QS = [[:en:Serjeant-at-law#King's or Queen's Serjeants|QS]]
| QSO = [[:en:Companion of the Queen's Service Order|QSO]]
| QSOe = [[:en:Extra Companion of the Queen's Service Order|QSO]]
| QSOh = [[:en:Honorary Companion of the Queen's Service Order|QSO]]
| RA = [[:en:Royal Academician|RA]]
| RAF = [[:en:Serving Officer of the Royal Air Force|RAF]]
| RAFr = [[:en:Retired Officer of the Royal Air Force|RAF (rtd.)]]
| RD = [[:en:Decoration for Officers of the Royal Naval Reserve|RD]]
| RDI = [[:en:Royal Designer for Industry|RDI]]
| RDIh = [[:en:Honorary Royal Designer for Industry|HonRDI]]
| RFA = [[:en:Royal Field Artillery|RFA]]
| RFAx = [[:en:Royal Fleet Auxiliary|RFA]]
| RIAS = [[:en:Royal Incorporation of Architects in Scotland|RIAS]]
| RIBA = [[:en:Royal Institute of British Architects|RIBA]]
| RIN = [[:en:Royal Indian Navy|RIN]]
| RM = [[:en:Serving Officer of the Royal Marines|RM]]
| RN = [[:en:Serving Officer of the Royal Navy|RN]]
| RNr = [[:en:Retired Officer of the Royal Navy|RN]]
| RNR = [[:en:Royal Naval Reserve|RNR]]
| RNVR = [[:en:Royal Naval Volunteer Reserve|RNVR]]
| RRC = [[:en:Royal Red Cross|RRC]]
| RVM = [[:en:Royal Victorian Medal|RVM]]
| SBStJ = [[:en:Serving Brother of the Order of St John|SBStJ]]
| SSC = [[:en:Society of the Holy Cross|SSC]]
| SSStJ = [[:en:Serving Sister of the Order of St John|SSStJ]]
| Sub-ChStJ = [[:en:Sub-Chaplain of the Order of St John|Sub-ChStJ]]
| SGM = [[:en:Sea Gallantry Medal|SGM]]
| SL = [[:en:Serjeant-at-law|SL]]
| TD = [[:en:Territorial Decoration|TD]]
| UD = [[:en:Ulster Defence Regiment Decoration|UD]]
| VA = [[:en:Lady of the Royal Order of Victoria and Albert|VA]]
| VC = [[:en:Victoria Cross|VC]]
| VC* = [[:en:Victoria Cross and bar|VC*]]
| VD = [[:en:Volunteer Decoration|VD]]
| VRD = [[:en:Decoration for Officers of the Royal Naval Volunteer Reserve|VRD]]
| WS = [[:en:Writer to the Signet|WS]]
}}<noinclude>See [[:en:Template:Post-nominals/doc]] for more information about this template.
Order of Precedence for post-nominals is in [[:en:List of post-nominal letters (United Kingdom)]]
{{documentation}}
</noinclude>
oayyhv6vm8p3vttakbmylf5a2013284
တမ်းပလိတ်:Pp-protected
10
3820
17620
2026-03-29T16:48:42Z
YaThaWinTha
42
Created page with "{{#invoke:Protection banner|main}}<noinclude> {{documentation}} </noinclude>"
17620
wikitext
text/x-wiki
{{#invoke:Protection banner|main}}<noinclude>
{{documentation}}
</noinclude>
8rt1snyv5yit3jnuzrbl00negaj27e5
တမ်းပလိတ်:Pronunciation
10
3821
17621
2026-03-29T16:49:18Z
YaThaWinTha
42
Created page with "{{Audio<!--PLEASE DO NOT SUBST-->|{{{1}}}|အသံထွက်}}<noinclude> {{documentation}} [[Category:Pronunciation templates]] </noinclude>"
17621
wikitext
text/x-wiki
{{Audio<!--PLEASE DO NOT SUBST-->|{{{1}}}|အသံထွက်}}<noinclude>
{{documentation}}
[[Category:Pronunciation templates]]
</noinclude>
crp9c1edajlhncb5g9uzu72fey4u1l0
တမ်းပလိတ်:Error-small
10
3822
17622
2026-03-29T16:50:14Z
YaThaWinTha
42
Created page with "{{#invoke:Error|error|{{{message|{{{1}}}}}}|tag=span|style=font-size:inherit}}<noinclude>{{documentation}}</noinclude>"
17622
wikitext
text/x-wiki
{{#invoke:Error|error|{{{message|{{{1}}}}}}|tag=span|style=font-size:inherit}}<noinclude>{{documentation}}</noinclude>
hnkvrfis3ah1x3eijkfnl3mnf6fdn7m
တမ်းပလိတ်:Release date and age
10
3823
17623
2026-03-29T16:51:40Z
YaThaWinTha
42
Created page with "<includeonly><!-- IMPLEMENTATION OF DATE -->{{#if: {{{1|}}}<!-- -->|{{#if: {{{2|}}}<!-- -->|{{#if: {{{3|}}}<!-- -->|{{#ifeq:{{yesno|{{{df|no}}}}}|yes<!-- -->|{{formatnum:{{#expr:{{{3}}}}}}} {{MONTHNAME|{{{2}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}} {{formatnum:{{#expr:{{{3}}}}}}}၊<!-- -->}} {{formatnum:{{{1}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}} {{formatnum:{{{1}}}}}<!-- -->}}<!-- -->|{{for..."
17623
wikitext
text/x-wiki
<includeonly><!--
IMPLEMENTATION OF DATE
-->{{#if: {{{1|}}}<!--
-->|{{#if: {{{2|}}}<!--
-->|{{#if: {{{3|}}}<!--
-->|{{#ifeq:{{yesno|{{{df|no}}}}}|yes<!--
-->|{{formatnum:{{#expr:{{{3}}}}}}} {{MONTHNAME|{{{2}}}}}<!--
-->|{{MONTHNAME|{{{2}}}}} {{formatnum:{{#expr:{{{3}}}}}}}၊<!--
-->}} {{formatnum:{{{1}}}}}<!--
-->|{{MONTHNAME|{{{2}}}}} {{formatnum:{{{1}}}}}<!--
-->}}<!--
-->|{{formatnum:{{{1}}}}}<!--
-->}}<!--
--><span class="noprint">{{#ifeq:{{yesno|{{{paren|{{{p|no}}}}}}}}|yes||;}}<!--
-->{{#ifeq:{{yesno|{{{br|no}}}}}|yes|<br/>| }}<!--
-->{{#ifeq:{{yesno|{{{paren|{{{p|no}}}}}}}}|yes|(}}<!--
-->{{#if: {{{2|}}}<!--
-->|{{#if: {{{3|}}}<!--
-->|{{time ago|{{{1}}}-{{{2}}}-{{{3}}}|min_magnitude=days}}<!--
-->|{{years or months ago|{{{1}}}|{{#time:n|1-{{{2}}}-1|en}}}}<!--
-->}}<!--
-->|{{#iferror:{{#expr:{{{1}}}}}<!--
-->|{{time ago|{{{1}}}|min_magnitude=days}}<!--
-->|{{years or months ago|{{{1}}}}}<!--
-->}}<!--
-->}}<!--
-->{{#ifeq:{{yesno|{{{paren|{{{p|no}}}}}}}}|yes|)}}</span><!--
-->|'''{{color|red|Error: first parameter is missing.}}'''<!--
-->}}<!--
IMPLEMENTATION OF microformat date classes
--><span style="display:none"> (<span class="{{#ifeq:{{yesno|{{{end|no}}}}}|yes|dtend|bday dtstart published updated}}"><!--
-->{{#if: {{{1|}}}<!--
-->|{{formatnum:{{{1}}}}}<!--
-->{{#if: {{{2|}}}<!--
-->| -{{#time:m|1-{{{2}}}-1}}<!--
-->{{#if: {{{3|}}}<!--
-->| -{{padleft:{{{3}}}|2|0}}<!--
-->}}<!--
-->}}<!--
-->}}<!--
--></span>)</span></includeonly><noinclude>
{{documentation}}
</noinclude>
mxurppn9bijfaeed79ohca72nn2zht2
တမ်းပလိတ်:SHORTDESC:
10
3824
17624
2026-03-29T16:52:24Z
YaThaWinTha
42
Created page with "{{#ifeq:{{lc:{{{1|}}}}}|none|<nowiki /><!--Prevents whitespace issues when used with adjacent newlines-->|<div class="shortdescription nomobile noexcerpt noprint searchaux" style="display:none">{{{1|}}}{{SHORTDESC:{{{1|}}}|{{{2|}}}}}</div>}}<includeonly>{{#ifeq:{{{pagetype}}}|သံတူကြောင်းကွဲ စာမျက်နှာတိ||{{#ifeq:{{pagetype |defaultns = all |user=exclude}}|exclude||{{#ifeq:{{#switch: {{NAMESPACENUMBER}} | 2 | 3 | 4 | 5 | 6..."
17624
wikitext
text/x-wiki
{{#ifeq:{{lc:{{{1|}}}}}|none|<nowiki /><!--Prevents whitespace issues when used with adjacent newlines-->|<div class="shortdescription nomobile noexcerpt noprint searchaux" style="display:none">{{{1|}}}{{SHORTDESC:{{{1|}}}|{{{2|}}}}}</div>}}<includeonly>{{#ifeq:{{{pagetype}}}|သံတူကြောင်းကွဲ စာမျက်နှာတိ||{{#ifeq:{{pagetype |defaultns = all |user=exclude}}|exclude||{{#ifeq:{{#switch: {{NAMESPACENUMBER}} | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 100 | 101 | 118 | 119 | 828 | 829 | = exclude|#default=}}|exclude||[[Category:ဖော်ပြချက်တို ပါဝင်ရေ {{{pagetype|{{pagetype |defaultns = extended |plural=y}}}}}]]}}}}}}</includeonly><!-- Start tracking
-->{{#ifexpr: {{#invoke:String|len|{{{1|}}}}}>100 | [[Category:ရှည်လျားရေ ဖော်ပြချက်တိုပါဝင်ရေ {{{pagetype|{{pagetype |defaultns = extended |plural=y}}}}}]]}}<!--
--><includeonly>{{#if:{{{1|}}}||[[Category:ဖော်ပြချက်တို ဗလာဖြစ်နီရေ စာမျက်နှာတိ]]}}</includeonly><!--
-->{{Main other |{{SDcat |sd={{{1|}}} }} }}<noinclude>
{{Documentation}}
</noinclude>
0mo5kmvj00pm9rh6um9s3clgegqt5ru
တမ်းပလိတ်:Sfnp
10
3825
17625
2026-03-29T16:54:01Z
YaThaWinTha
42
Created page with "<includeonly>{{#invoke:Footnotes|sfn |bracket_year_left = ( |bracket_year_right = ) }}</includeonly><noinclude> {{documentation}} </noinclude>"
17625
wikitext
text/x-wiki
<includeonly>{{#invoke:Footnotes|sfn
|bracket_year_left = (
|bracket_year_right = )
}}</includeonly><noinclude>
{{documentation}}
</noinclude>
q19wkytjnfjjrpm0011n7vx6giiioom
တမ်းပလိတ်:Spaced ndash
10
3826
17626
2026-03-29T16:54:25Z
YaThaWinTha
42
Created page with " – <noinclude> {{documentation}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude>"
17626
wikitext
text/x-wiki
– <noinclude>
{{documentation}}
<!-- Add categories and interwikis to the /doc subpage, not here! -->
</noinclude>
44od3v3hy3o7813hgbduh1peb2790sz
တမ်းပလိတ်:Stub documentation
10
3827
17627
2026-03-29T16:55:40Z
YaThaWinTha
42
Created page with "ဒေတမ်းပလိတ်မှာ '''ဆောင်းပါးတို တမ်းပလိတ်'''တခုဖြစ်တေ။ ၎င်းတမ်းပလိတ်တိအကြောင်း အကျိုင်းယှင်းလင်းချက်မှာ အောက်ပါအတိုင်းဖြစ်တေ။ အသေးစိတ်သိဟိလိုကေ ဝီကီးပီးဒီးယား:ဆောင်းပါး..."
17627
wikitext
text/x-wiki
ဒေတမ်းပလိတ်မှာ '''ဆောင်းပါးတို တမ်းပလိတ်'''တခုဖြစ်တေ။ ၎င်းတမ်းပလိတ်တိအကြောင်း အကျိုင်းယှင်းလင်းချက်မှာ အောက်ပါအတိုင်းဖြစ်တေ။ အသေးစိတ်သိဟိလိုကေ [[ဝီကီးပီးဒီးယား:ဆောင်းပါးတို]]တိအကြောင်းမာ ကြည့်ရှုပါ။
=== ဆောင်းပါးတိုဆိုစွာ ဇာလေ့? ===
'''ဆောင်းပါးတို'''ဆိုစွာမာ ဝါကျအကြောင်းရေ စိကေသျှေသာပါဟိဗျာယ်း ၎င်းနန့်သက်ဆိုင်ရေ အကြောင်းအရာအား ပြည့်စုံစွာ ခြုံငုံဖော်ပြနိူင်စွမ်းမဟိရေ စွယ်စုံကျမ်း ဆောင်းပါးအရာမမြောက်ရေ ဆောင်းပါးတစ်ပုဒ်ပင်ဖြစ်တေ။
=== ဆောင်းပါးတိုကို တခုပိုင်လေ့တ်သားဖို့လဲ ===
* ဖြစ်နှိုင်ပါက မိမိရီးသားရေ ဆောင်းပါးတိုနန့် အသင့်တော်ဆုံး တမ်းပလိတ်ကိုသုံး၍ မှတ်သားပါ။ စာရင်းအပြည့်အစုံမှာ နောင်ရခိုင်ဝီကီး တိုးပွားစေပင်လာရေအခါ [[ဝီကီးပီးဒီးယား:ဝီကီးပရောဂျက် ဆောင်းပါးတို စီမံရီး/ဆောင်းပါးတို အမျိုးအစားတိ]] အဖြစ် ပရောဂျက်တခုအနေနန့် စီစိုင်ရန်ဖြစ်တေ။
* လိုအပ်ပါကေ ဆောင်းပါးတို တမ်းပလိတ် (၂)ခုထက်ပိုပြီးကေ သုံးနှိုင်ရေ်လည်း၊ အများဆုံး (၄)ခုထက်ပိုပြီးကေ မသုံးသင့်ပါ၊၊
* ဆောင်းပါးတို တမ်းပလိတ်ကို “ပြင်ပချိတ်ဆက်လင့်တိ”၊ လှည့်လည်ကြည့်ရှုရာမာ လွယ်ကူစီရန် ကူညီရေ လက်ကြားပြ တမ်းပလိတ်တိ(navigation template)၊ ကဏ္ဍတိ(category)၊ စာတွဲအမှတ်အသားတိ(tag) စသည်ရို့ အားနုန်းဧ့ အနောက်၊ ဆောင်းပါးဧ့ ''[[:en:WP:FOOTERS|နောက်ပိတ်ဆုံး]]''နီရာတွင် ထည့်သွင်းပါ။ တမ်းပလိတ်တိကို ထည့်သွင်းရေ ထုံးစံအတိုင်း <code><nowiki>{{stub}}</nowiki></code> ဟု တွန့်ကွင်းနှစ်ထပ်ကြားမာ ရီးပါ။
=== ဆက်ပနာလိ့လာရန် ===
ဒေအကြောင်းကို ဆက်ပနာလိ့လာလိုကေ အောက်ပါရို့ကို ရှုပါ:
* [[ဝီကီးပီးဒီးယား:ဆောင်းပါးတို]]
* [[ဝီကီးပီးဒီးယား:ဝီကီးပရောဂျက် ဆောင်းပါးတို စီမံရီး]]([[:en:Wikipedia:WikiProject Stub sorting|Wikipedia:WikiProject Stub sorting]]) - ''(ရခိုင်ဝီကီးမာ ဒေပရောဂျက် မဟိသိမ့်/ဟိရန်မလိုသိမ့်ပါ။ နောင်လုပ်ရဖို့ အလုပ်တခုအဖြစ်မှတ်နိုင်ရေ။)''
နောင်မာ ရခိုင်ဝီကီး၌ ဆောင်းပါးတိတိုးပွားလာပြီးကေ ဆောင်းပါးတို အမျိုးအစား မြောက်မြားစွာဟိလှာယားယပြီးနောက်မာ ဆောင်းပါးတို တမ်းပလိတ်အသစ်တိနန့် ဆောင်းပါးတို အမျိုးအစားအသစ်တိကို မိမိသဘောနန့်မိမိ မဖန်တီးဘဲ [[ဝီကီးပီးဒီးယား:ဝီကီးပရောဂျက် ဆောင်းပါးတို စီမံရီး/အဆိုပြုလွှာတိ]] မာ တင်ပြအဆိုပြုပနာ အတိသဘောတူညီချက်ရယားမှရာ အသစ်ဖန်တီးသင့်ရေ။ ယေမှသာ ရခိုင်ဝီကီးတခုလုံးဟိ ဆောင်းပါးတို အမျိုးအစားနန့် တမ်းပလိတ်တိကို စနစ်တကျ စီစိုင်ထားသိုခြင်းနန့် ရှုပ်ထွီးမှုနန့် ပြဿနာတိ နည်းပါးစီဖို့ဖြစ်တေ။ အဂုအချိန်ပိုင် ရခိုင်ဝီကီး အားနည်းနေချိန်မှာပင် အခြားသူတိ ဖန်တီးထားရေ ဆောင်းပါးတို (stub) တိ၊ ဆောင်းပါးတို ကဏ္ဍ (stub category) တိ၊ ဆောင်းပါးတို တမ်းပလိတ် (stub template) တိကို ကြီးကြီးမားမား အပြောင်းအလဲမပြုမီ အတိနန့် ဆွီးနွီးလက်သပ်သင့်ပါရေ။
<noinclude>
{{documentation}}
[[ကဏ္ဍ:တမ်းပလိတ် စာရွက်စာတမ်းပြုစုခြင်း]]
</noinclude>
tvu47d63r0756edvnaednwetk0ebpq7
တမ်းပလိတ်:Su
10
3828
17628
2026-03-29T16:56:20Z
YaThaWinTha
42
Created page with "{{#invoke:Su|main}}<noinclude> {{documentation}} <!-- Categories go on the /doc subpage, and interwikis go on Wikidata. --> </noinclude>"
17628
wikitext
text/x-wiki
{{#invoke:Su|main}}<noinclude>
{{documentation}}
<!-- Categories go on the /doc subpage, and interwikis go on Wikidata. -->
</noinclude>
6bkrs91uek4wf6qc8u3kn1ipqfajpnd
Module:Su
828
3829
17629
2026-03-29T16:56:54Z
YaThaWinTha
42
Created page with "-- This module implements {{su}}. local p = {} function p.main(frame) -- Use arguments from the parent frame only, and remove any blank arguments. -- We don't need to trim whitespace from any arguments, as this module only -- uses named arguments, and whitespace is trimmed from them automatically. local origArgs = frame:getParent().args local args = {} for k, v in pairs(origArgs) do if v ~= '' then args[k] = v end end -- Define the variables to pass to..."
17629
Scribunto
text/plain
-- This module implements {{su}}.
local p = {}
function p.main(frame)
-- Use arguments from the parent frame only, and remove any blank arguments.
-- We don't need to trim whitespace from any arguments, as this module only
-- uses named arguments, and whitespace is trimmed from them automatically.
local origArgs = frame:getParent().args
local args = {}
for k, v in pairs(origArgs) do
if v ~= '' then
args[k] = v
end
end
-- Define the variables to pass to luaMain.
local sup = args.p
local sub = args.b
local options = {
align = args.a,
fontSize = args.w,
lineHeight = args.lh
}
return p._main(sup, sub, options)
end
function p._main(sup, sub, options)
options = options or {}
local span = mw.html.create('span')
-- Set the styles.
span:css{
['display'] = 'inline-block',
['margin-bottom'] = '-0.3em',
['vertical-align'] = sub and '-0.4em' or '0.8em',
['line-height'] = options.lineHeight or '1.2em'
}
if options.fontSize == 'f' or options.fontSize == 'fixed' then
span:css{
['font-family'] = 'monospace,courier',
['font-size'] = '85%'
}
else
span:css('font-size', options.fontSize and options.fontSize or '85%')
end
if options.align == 'r' or options.align == 'right' then
span:css('text-align', 'right')
elseif options.align == 'c' or options.align == 'center' then
span:css('text-align', 'center')
else
span:css('text-align', 'left')
end
-- Add the wikitext.
span
:wikitext(sup)
:tag('br', {selfClosing = true}):done()
:wikitext(sub)
return tostring(span)
end
return p
d8rd8ei8giut77f36yrjslpn02jgq7d
တမ်းပလိတ်:Subatomic particle
10
3830
17630
2026-03-29T16:57:25Z
YaThaWinTha
42
Created page with "{{#invoke:Subatomic particle|main}}<noinclude> {{Documentation}} </noinclude>"
17630
wikitext
text/x-wiki
{{#invoke:Subatomic particle|main}}<noinclude>
{{Documentation}}
</noinclude>
mqae6uumxsauynkhkdisdvyebf69v0m
Module:Subatomic particle
828
3831
17631
2026-03-29T16:57:55Z
YaThaWinTha
42
Created page with "local p = {} local particles = { ["10neutron"] = { link = "Neutron", symbol = { "n", TL = "1", BL = "0" } }, ["11proton"] = { link = "Proton", symbol = { "p", TL = "1", BL = "1" } }, ["alpha"] = { link = "Alpha particle", symbol = { "α" } }, ["alpha++"] = { link = "Alpha particle", symbol = { "α", TR = "++" } }, ["antib"] = { link = "B meson", symbol = { "B", anti = "yes" } }, ["antib*"] = { link = "B meson", symbol = { "B", anti = "y..."
17631
Scribunto
text/plain
local p = {}
local particles = {
["10neutron"] = { link = "Neutron", symbol = { "n", TL = "1", BL = "0" } },
["11proton"] = { link = "Proton", symbol = { "p", TL = "1", BL = "1" } },
["alpha"] = { link = "Alpha particle", symbol = { "α" } },
["alpha++"] = { link = "Alpha particle", symbol = { "α", TR = "++" } },
["antib"] = { link = "B meson", symbol = { "B", anti = "yes" } },
["antib*"] = { link = "B meson", symbol = { "B", anti = "yes", TR = "∗" } },
["antib*0"] = { link = "B meson", symbol = { "B", anti = "yes", TR = "∗0" } },
["antib0"] = { link = "B meson", symbol = { "B", anti = "yes", TR = "0" } },
["antid"] = { link = "D meson", symbol = { "D", anti = "yes" } },
["antid*"] = { link = "D meson", symbol = { "D", anti = "yes", TR = "∗" } },
["antid*0"] = { link = "D meson", symbol = { "D", anti = "yes", TR = "∗0" } },
["antid0"] = { link = "D meson", symbol = { "D", anti = "yes", TR = "0" } },
["antideuterium"] = { link = "Antideuterium", symbol = { "D", anti = "yes" } },
["antielectron"] = { link = "Positron", symbol = { "e", TR = "+" } },
["antigluon"] = { link = "Antigluon", symbol = { "g", anti = "yes" } },
["antigluon0"] = { link = "Antigluon", symbol = { "g", anti = "yes", TR = "0" } },
["antihelium"] = { link = "Antihelium", symbol = { "He", anti = "yes" } },
["antihydrogen"] = { link = "Antihydrogen", symbol = { "H", anti = "yes" } },
["antikaon"] = { link = "Kaon", symbol = { "K", anti = "yes" } },
["antikaon*"] = { link = "Kaon", symbol = { "K", anti = "yes", TR = "∗" } },
["antikaon*0"] = { link = "Kaon", symbol = { "K", anti = "yes", TR = "∗0" } },
["antikaon0"] = { link = "Kaon", symbol = { "K", anti = "yes", TR = "0" } },
["antilepton"] = { link = "Antilepton", symbol = { "ℓ", anti = "yes" } },
["antilepton0"] = { link = "Antilepton", symbol = { "ℓ", TR = "0", anti = "yes" } },
["antimuon"] = { link = "Antimuon", symbol = { "μ", TR = "+" } },
["antineutrino"] = { link = "Antineutrino", symbol = { "ν", anti = "yes" } },
["antineutrino0"] = { link = "Antineutrino", symbol = { "ν", TR = "0", anti = "yes" } },
["antineutron"] = { link = "Antineutron", symbol = { "n", anti = "yes" } },
["antineutron0"] = { link = "Antineutron", symbol = { "n", anti = "yes", TR = "0" } },
["antinucleon"] = { link = "Antinucleon", symbol = { "N", anti = "yes" } },
["antinucleon0"] = { link = "Antinucleon", symbol = { "N", anti = "yes", TR = "0" } },
["antiphoton"] = { link = "Antiphoton", symbol = { "γ", anti = "yes" } },
["antiphoton0"] = { link = "Antiphoton", symbol = { "γ", anti = "yes", TR = "0" } },
["antiproton"] = { link = "Antiproton", symbol = { "p", anti = "yes" } },
["antiquark"] = { link = "Antiquark", symbol = { "q", anti = "yes" } },
["antislepton"] = { link = "Slepton", symbol = { "l̅͂" } },
["antisquark"] = { link = "Squark", symbol = { "q̅͂" } },
["antit"] = { link = "T meson", symbol = { "T", anti = "yes" } },
["antit*"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "∗" } },
["antit*0"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "∗0" } },
["antit0"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "0" } },
["antitau"] = { link = "Antitau", symbol = { "τ", TR = "+" } },
["antitauon"] = { link = "Antitauon", symbol = { "τ", TR = "+" } },
["antitritium"] = { link = "Antitritium", symbol = { "T", anti = "yes" } },
["axino"] = { link = "", symbol = { "A͂", TR = "0" } },
["axion"] = { link = "", symbol = { "A", TR = "0" } },
["b"] = { link = "B meson", symbol = { "B" } },
["b*"] = { link = "B meson", symbol = { "B", TR = "∗" } },
["b*+"] = { link = "B meson", symbol = { "B", TR = "∗+" } },
["b*+-"] = { link = "B meson", symbol = { "B", TR = "∗±" } },
["b*-"] = { link = "B meson", symbol = { "B", TR = "∗−" } },
["b*-+"] = { link = "B meson", symbol = { "B", TR = "∗∓" } },
["b*0"] = { link = "B meson", symbol = { "B", TR = "∗0" } },
["b+"] = { link = "B meson", symbol = { "B", TR = "+" } },
["b+-"] = { link = "B meson", symbol = { "B", TR = "±" } },
["b-"] = { link = "B meson", symbol = { "B", TR = "−" } },
["b-+"] = { link = "B meson", symbol = { "B", TR = "∓" } },
["b0"] = { link = "B meson", symbol = { "B", TR = "0" } },
["b boson"] = { link = "B boson", symbol = { "B" } },
["b boson0"] = { link = "B boson", symbol = { "B", TR = "0" } },
["beta"] = { link = "Beta particle", symbol = { "β" } },
["beta+"] = { link = "Beta particle", symbol = { "β", TR = "+" } },
["beta+-"] = { link = "Beta particle", symbol = { "β", TR = "±" } },
["beta-"] = { link = "Beta particle", symbol = { "β", TR = "−" } },
["beta-+"] = { link = "Beta particle", symbol = { "β", TR = "∓" } },
["bino"] = { link = "Bino (particle)", symbol = { "b͂" } },
["blue antiquark"] = { link = "Color charge", symbol = { "q", anti = "yes", BR = "B" } },
["blue antisquark"] = { link = "Color charge", symbol = { "q̅͂", BR = "B" } },
["blue quark"] = { link = "Color charge", symbol = { "q", BR = "B" } },
["blue squark"] = { link = "Color charge", symbol = { "q͂", BR = "B" } },
["bottom antiquark"] = { link = "Bottom antiquark", symbol = { "b", anti = "yes" } },
["bottom antisquark"] = { link = "Squark", symbol = { "b̅͂" } },
["bottom antit"] = { link = "Bottom T meson", symbol = { "T", anti = "yes", TR = "b" } },
["bottom double top omega"] = { link = "Bottom double top omega baryon", symbol = { "Ω", BR = "btt" } },
["bottom double top omega*"] = { link = "Bottom double top omega baryon", symbol = { "Ω", TR = "∗", BR = "btt" } },
["bottom double top omega*+"] = { link = "Bottom double top omega baryon", symbol = { "Ω", TR = "∗+", BR = "btt" } },
["bottom double top omega+"] = { link = "Bottom double top omega baryon", symbol = { "Ω", TR = "+", BR = "btt" } },
["bottom eta"] = { link = "Bottom eta meson", symbol = { "η", BR = "b" } },
["bottom eta0"] = { link = "Bottom eta meson", symbol = { "η", TR = "0", BR = "b" } },
["bottom eta prime"] = { link = "Bottom eta prime meson", symbol = { "η′", BR = "b" } },
["bottom eta prime0"] = { link = "Bottom eta prime meson", symbol = { "η′", TR = "0", BR = "b" } },
["bottom lambda"] = { link = "Bottom lambda baryon", symbol = { "Λ", BR = "b" } },
["bottom lambda*"] = { link = "Bottom lambda baryon", symbol = { "Λ", TR = "∗", BR = "b" } },
["bottom lambda*0"] = { link = "Bottom lambda baryon", symbol = { "Λ", TR = "∗0", BR = "b" } },
["bottom lambda0"] = { link = "Bottom lambda baryon", symbol = { "Λ", TR = "0", BR = "b" } },
["bottom omega"] = { link = "Bottom omega baryon", symbol = { "Ω", BR = "b" } },
["bottom omega*"] = { link = "Bottom omega baryon", symbol = { "Ω", TR = "∗", BR = "b" } },
["bottom omega*-"] = { link = "Bottom omega baryon", symbol = { "Ω", TR = "∗−", BR = "b" } },
["bottom omega-"] = { link = "Bottom omega baryon", symbol = { "Ω", TR = "−", BR = "b" } },
["bottom quark"] = { link = "Bottom quark", symbol = { "b" } },
["bottom sigma"] = { link = "Bottom sigma baryon", symbol = { "Σ", BR = "b" } },
["bottom sigma*"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∗", BR = "b" } },
["bottom sigma*+"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∗+", BR = "b" } },
["bottom sigma*+-"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∗±", BR = "b" } },
["bottom sigma*-"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∗−", BR = "b" } },
["bottom sigma*-+"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∓", BR = "b" } },
["bottom sigma*0"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∗0", BR = "b" } },
["bottom sigma+"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "+", BR = "b" } },
["bottom sigma+-"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "±", BR = "b" } },
["bottom sigma-"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "−", BR = "b" } },
["bottom sigma-+"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "∓", BR = "b" } },
["bottom sigma0"] = { link = "Bottom sigma baryon", symbol = { "Σ", TR = "0", BR = "b" } },
["bottom squark"] = { link = "Squark", symbol = { "b͂" } },
["bottom t"] = { link = "Bottom T meson", symbol = { "T", TR = "b" } },
["bottom t*"] = { link = "Bottom T meson", symbol = { "T", TR = "∗", BR = "b" } },
["bottom t*+"] = { link = "Bottom T meson", symbol = { "T", TR = "∗+", BR = "b" } },
["bottom t*+-"] = { link = "Bottom T meson", symbol = { "T", TR = "∗±", BR = "b" } },
["bottom t*-"] = { link = "Bottom T meson", symbol = { "T", TR = "∗−", BR = "b" } },
["bottom t*-+"] = { link = "Bottom T meson", symbol = { "T", TR = "∗∓", BR = "b" } },
["bottom t+"] = { link = "Bottom T meson", symbol = { "T", TR = "+", BR = "b" } },
["bottom t+-"] = { link = "Bottom T meson", symbol = { "T", TR = "±", BR = "b" } },
["bottom t-"] = { link = "Bottom T meson", symbol = { "T", TR = "−", BR = "b" } },
["bottom top omega"] = { link = "Bottom top omega baryon", symbol = { "Ω", BR = "bt" } },
["bottom top omega'"] = { link = "", symbol = { "Ω′", BR = "bt" } },
["bottom top omega'0"] = { link = "", symbol = { "Ω′", TR = "0", BR = "bt" } },
["bottom top omega*"] = { link = "Bottom top omega baryon", symbol = { "Ω", TR = "∗", BR = "bt" } },
["bottom top omega*0"] = { link = "Charmed top omega baryon", symbol = { "Ω", TR = "∗0", BR = "bt" } },
["bottom top omega0"] = { link = "Charmed top omega baryon", symbol = { "Ω", TR = "0", BR = "bt" } },
["bottom top xi"] = { link = "Bottom top xi baryon", symbol = { "Ξ", BR = "bt" } },
["bottom top xi'"] = { link = "", symbol = { "Ξ′", BR = "bt" } },
["bottom top xi'+"] = { link = "", symbol = { "Ξ′", TR = "+", BR = "bt" } },
["bottom top xi'0"] = { link = "", symbol = { "Ξ′", TR = "0", BR="bt" } },
["bottom top xi*"] = { link = "Bottom top xi baryon", symbol = { "Ξ", TR = "∗", BR = "bt" } },
["bottom top xi*+"] = { link = "Bottom top xi baryon", symbol = { "Ξ", TR = "∗+", BR = "bt" } },
["bottom top xi*0"] = { link = "Bottom top xi baryon", symbol = { "Ξ", TR = "∗0", BR = "bt" } },
["bottom top xi+"] = { link = "Bottom top xi baryon", symbol = { "Ξ", TR = "+", BR = "bt" } },
["bottom top xi0"] = { link = "Bottom top xi baryon", symbol = { "Ξ", TR = "0", BR = "bt" } },
["bottom xi"] = { link = "Bottom xi baryon", symbol = { "Ξ", BR = "b" } },
["bottom xi'"] = { link = "Bottom xi baryon", symbol = { "Ξ′", BR = "b" } },
["bottom xi'-"] = { link = "Bottom xi baryon", symbol = { "Ξ′", TR = "−", BR = "b" } },
["bottom xi'0"] = { link = "Bottom xi baryon", symbol = { "Ξ′", TR = "0", BR = "b" } },
["bottom xi*"] = { link = "Bottom xi baryon", symbol = { "Ξ", TR = "∗", BR = "b" } },
["bottom xi*-"] = { link = "Bottom xi baryon", symbol = { "Ξ", TR = "∗−", BR = "b" } },
["bottom xi*0"] = { link = "Bottom xi baryon", symbol = { "Ξ", TR = "∗0", BR = "b" } },
["bottom xi-"] = { link = "Bottom xi baryon", symbol = { "Ξ", TR = "−", BR = "b" } },
["bottom xi0"] = { link = "Bottom xi baryon", symbol = { "Ξ", TR = "0", BR = "b" } },
["cascade b"] = { link = "Charmed xi baryon", symbol = { "Ξ", BR = "b" } },
["chargino+"] = { link = "Chargino", symbol = { "C͂", TR = "+" } },
["chargino+-"] = { link = "Chargino", symbol = { "C͂", TR = "±" } },
["chargino-"] = { link = "Chargino", symbol = { "C͂", TR = "−" } },
["chargino-+"] = { link = "Chargino", symbol = { "C͂", TR = "∓" } },
["chargino 1+"] = { link = "Chargino", symbol = { "C͂", TR = "+", BR = "1" } },
["chargino 1+-"] = { link = "Chargino", symbol = { "C͂", TR = "±", BR = "1" } },
["chargino 1-"] = { link = "Chargino", symbol = { "C͂", TR = "−", BR = "1" } },
["chargino 1-+"] = { link = "Chargino", symbol = { "C͂", TR = "∓", BR = "1" } },
["chargino 2+"] = { link = "Chargino", symbol = { "C͂", TR = "+", BR = "2" } },
["chargino 2+-"] = { link = "Chargino", symbol = { "C͂", TR = "±", BR = "2" } },
["chargino 2-"] = { link = "Chargino", symbol = { "C͂", TR = "−", BR = "2" } },
["chargino 2-+"] = { link = "Chargino", symbol = { "C͂", TR = "∓", BR = "2" } },
["chargino i+"] = { link = "Chargino", symbol = { "C͂", TR = "+", BR = "i" } },
["chargino i+-"] = { link = "Chargino", symbol = { "C͂", TR = "±", BR = "i" } },
["chargino i-"] = { link = "Chargino", symbol = { "C͂", TR = "−", BR = "i" } },
["chargino i-+"] = { link = "Chargino", symbol = { "C͂", TR = "∓", BR = "i" } },
["charm antiquark"] = { link = "Charm antiquark", symbol = { "c", anti = "yes" } },
["charm antisquark"] = { link = "Squark", symbol = { "c̅͂" } },
["charm quark"] = { link = "Charm quark", symbol = { "c" } },
["charm squark"] = { link = "Squark", symbol = { "c͂" } },
["charmed antib"] = { link = "Charmed B meson", symbol = { "B", anti = "yes", BR = "c" } },
["charmed antib*"] = { link = "Charmed B meson", symbol = { "B", anti = "yes", TR = "∗", BR = "c" } },
["charmed antit"] = { link = "Charmed T meson", symbol = { "T", anti = "yes", BR = "c" } },
["charmed antit*"] = { link = "", symbol = { "T", anti = "yes", TR = "∗", BR = "c" } },
["charmed antit0"] = { link = "Charmed T meson", symbol = { "T", anti = "yes", TR = "0", BR = "c" } },
["charmed antit0*"] = { link = "Charmed T meson", symbol = { "T", anti = "yes", TR = "∗0", BR = "c" } },
["charmed b"] = { link = "Charmed B meson", symbol = { "B", BR = "c" } },
["charmed b*"] = { link = "Charmed B meson", symbol = { "B", TR = "∗", BR = "c" } },
["charmed b*+"] = { link = "Charmed B meson", symbol = { "B", TR = "∗+", BR = "c" } },
["charmed b*+-"] = { link = "Charmed B meson", symbol = { "B", TR = "∗±", BR = "c" } },
["charmed b*-"] = { link = "Charmed B meson", symbol = { "B", TR = "∗−", BR = "c" } },
["charmed b*-+"] = { link = "Charmed B meson", symbol = { "B", TR = "∗∓", BR = "c" } },
["charmed b+"] = { link = "Charmed B meson", symbol = { "B", TR = "+", BR = "c" } },
["charmed b+-"] = { link = "Charmed B meson", symbol = { "B", TR = "±", BR = "c" } },
["charmed b-"] = { link = "Charmed B meson", symbol = { "B", TR = "−", BR = "c" } },
["charmed b-+"] = { link = "Charmed B meson", symbol = { "B", TR = "∓", BR = "c" } },
["charmed bottom omega"] = { link = "Charmed bottom omega baryon", symbol = { "Ω", BR = "cb" } },
["charmed bottom omega'"] = { link = "Charmed bottom omega baryon", symbol = { "Ω′", BR = "cb" } },
["charmed bottom omega'0"] = { link = "Charmed bottom omega baryon", symbol = { "Ω′", TR = "0", BR = "cb" } },
["charmed bottom omega*"] = { link = "Charmed bottom omega baryon", symbol = { "Ω", TR = "∗", BR = "cb" } },
["charmed bottom omega*0"] = { link = "Charmed bottom omega baryon", symbol = { "Ω", TR = "∗0", BR = "cb" } },
["charmed bottom omega0"] = { link = "Charmed bottom omega baryon", symbol = { "Ω", TR = "0", BR = "cb" } },
["charmed bottom top omega"] = { link = "Charmed bottom top omega baryon", symbol = { "Ω", BR = "cbt" } },
["charmed bottom top omega*"] = { link = "Charmed bottom top omega baryon", symbol = { "Ω", TR = "∗", BR = "cbt" } },
["charmed bottom top omega*+"] = { link = "Charmed bottom top omega baryon", symbol = { "Ω", TR = "∗+", BR = "cbt" } },
["charmed bottom top omega+"] = { link = "Charmed bottom top omega baryon", symbol = { "Ω", TR = "+", BR = "cbt" } },
["charmed bottom xi"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", BR = "cc" } },
["charmed bottom xi'"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ′", BR = "cc" } },
["charmed bottom xi'+"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ′", TR = "+", BR = "cb" } },
["charmed bottom xi'0"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ′", TR = "0", BR = "cb" } },
["charmed bottom xi*"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", TR = "∗", BR = "cc" } },
["charmed bottom xi*+"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", TR = "∗+", BR = "cb" } },
["charmed bottom xi*0"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", TR = "∗0", BR = "cb" } },
["charmed bottom xi+"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", TR = "+", BR = "cb" } },
["charmed bottom xi0"] = { link = "Charmed bottom xi baryon", symbol = { "Ξ", TR = "0", BR = "cb" } },
["charmed double bottom omega"] = { link = "Charmed double bottom omega baryon", symbol = { "Ω", BR = "cbb" } },
["charmed double bottom omega*"] = { link = "Charmed double bottom omega baryon", symbol = { "Ω", TR = "∗", BR = "cbb" } },
["charmed double bottom omega*0"] = { link = "Charmed double bottom omega baryon", symbol = { "Ω", TR = "∗0", BR = "cbb" } },
["charmed double bottom omega0"] = { link = "Charmed double bottom omega baryon", symbol = { "Ω", TR = "0", BR = "cbb" } },
["charmed double top omega"] = { link = "Charmed double top omega baryon", symbol = { "Ω", BR = "ctt" } },
["charmed double top omega*"] = { link = "Charmed double top omega baryon", symbol = { "Ω", TR = "∗", BR = "ctt" } },
["charmed double top omega*++"] = { link = "Charmed double top omega baryon", symbol = { "Ω", TR = "∗++", BR = "ctt" } },
["charmed double top omega++"] = { link = "Charmed double top omega baryon", symbol = { "Ω", TR = "++", BR = "ctt" } },
["charmed eta"] = { link = "Charmed eta meson", symbol = { "η", BR = "c" } },
["charmed eta0"] = { link = "Charmed eta meson", symbol = { "η", TR = "0", BR = "c" } },
["charmed eta prime"] = { link = "Charmed eta prime meson", symbol = { "η′", BR = "c" } },
["charmed eta prime0"] = { link = "Charmed eta prime meson", symbol = { "η′", TR = "0", BR = "c" } },
["charmed lambda"] = { link = "Charmed lambda baryon", symbol = { "Λ", BR = "c" } },
["charmed lambda*"] = { link = "Charmed lambda baryon", symbol = { "Λ", TR = "∗", BR = "c" } },
["charmed lambda*+"] = { link = "Charmed lambda baryon", symbol = { "Λ", TR = "∗+", BR = "c" } },
["charmed lambda+"] = { link = "Charmed lambda baryon", symbol = { "Λ", TR = "+", BR = "c" } },
["charmed omega"] = { link = "Charmed omega baryon", symbol = { "Ω", BR = "c" } },
["charmed omega*"] = { link = "Charmed omega baryon", symbol = { "Ω", TR = "∗", BR = "c" } },
["charmed omega*0"] = { link = "Charmed omega baryon", symbol = { "Ω", TR = "∗0", BR = "c" } },
["charmed omega0"] = { link = "Charmed omega baryon", symbol = { "Ω", TR = "0", BR = "c" } },
["charmed sigma"] = { link = "Charmed sigma baryon", symbol = { "Σ", BR = "c" } },
["charmed sigma*"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "∗", BR = "c" } },
["charmed sigma*+"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "∗+", BR = "c" } },
["charmed sigma*++"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "∗++", BR = "c" } },
["charmed sigma*0"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "∗0", BR = "c" } },
["charmed sigma+"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "+", BR = "c" } },
["charmed sigma++"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "++", BR = "c" } },
["charmed sigma0"] = { link = "Charmed sigma baryon", symbol = { "Σ", TR = "0", BR = "c" } },
["charmed t"] = { link = "Charmed T meson", symbol = { "T", BR = "c" } },
["charmed t*"] = { link = "Charmed T meson", symbol = { "T", TR = "∗", BR = "c" } },
["charmed t*0"] = { link = "Charmed T meson", symbol = { "T", TR = "∗0", BR = "c" } },
["charmed t0"] = { link = "Charmed T meson", symbol = { "T", TR = "0", BR = "c" } },
["charmed theta0"] = { link = "Pentaquark", symbol = { "Θ", TR = "0", BR = "c" } },
["charmed top omega"] = { link = "Charmed top omega baryon", symbol = { "Ω", BR = "ct" } },
["charmed top omega'"] = { link = "", symbol = { "Ω′", BR = "ct" } },
["charmed top omega'+"] = { link = "", symbol = { "Ω′", TR = "+", BR = "ct" } },
["charmed top omega*"] = { link = "Charmed top omega baryon", symbol = { "Ω", TR = "∗", BR = "ct" } },
["charmed top omega*+"] = { link = "Charmed top omega baryon", symbol = { "Ω", TR = "∗+", BR = "ct" } },
["charmed top omega+"] = { link = "Charmed top omega baryon", symbol = { "Ω", TR = "+", BR = "ct" } },
["charmed top xi"] = { link = "Charmed top xi baryon", symbol = { "Ξ", BR = "ct" } },
["charmed top xi'"] = { link = "", symbol = { "Ξ′", BR = "ct" } },
["charmed top xi'+"] = { link = "", symbol = { "Ξ′", TR = "+", BR = "ct" } },
["charmed top xi'++"] = { link = "", symbol = { "Ξ′", TR = "++", BR = "ct" } },
["charmed top xi*"] = { link = "Charmed top xi baryon", symbol = { "Ξ", TR = "∗", BR = "ct" } },
["charmed top xi*+"] = { link = "Charmed top xi baryon", symbol = { "Ξ", TR = "∗+", BR = "ct" } },
["charmed top xi*++"] = { link = "Charmed top xi baryon", symbol = { "Ξ", TR = "∗++", BR = "ct" } },
["charmed top xi+"] = { link = "Charmed top xi baryon", symbol = { "Ξ", TR = "+", BR = "ct" } },
["charmed top xi++"] = { link = "Charmed top xi baryon", symbol = { "Ξ", TR = "++", BR = "ct" } },
["charmed xi"] = { link = "Charmed xi baryon", symbol = { "Ξ", BR = "c" } },
["charmed xi'"] = { link = "Charmed xi baryon", symbol = { "Ξ′", BR = "c" } },
["charmed xi'+"] = { link = "Charmed xi baryon", symbol = { "Ξ′", TR = "+", BR = "c" } },
["charmed xi'0"] = { link = "Charmed xi baryon", symbol = { "Ξ′", TR = "0", BR = "c" } },
["charmed xi*"] = { link = "Charmed xi baryon", symbol = { "Ξ", TR = "∗", BR = "c" } },
["charmed xi*+"] = { link = "Charmed xi baryon", symbol = { "Ξ", TR = "∗+", BR = "c" } },
["charmed xi*0"] = { link = "Charmed xi baryon", symbol = { "Ξ", TR = "∗0", BR = "c" } },
["charmed xi+"] = { link = "Charmed xi baryon", symbol = { "Ξ", TR = "+", BR = "c" } },
["charmed xi0"] = { link = "Charmed xi baryon", symbol = { "Ξ", TR = "0", BR = "c" } },
["d"] = { link = "D meson", symbol = { "D" } },
["d*"] = { link = "D meson", symbol = { "D", TR = "∗" } },
["d*+"] = { link = "D meson", symbol = { "D", TR = "∗+" } },
["d*+-"] = { link = "D meson", symbol = { "D", TR = "∗±" } },
["d*-"] = { link = "D meson", symbol = { "D", TR = "∗−" } },
["d*-+"] = { link = "D meson", symbol = { "D", TR = "∗∓" } },
["d*0"] = { link = "D meson", symbol = { "D", TR = "∗0" } },
["d+"] = { link = "D meson", symbol = { "D", TR = "+" } },
["d+-"] = { link = "D meson", symbol = { "D", TR = "±" } },
["d-"] = { link = "D meson", symbol = { "D", TR = "−" } },
["d-+"] = { link = "D meson", symbol = { "D", TR = "∓" } },
["d0"] = { link = "D meson", symbol = { "D", TR = "0" } },
["delta"] = { link = "Delta baryon", symbol = { "Δ" } },
["delta+"] = { link = "Delta baryon", symbol = { "Δ", TR = "+" } },
["delta++"] = { link = "Delta baryon", symbol = { "Δ", TR = "++" } },
["delta+-"] = { link = "Delta baryon", symbol = { "Δ", TR = "±" } },
["delta-"] = { link = "Delta baryon", symbol = { "Δ", TR = "−" } },
["delta-+"] = { link = "Delta baryon", symbol = { "Δ", TR = "∓" } },
["delta0"] = { link = "Delta baryon", symbol = { "Δ", TR = "0" } },
["deuterium"] = { link = "", symbol = { "D" } },
["double bottom omega"] = { link = "Double bottom omega baryon", symbol = { "Ω", BR = "bb" } },
["double bottom omega*"] = { link = "Double bottom omega baryon", symbol = { "Ω", TR = "∗", BR = "bb" } },
["double bottom omega*-"] = { link = "Double bottom omega baryon", symbol = { "Ω", TR = "∗−", BR = "bb" } },
["double bottom omega-"] = { link = "Double bottom omega baryon", symbol = { "Ω", TR = "−", BR = "bb" } },
["double bottom top omega"] = { link = "Double bottom top omega baryon", symbol = { "Ω", BR = "bbt" } },
["double bottom top omega*"] = { link = "Double bottom top omega baryon", symbol = { "Ω", TR = "∗", BR = "bbt" } },
["double bottom top omega*0"] = { link = "Double bottom top omega baryon", symbol = { "Ω", TR = "∗0", BR = "bbt" } },
["double bottom top omega0"] = { link = "Double bottom top omega baryon", symbol = { "Ω", TR = "0", BR = "bbt" } },
["double bottom xi"] = { link = "Double bottom xi baryon", symbol = { "Ξ", BR = "bb" } },
["double bottom xi*"] = { link = "Double bottom xi baryon", symbol = { "Ξ", TR = "∗", BR = "bb" } },
["double bottom xi*-"] = { link = "Double bottom xi baryon", symbol = { "Ξ", TR = "∗−", BR = "bb" } },
["double bottom xi*0"] = { link = "Double bottom xi baryon", symbol = { "Ξ", TR = "∗0", BR = "bb" } },
["double bottom xi-"] = { link = "Double bottom xi baryon", symbol = { "Ξ", TR = "−", BR = "bb" } },
["double bottom xi0"] = { link = "Double bottom xi baryon", symbol = { "Ξ", TR = "0", BR = "bb" } },
["double charmed bottom omega"] = { link = "Double charmed bottom omega baryon", symbol = { "Ω", BR = "ccb" } },
["double charmed bottom omega*"] = { link = "Double charmed bottom omega baryon", symbol = { "Ω", TR = "∗", BR = "ccb" } },
["double charmed bottom omega*+"] = { link = "Double charmed bottom omega baryon", symbol = { "Ω", TR = "∗+", BR = "ccb" } },
["double charmed bottom omega+"] = { link = "Double charmed bottom omega baryon", symbol = { "Ω", TR = "+", BR = "ccb" } },
["double charmed omega"] = { link = "Double charmed omega baryon", symbol = { "Ω", BR = "cc" } },
["double charmed omega*"] = { link = "Double charmed omega baryon", symbol = { "Ω", TR = "∗", BR = "cc" } },
["double charmed omega*+"] = { link = "Double charmed omega baryon", symbol = { "Ω", TR = "∗+", BR = "cc" } },
["double charmed omega+"] = { link = "Double charmed omega baryon", symbol = { "Ω", TR = "+", BR = "cc" } },
["double charmed top omega"] = { link = "Double charmed top omega baryon", symbol = { "Ω", BR = "cct" } },
["double charmed top omega*"] = { link = "Double charmed top omega baryon", symbol = { "Ω", TR = "∗", BR = "cct" } },
["double charmed top omega*++"] = { link = "Double charmed top omega baryon", symbol = { "Ω", TR = "∗++", BR = "cct" } },
["double charmed top omega++"] = { link = "Double charmed top omega baryon", symbol = { "Ω", TR = "++", BR = "cct" } },
["double charmed xi"] = { link = "Double charmed xi baryon", symbol = { "Ξ", BR = "cc" } },
["double charmed xi*"] = { link = "Double charmed xi baryon", symbol = { "Ξ", TR = "∗", BR = "cc" } },
["double charmed xi*+"] = { link = "Double charmed xi baryon", symbol = { "Ξ", TR = "∗+", BR = "cc" } },
["double charmed xi*++"] = { link = "Double charmed xi baryon", symbol = { "Ξ", TR = "∗++", BR = "cc" } },
["double charmed xi+"] = { link = "Double charmed xi baryon", symbol = { "Ξ", TR = "+", BR = "cc" } },
["double charmed xi++"] = { link = "Double charmed xi baryon", symbol = { "Ξ", TR = "++", BR = "cc" } },
["double top omega"] = { link = "Double top omega baryon", symbol = { "Ω", BR = "tt" } },
["double top omega*"] = { link = "Double top omega baryon", symbol = { "Ω", TR = "∗", BR = "tt" } },
["double top omega*+"] = { link = "Double top omega baryon", symbol = { "Ω", TR = "∗+", BR = "tt" } },
["double top omega+"] = { link = "Double top omega baryon", symbol = { "Ω", TR = "+", BR = "tt" } },
["double top xi"] = { link = "Double top xi baryon", symbol = { "Ξ", BR = "tt" } },
["double top xi*"] = { link = "Double top xi baryon", symbol = { "Ξ", TR = "∗", BR = "tt" } },
["double top xi*+"] = { link = "Double top xi baryon", symbol = { "Ξ", TR = "∗+", BR = "tt" } },
["double top xi*++"] = { link = "Double top xi baryon", symbol = { "Ξ", TR = "∗++", BR = "tt" } },
["double top xi+"] = { link = "Double top xi baryon", symbol = { "Ξ", TR = "+", BR = "tt" } },
["double top xi++"] = { link = "Double top xi baryon", symbol = { "Ξ", TR = "++", BR = "tt" } },
["down antiquark"] = { link = "Down antiquark", symbol = { "d", anti = "yes" } },
["down antisquark"] = { link = "Squark", symbol = { "d̅͂" } },
["down quark"] = { link = "Down quark", symbol = { "d" } },
["down squark"] = { link = "Squark", symbol = { "d͂" } },
["electron"] = { link = "Electron", symbol = { "e", TR = "−" } },
["electron+"] = { link = "Positron", symbol = { "e", TR = "+" } },
["electron+-"] = { link = "", symbol = { "e", TR = "±" } },
["electron-"] = { link = "Electron", symbol = { "e", TR = "−" } },
["electron-+"] = { link = "Electron", symbol = { "e", TR = "∓" } },
["electron antineutrino"] = { link = "Electron antineutrino", symbol = { "ν", anti = "yes", BR = "e" } },
["electron antineutrino0"] = { link = "Electron antineutrino", symbol = { "ν", anti = "yes", TR = "0", BR = "e" } },
["electron neutrino"] = { link = "Electron neutrino", symbol = { "ν", BR = "e" } },
["electron neutrino0"] = { link = "Electron neutrino", symbol = { "ν", TR = "0", BR = "e" } },
["eta"] = { link = "Eta meson", symbol = { "η" } },
["eta0"] = { link = "Eta meson", symbol = { "η", TR = "0" } },
["eta prime"] = { link = "Eta prime meson", symbol = { "η′" } },
["eta prime0"] = { link = "Eta prime meson", symbol = { "η′", TR = "0" } },
["gamma"] = { link = "Gamma ray", symbol = { "γ" } },
["gluino"] = { link = "Gluino", symbol = { "g͂" } },
["gluon"] = { link = "Gluon", symbol = { "g" } },
["gluon0"] = { link = "Gluon", symbol = { "g", TR = "0" } },
["gravitino"] = { link = "Gravitino", symbol = { "G͂" } },
["graviton"] = { link = "", symbol = { "G" } },
["green antiquark"] = { link = "Color charge", symbol = { "q", anti = "yes", BR = "G" } },
["green antisquark"] = { link = "Color charge", symbol = { "q̅͂", BR = "G" } },
["green quark"] = { link = "Color charge", symbol = { "q", BR = "G" } },
["green squark"] = { link = "Color charge", symbol = { "q͂", BR = "G" } },
["helium"] = { link = "", symbol = { "He" } },
["higgs boson"] = { link = "Higgs boson", symbol = { "H", TR = "0" } },
["higgsino"] = { link = "Higgsino", symbol = { "H͂" } },
["hydrogen"] = { link = "", symbol = { "H" } },
["j/psi"] = { link = "J/psi meson", symbol = { "J/ψ" } },
["j/psi0"] = { link = "J/psi meson", symbol = { "J/ψ", TR = "0" } },
["k-long"] = { link = "Kaon", symbol = { "K", BR = "L" } },
["k-long*"] = { link = "Kaon", symbol = { "K", TR = "∗", BR = "L" } },
["k-long*0"] = { link = "Kaon", symbol = { "K", TR = "∗0", BR = "L" } },
["k-long0"] = { link = "Kaon", symbol = { "K", TR = "0", BR = "L" } },
["k-short"] = { link = "Kaon", symbol = { "K", BR = "S" } },
["k-short*"] = { link = "Kaon", symbol = { "K", TR = "∗", BR = "S" } },
["k-short*0"] = { link = "Kaon", symbol = { "K", TR = "∗0", BR = "S" } },
["k-short0"] = { link = "Kaon", symbol = { "K", TR = "0", BR = "S" } },
["kaon"] = { link = "Kaon", symbol = { "K" } },
["kaon*"] = { link = "Kaon", symbol = { "K", TR = "∗" } },
["kaon*+"] = { link = "Kaon", symbol = { "K", TR = "∗+" } },
["kaon*+-"] = { link = "Kaon", symbol = { "K", TR = "∗±" } },
["kaon*-"] = { link = "Kaon", symbol = { "K", TR = "∗−" } },
["kaon*-+"] = { link = "Kaon", symbol = { "K", TR = "∗∓" } },
["kaon*0"] = { link = "Kaon", symbol = { "K", TR = "∗0" } },
["kaon+"] = { link = "Kaon", symbol = { "K", TR = "+" } },
["kaon+-"] = { link = "Kaon", symbol = { "K", TR = "±" } },
["kaon-"] = { link = "Kaon", symbol = { "K", TR = "−" } },
["kaon-+"] = { link = "Kaon", symbol = { "K", TR = "∓" } },
["kaon0"] = { link = "Kaon", symbol = { "K", TR = "0" } },
["lambda"] = { link = "Lambda baryon", symbol = { "Λ" } },
["lambda*"] = { link = "Lambda baryon", symbol = { "Λ", TR = "∗" } },
["lambda*0"] = { link = "Lambda baryon", symbol = { "Λ", TR = "∗0" } },
["lambda0"] = { link = "Lambda baryon", symbol = { "Λ", TR = "0" } },
["lepton"] = { link = "Lepton", symbol = { "ℓ" } },
["lepton+"] = { link = "Antilepton", symbol = { "ℓ", TR = "+" } },
["lepton+-"] = { link = "Lepton", symbol = { "ℓ", TR = "±" } },
["lepton-"] = { link = "Lepton", symbol = { "ℓ", TR = "−" } },
["lepton-+"] = { link = "Lepton", symbol = { "ℓ", TR = "∓" } },
["lepton0"] = { link = "Neutrino", symbol = { "ℓ", TR = "0" } },
["lepton antineutrino"] = { link = "Antineutrino", symbol = { "ν", anti = "yes", BR = "l" } },
["lepton antineutrino0"] = { link = "Antineutrino", symbol = { "ν", anti = "yes", TR = "0", BR = "l" } },
["lepton neutrino"] = { link = "Neutrino", symbol = { "ν", BR = "l" } },
["lepton neutrino0"] = { link = "Neutrino", symbol = { "ν", TR = "0", BR = "l" } },
["majorino"] = { link = "", symbol = { "J͂" } },
["majoron"] = { link = "Majoron", symbol = { "J" } },
["muon"] = { link = "Muon", symbol = { "μ", TR = "−" } },
["muon+"] = { link = "Antimuon", symbol = { "μ", TR = "+" } },
["muon+-"] = { link = "Muon", symbol = { "μ", TR = "±" } },
["muon-"] = { link = "Muon", symbol = { "μ", TR = "−" } },
["muon-+"] = { link = "Muon", symbol = { "μ", TR = "∓" } },
["muon antineutrino"] = { link = "Muon antineutrino", symbol = { "ν", anti = "yes", BR = "μ" } },
["muon antineutrino0"] = { link = "Muon antineutrino", symbol = { "ν", anti = "yes", TR = "0", BR = "μ" } },
["muon neutrino"] = { link = "Muon neutrino", symbol = { "ν", BR = "μ" } },
["muon neutrino0"] = { link = "Muon neutrino", symbol = { "ν", TR = "0", BR = "μ" } },
["neutralino"] = { link = "Neutralino", symbol = { "N͂", TR = "0" } },
["neutralino 1"] = { link = "Neutralino", symbol = { "N͂", TR = "0", BR = "1" } },
["neutralino 2"] = { link = "Neutralino", symbol = { "N͂", TR = "0", BR = "2" } },
["neutralino 3"] = { link = "Neutralino", symbol = { "N͂", TR = "0", BR = "3" } },
["neutralino 4"] = { link = "Neutralino", symbol = { "N͂", TR = "0", BR = "4" } },
["neutralino i"] = { link = "Neutralino", symbol = { "N͂", TR = "0", BR = "i" } },
["neutrino"] = { link = "Neutrino", symbol = { "ν" } },
["neutrino0"] = { link = "Neutrino", symbol = { "ν", TR = "0" } },
["neutron"] = { link = "Neutron", symbol = { "n" } },
["neutron0"] = { link = "Neutron", symbol = { "n", TR = "0" } },
["nucleon"] = { link = "Nucleon", symbol = { "N" } },
["nucleon+"] = { link = "Proton", symbol = { "N", TR = "+" } },
["nucleon-"] = { link = "Antiproton", symbol = { "N", TR = "-" } },
["nucleon0"] = { link = "Neutron", symbol = { "N", TR = "0" } },
["omega"] = { link = "Omega baryon", symbol = { "Ω" } },
["omega-"] = { link = "Omega baryon", symbol = { "Ω", TR = "−" } },
["omega meson"] = { link = "Omega meson", symbol = { "ω" } },
["omega meson0"] = { link = "Omega meson", symbol = { "ω", TR = "0" } },
["ortho-positronium"] = { link = "Positronium", symbol = { "S", TL = "3", BR = "0" } },
["para-positronium"] = { link = "Positronium", symbol = { "S", TL = "1", BR = "0" } },
["phi--"] = { link = "Pentaquark", symbol = { "Φ", TR = "−−" } },
["phi0"] = { link = "Pentaquark", symbol = { "Φ", TR = "0" } },
["phi meson"] = { link = "Phi meson", symbol = { "ϕ" } },
["phi meson0"] = { link = "Phi meson", symbol = { "ϕ", TR = "0" } },
["photino"] = { link = "Photino", symbol = { "γ͂" } },
["photon"] = { link = "Photon", symbol = { "γ" } },
["photon0"] = { link = "Photon", symbol = { "γ", TR = "0" } },
["pion"] = { link = "Pion", symbol = { "π" } },
["pion+"] = { link = "Pion", symbol = { "π", TR = "+" } },
["pion+-"] = { link = "Pion", symbol = { "π", TR = "±" } },
["pion-"] = { link = "Pion", symbol = { "π", TR = "−" } },
["pion-+"] = { link = "Pion", symbol = { "π", TR = "∓" } },
["pion0"] = { link = "Pion", symbol = { "π", TR = "0" } },
["positron"] = { link = "Positron", symbol = { "e", TR = "+" } },
["proton"] = { link = "Proton", symbol = { "p" } },
["proton+"] = { link = "Proton", symbol = { "p", TR = "+" } },
["quark"] = { link = "Quark", symbol = { "q" } },
["red antiquark"] = { link = "Color charge", symbol = { "q", anti = "yes", BR = "R" } },
["red antisquark"] = { link = "Color charge", symbol = { "q̅͂", BR = "R" } },
["red quark"] = { link = "Color charge", symbol = { "q", BR = "R" } },
["red squark"] = { link = "Color charge", symbol = { "q͂", BR = "R" } },
["rho"] = { link = "Rho meson", symbol = { "ρ" } },
["rho+"] = { link = "Rho meson", symbol = { "ρ", TR = "+" } },
["rho+-"] = { link = "Rho meson", symbol = { "ρ", TR = "±" } },
["rho-"] = { link = "Rho meson", symbol = { "ρ", TR = "−" } },
["rho-+"] = { link = "Rho meson", symbol = { "ρ", TR = "∓" } },
["rho0"] = { link = "Rho meson", symbol = { "ρ", TR = "0" } },
["sea antiquark"] = { link = "Sea antiquark", symbol = { "q", anti = "yes", BR = "s" } },
["sea quark"] = { link = "Sea quark", symbol = { "q", BR = "s" } },
["selectron"] = { link = "Selectron (particle)", symbol = { "e͂", TR = "−" } },
["sigma"] = { link = "Sigma baryon", symbol = { "Σ" } },
["sigma*"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗" } },
["sigma*+"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗+" } },
["sigma*+-"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗±" } },
["sigma*-"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗−" } },
["sigma*-+"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗∓" } },
["sigma*0"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∗0" } },
["sigma+"] = { link = "Sigma baryon", symbol = { "Σ", TR = "+" } },
["sigma+-"] = { link = "Sigma baryon", symbol = { "Σ", TR = "±" } },
["sigma-"] = { link = "Sigma baryon", symbol = { "Σ", TR = "−" } },
["sigma-+"] = { link = "Sigma baryon", symbol = { "Σ", TR = "∓" } },
["sigma0"] = { link = "Sigma baryon", symbol = { "Σ", TR = "0" } },
["slepton"] = { link = "Slepton", symbol = { "l͂" } },
["squark"] = { link = "Squark", symbol = { "q͂" } },
["strange antib"] = { link = "Strange B meson", symbol = { "B", anti = "yes", BR = "s" } },
["strange antib*"] = { link = "Strange B meson", symbol = { "B", anti = "yes", TR = "∗", BR = "s" } },
["strange antib*0"] = { link = "Strange B meson", symbol = { "B", anti = "yes", TR = "∗0", BR = "s" } },
["strange antib0"] = { link = "Strange B meson", symbol = { "B", anti = "yes", TR = "0", BR = "s" } },
["strange antiquark"] = { link = "Strange antiquark", symbol = { "s", anti = "yes" } },
["strange antisquark"] = { link = "Squark", symbol = { "s̅͂" } },
["strange antit"] = { link = "Strange T meson", symbol = { "T", anti = "yes", BR = "s" } },
["strange antit*"] = { link = "Strange T meson", symbol = { "T", anti = "yes", TR = "∗±", BR = "s" } },
["strange b"] = { link = "Strange B meson", symbol = { "B", BR = "s" } },
["strange b*"] = { link = "Strange B meson", symbol = { "B", TR = "∗", BR = "s" } },
["strange b*0"] = { link = "Strange B meson", symbol = { "B", TR = "∗0", BR = "s" } },
["strange b0"] = { link = "Strange B meson", symbol = { "B", TR = "0", BR = "s" } },
["strange d"] = { link = "Strange D meson", symbol = { "D", BR = "s" } },
["strange d*"] = { link = "Strange D meson", symbol = { "D", TR = "∗", BR = "s" } },
["strange d*+"] = { link = "Strange D meson", symbol = { "D", TR = "∗+", BR = "s" } },
["strange d*+-"] = { link = "Strange D meson", symbol = { "D", TR = "∗±", BR = "s" } },
["strange d*-"] = { link = "Strange D meson", symbol = { "D", TR = "∗−", BR = "s" } },
["strange d*-+"] = { link = "Strange D meson", symbol = { "D", TR = "∗∓", BR = "s" } },
["strange d+"] = { link = "Strange D meson", symbol = { "D", TR = "+", BR = "s" } },
["strange d+-"] = { link = "Strange D meson", symbol = { "D", TR = "±", BR = "s" } },
["strange d-"] = { link = "Strange D meson", symbol = { "D", TR = "−", BR = "s" } },
["strange d-+"] = { link = "Strange D meson", symbol = { "D", TR = "∓", BR = "s" } },
["strange quark"] = { link = "Strange quark", symbol = { "s" } },
["strange squark"] = { link = "Squark", symbol = { "s͂" } },
["strange t"] = { link = "Strange T meson", symbol = { "T", BR = "s" } },
["strange t*"] = { link = "Strange T meson", symbol = { "T", TR = "∗", BR = "s" } },
["strange t*+"] = { link = "Strange T meson", symbol = { "T", TR = "∗+", BR = "s" } },
["strange t*+-"] = { link = "Strange T meson", symbol = { "T", TR = "∗±", BR = "s" } },
["strange t*-"] = { link = "Strange T meson", symbol = { "T", TR = "∗−", BR = "s" } },
["strange t*-+"] = { link = "Strange T meson", symbol = { "T", TR = "∗∓", BR = "s" } },
["strange t+"] = { link = "Strange T meson", symbol = { "T", TR = "+", BR = "s" } },
["strange t+-"] = { link = "Strange T meson", symbol = { "T", TR = "±", BR = "s" } },
["strange t-"] = { link = "Strange T meson", symbol = { "T", TR = "−", BR = "s" } },
["t"] = { link = "T meson", symbol = { "T" } },
["t*"] = { link = "T meson", symbol = { "T", TR = "∗" } },
["t*+"] = { link = "T meson", symbol = { "T", TR = "∗+" } },
["t*+-"] = { link = "T meson", symbol = { "T", TR = "∗±" } },
["t*-"] = { link = "T meson", symbol = { "T", TR = "∗−" } },
["t*-+"] = { link = "T meson", symbol = { "T", TR = "∗∓" } },
["t*0"] = { link = "T meson", symbol = { "T", TR = "∗0" } },
["t+"] = { link = "T meson", symbol = { "T", TR = "+" } },
["t+-"] = { link = "T meson", symbol = { "T", TR = "±" } },
["t-"] = { link = "T meson", symbol = { "T", TR = "−" } },
["t-+"] = { link = "T meson", symbol = { "T", TR = "∓" } },
["t0"] = { link = "T meson", symbol = { "T", TR = "0" } },
["tau"] = { link = "Tau (particle)", symbol = { "τ", TR = "−" } },
["tau+"] = { link = "Antitauon", symbol = { "τ", TR = "+" } },
["tau+-"] = { link = "Tauon", symbol = { "τ", TR = "±" } },
["tau-"] = { link = "Tauon", symbol = { "τ", TR = "−" } },
["tau-+"] = { link = "Tauon", symbol = { "τ", TR = "∓" } },
["tau antineutrino"] = { link = "Tauon antineutrino", symbol = { "ν", anti = "yes", BR = "τ" } },
["tau antineutrino0"] = { link = "Tauon antineutrino", symbol = { "ν", anti = "yes", TR = "0", BR = "τ" } },
["tau neutrino"] = { link = "Tau neutrino", symbol = { "ν", BR = "τ" } },
["tau neutrino0"] = { link = "Tauon neutrino", symbol = { "ν", TR = "0", BR = "τ" } },
["tauon"] = { link = "Tauon", symbol = { "τ", TR = "−" } },
["tauon+"] = { link = "Antitauon", symbol = { "τ", TR = "+" } },
["tauon+-"] = { link = "Tauon", symbol = { "τ", TR = "±" } },
["tauon-"] = { link = "Tauon", symbol = { "τ", TR = "−" } },
["tauon-+"] = { link = "Tauon", symbol = { "τ", TR = "∓" } },
["tauon antineutrino"] = { link = "Tauon antineutrino", symbol = { "ν", anti = "yes", BR = "τ" } },
["tauon antineutrino0"] = { link = "Tauon antineutrino", symbol = { "ν", anti = "yes", TR = "0", BR = "τ" } },
["tauon neutrino"] = { link = "Tauon neutrino", symbol = { "ν", BR = "τ" } },
["tauon neutrino0"] = { link = "Tauon neutrino", symbol = { "ν", TR = "0", BR = "τ" } },
["theta+"] = { link = "Pentaquark", symbol = { "Θ", TR = "+" } },
["theta meson"] = { link = "Theta meson", symbol = { "θ" } },
["top antiquark"] = { link = "Top antiquark", symbol = { "t", anti = "yes" } },
["top antisquark"] = { link = "Squark", symbol = { "t̅͂" } },
["top eta"] = { link = "Top eta meson", symbol = { "η", BR = "t" } },
["top eta0"] = { link = "Top eta meson", symbol = { "η", TR = "0", BR = "t" } },
["top eta prime"] = { link = "Top eta prime meson", symbol = { "η′", BR = "t" } },
["top eta prime0"] = { link = "Top eta prime meson", symbol = { "η′", TR = "0", BR = "t" } },
["top lambda"] = { link = "Top lambda baryon", symbol = { "Λ", BR = "t" } },
["top lambda*"] = { link = "Top lambda baryon", symbol = { "Λ", TR = "∗", BR = "t" } },
["top lambda*+"] = { link = "Top lambda baryon", symbol = { "Λ", TR = "∗+", BR = "t" } },
["top lambda+"] = { link = "Top lambda baryon", symbol = { "Λ", TR = "+", BR = "t" } },
["top omega"] = { link = "Top omega baryon", symbol = { "Ω", BR = "t" } },
["top omega*"] = { link = "Top omega baryon", symbol = { "Ω", TR = "∗", BR = "t" } },
["top omega*0"] = { link = "Top omega baryon", symbol = { "Ω", TR = "∗0", BR = "t" } },
["top omega0"] = { link = "Top omega baryon", symbol = { "Ω", TR = "0", BR = "t" } },
["top quark"] = { link = "Top quark", symbol = { "t" } },
["top sigma"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "++", BR = "t" } },
["top sigma*"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "∗", BR = "t" } },
["top sigma*+"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "∗+", BR = "t" } },
["top sigma*++"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "∗++", BR = "t" } },
["top sigma*0"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "∗0", BR = "t" } },
["top sigma+"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "+", BR = "t" } },
["top sigma++"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "++", BR = "t" } },
["top sigma0"] = { link = "Top sigma baryon", symbol = { "Σ", TR = "0", BR = "t" } },
["top squark"] = { link = "Squark", symbol = { "t͂" } },
["top xi"] = { link = "Top xi baryon", symbol = { "Ξ", BR = "t" } },
["top xi'"] = { link = "", symbol = { "Ξ′", BR = "t" } },
["top xi'+"] = { link = "", symbol = { "Ξ′", TR = "+", BR = "t" } },
["top xi'0"] = { link = "", symbol = { "Ξ′", TR = "0", BR = "t" } },
["top xi*"] = { link = "Top xi baryon", symbol = { "Ξ", TR = "∗", BR = "t" } },
["top xi*+"] = { link = "Top xi baryon", symbol = { "Ξ", TR = "∗+", BR = "t" } },
["top xi*0"] = { link = "Top xi baryon", symbol = { "Ξ", TR = "∗0", BR = "t" } },
["top xi+"] = { link = "Top xi baryon", symbol = { "Ξ", TR = "+", BR = "t" } },
["top xi0"] = { link = "Top xi baryon", symbol = { "Ξ", TR = "0", BR = "t" } },
["triple bottom omega"] = { link = "Triple bottom omega baryon", symbol = { "Ω", BR = "bbb" } },
["triple bottom omega-"] = { link = "Triple bottom omega baryon", symbol = { "Ω", TR = "−", BR = "bbb" } },
["triple charmed omega"] = { link = "Triple charmed omega baryon", symbol = { "Ω", BR = "ccc" } },
["triple charmed omega++"] = { link = "Triple charmed omega baryon", symbol = { "Ω", TR = "++", BR = "ccc" } },
["triple top omega"] = { link = "Triple top omega baryon", symbol = { "Ω", BR = "ttt" } },
["triple top omega++"] = { link = "Triple top omega baryon", symbol = { "Ω", TR = "++", BR = "ttt" } },
["tritium"] = { link = "", symbol = { "T" } },
["up antiquark"] = { link = "Up antiquark", symbol = { "u", anti = "yes" } },
["up antisquark"] = { link = "Squark", symbol = { "u̅͂" } },
["up quark"] = { link = "Up quark", symbol = { "u" } },
["up squark"] = { link = "Squark", symbol = { "u͂" } },
["upsilon"] = { link = "Upsilon meson", symbol = { "ϒ" } },
["upsilon0"] = { link = "Upsilon meson", symbol = { "ϒ", TR = "0" } },
["valence antiquark"] = { link = "Valence antiquark", symbol = { "q", anti = "yes", BR = "v" } },
["valence quark"] = { link = "Valence quark", symbol = { "q", BR = "v" } },
["w boson"] = { link = "W boson", symbol = { "W" } },
["w boson+"] = { link = "W boson", symbol = { "W", TR = "+" } },
["w boson+-"] = { link = "W boson", symbol = { "W", TR = "±" } },
["w boson-"] = { link = "W boson", symbol = { "W", TR = "−" } },
["w boson-+"] = { link = "W boson", symbol = { "W", TR = "∓" } },
["w boson0"] = { link = "W boson", symbol = { "W", TR = "0" } },
["wino"] = { link = "Wino (particle)", symbol = { "W͂" } },
["wino+"] = { link = "Wino (particle)", symbol = { "W͂", TR = "+" } },
["wino+-"] = { link = "Wino (particle)", symbol = { "W͂", TR = "±" } },
["wino-"] = { link = "Wino (particle)", symbol = { "W͂", TR = "−" } },
["wino-+"] = { link = "Wino (particle)", symbol = { "W͂", TR = "∓" } },
["wino0"] = { link = "Wino (particle)", symbol = { "W͂", TR = "0" } },
["x boson"] = { link = "X boson", symbol = { "X" } },
["xi"] = { link = "Xi baryon", symbol = { "Ξ" } },
["xi*"] = { link = "Xi baryon", symbol = { "Ξ", TR = "∗" } },
["xi*-"] = { link = "Xi baryon", symbol = { "Ξ", TR = "∗−" } },
["xi*0"] = { link = "Xi baryon", symbol = { "Ξ", TR = "∗0" } },
["xi-"] = { link = "Xi baryon", symbol = { "Ξ", TR = "−" } },
["xi0"] = { link = "Xi baryon", symbol = { "Ξ", TR = "0" } },
["xino"] = { link = "", symbol = { "X͂" } },
["y boson"] = { link = "Y boson", symbol = { "Y" } },
["yino"] = { link = "", symbol = { "Y͂" } },
["z boson"] = { link = "Z boson", symbol = { "Z" } },
["z boson0"] = { link = "Z boson", symbol = { "Z", TR = "0" } },
["zino"] = { link = "Zino (particle)", symbol = { "Z͂" } },
["zino0"] = { link = "Zino (particle)", symbol = { "Z͂", TR = "0" } },
}
--- Public function which is used to return a particle's symbol,
--- with or without a link to its article.
---
--- Parameters:
--- |1= — The particle's name.
--- |link= — optional; Set if the particle should link to its article.
---
--- @param frame table The frame invoking the module.
function p.main(frame)
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
if not args[1] then
return ""
end
local requested_particle = string.lower(args[1])
local particle = particles[requested_particle]
if not particle then
return ""
end
local particle_args = particle.symbol
if args.link then
particle_args.link = particle.link
end
return frame:expandTemplate{title = "Physics particle", args = particle_args}
end
return p
0rd6hmnk7y92g0w8qzagsbsccse7hjf
တမ်းပလိတ်:Subscription
10
3832
17632
2026-03-29T16:59:15Z
YaThaWinTha
42
Created page with "{{#if:{{{via|}}}| – via {{{via}}} {{link note|note={{#switch: {{{1|not-sentence}}} | s | sentence = အသင်းဝင်ဖို့ လိုအပ်ရေ။ | အသင်းဝင်ဖို့ လိုအပ်ရေ။ }}}} [[Category:Subscription required using via]]|{{link note|note={{#switch: {{{1|not-sentence}}} | s | sentence = အသင်းဝင်ဖို့ လိုအပ်ရေ။ | အသင်းဝင်ဖို့..."
17632
wikitext
text/x-wiki
{{#if:{{{via|}}}| – via {{{via}}} {{link note|note={{#switch: {{{1|not-sentence}}}
| s
| sentence = အသင်းဝင်ဖို့ လိုအပ်ရေ။
| အသင်းဝင်ဖို့ လိုအပ်ရေ။
}}}} [[Category:Subscription required using via]]|{{link note|note={{#switch: {{{1|not-sentence}}}
| s
| sentence = အသင်းဝင်ဖို့ လိုအပ်ရေ။
| အသင်းဝင်ဖို့ လိုအပ်ရေ။
}}}}
}}<includeonly>[[Category:အသင်းဝင်မှရာ ရနှိုင်ရေ အကြောင်းအရာသို့ လင့်ချိတ်ထားရေ စာမျက်နှာတိ]]</includeonly><noinclude>{{documentation}}</noinclude>
lvzkvhpy07vqhmw9245c1tmxu3nvqk5
တမ်းပလိတ်:Taxonomy/Bubalina
10
3833
17633
2026-03-29T17:00:35Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=subtribus |link=Bubalina |parent=Bovini |extinct=<!--leave blank for "not extinct"; put "yes" for "extinct" --> |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17633
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=subtribus
|link=Bubalina
|parent=Bovini
|extinct=<!--leave blank for "not extinct"; put "yes" for "extinct" -->
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
8817zfw0f84yybwblwi8q8v8zztmm97
တမ်းပလိတ်:Taxonomy/Bovini
10
3834
17634
2026-03-29T17:01:17Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=tribus |link=Bovini |parent=Bovinae |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17634
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=tribus
|link=Bovini
|parent=Bovinae
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
53rgnoztm9y90gkw66ueiyxsaeky0ll
တမ်းပလိတ်:Taxonomy/Bovinae
10
3835
17635
2026-03-29T17:01:52Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=subfamilia |link=Bovinae |parent=Bovidae |always_display=true |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17635
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=subfamilia
|link=Bovinae
|parent=Bovidae
|always_display=true
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
123zgqh7e1sf9v9ieba9cbumvyhjibf
တမ်းပလိတ်:Taxonomy/Bovidae
10
3836
17636
2026-03-29T17:02:24Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=familia |link=Bovidae |parent=Pecora }}"
17636
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=familia
|link=Bovidae
|parent=Pecora
}}
g7e2ug2bbldqxh3mkyfu179i6v7mtsx
တမ်းပလိတ်:Taxonomy/Bubalus
10
3837
17637
2026-03-29T17:02:55Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=genus |link=Bubalus |parent=Bubalina |extinct=<!--leave blank for "not extinct"; put "yes" for "extinct" --> |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17637
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=genus
|link=Bubalus
|parent=Bubalina
|extinct=<!--leave blank for "not extinct"; put "yes" for "extinct" -->
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
4o6ztqxm3nrcytkpu3bluu6hhs8qioc
တမ်းပလိတ်:Taxonomy/Pecora
10
3838
17638
2026-03-29T17:03:27Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=infraordo |link=Pecora |parent=Ruminantia |extinct= }}"
17638
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=infraordo
|link=Pecora
|parent=Ruminantia
|extinct=
}}
g6db6r4pe80wbheagw0x59il0zjzrmf
တမ်းပလိတ်:Taxonomy/Ruminantia
10
3839
17639
2026-03-29T17:04:14Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=subordo |link=စားမြုံ့ပြန်တတ်ရေ တိရစ္ဆာန်တိ|Ruminantia |parent=Ruminantiamorpha }}"
17639
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=subordo
|link=စားမြုံ့ပြန်တတ်ရေ တိရစ္ဆာန်တိ|Ruminantia
|parent=Ruminantiamorpha
}}
jsecsz0t3on1o1qlrmjsfbmifs8d30x
တမ်းပလိတ်:Taxonomy/Ruminantiamorpha
10
3840
17640
2026-03-29T17:04:54Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=Clade |link=စားမြုံ့ပြန်ကောင်|Ruminantiamorpha |parent=Cetruminantia |extinct= |refs= }}"
17640
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=Clade
|link=စားမြုံ့ပြန်ကောင်|Ruminantiamorpha
|parent=Cetruminantia
|extinct=
|refs=
}}
f70jz5l1sowo6tlxtxntjdsv2dmlvzj
တမ်းပလိတ်:Taxonomy/Cetruminantia
10
3841
17641
2026-03-29T17:05:30Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=Clade |link=Cetruminantia |parent=Artiodactyla/skip }}"
17641
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=Clade
|link=Cetruminantia
|parent=Artiodactyla/skip
}}
glz64g82h4dzb0uyql2aeavrecgj09n
တမ်းပလိတ်:Taxonomy/Artiodactyla/skip
10
3842
17642
2026-03-29T17:06:03Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |same as=Artiodactyla |parent=Placentalia }}"
17642
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|same as=Artiodactyla
|parent=Placentalia
}}
t9cddzq1nymrpsrrd38fym3rsrr9vhq
တမ်းပလိတ်:Taxonomy/Artiodactyla
10
3843
17643
2026-03-29T17:06:32Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=ordo |link=ခွာစုံပါရေ တိရစ္ဆာန်တိ|Artiodactyla |parent=Cetartiodactyla }}"
17643
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=ordo
|link=ခွာစုံပါရေ တိရစ္ဆာန်တိ|Artiodactyla
|parent=Cetartiodactyla
}}
3ynmmiwpszundloq3b3sdk1oa33alp0
တမ်းပလိတ်:Don't edit this line all
10
3844
17644
2026-03-29T17:07:05Z
YaThaWinTha
42
Created page with "<includeonly>{{{parent|}}}${{{rank|}}}${{{link|}}}${{trim|{{#ifeq:{{padleft:|1|{{{1|}}}}}|{|{{{2|}}}|{{{1|}}}}}}}${{{always_display|{{{always display|}}}}}}${{{extinct|}}}${{{same_as|{{{same as|}}}}}}${{{refs|}}}</includeonly><noinclude>{{documentation|Template:Don't edit this line/doc/variant}} [[Category:Taxobox templates]]</noinclude>"
17644
wikitext
text/x-wiki
<includeonly>{{{parent|}}}${{{rank|}}}${{{link|}}}${{trim|{{#ifeq:{{padleft:|1|{{{1|}}}}}|{|{{{2|}}}|{{{1|}}}}}}}${{{always_display|{{{always display|}}}}}}${{{extinct|}}}${{{same_as|{{{same as|}}}}}}${{{refs|}}}</includeonly><noinclude>{{documentation|Template:Don't edit this line/doc/variant}}
[[Category:Taxobox templates]]</noinclude>
5p1dozh194r8cxl0mjdzfnnl6zvif71
တမ်းပလိတ်:Taxonomy/Placentalia
10
3845
17645
2026-03-29T17:07:49Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=infraclassis |link=Placentalia |parent=Eutheria }}"
17645
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=infraclassis
|link=Placentalia
|parent=Eutheria
}}
f72q9yu54wqkqjq1m78yb7ha0h1c9rr
တမ်းပလိတ်:Taxonomy/Eutheria
10
3846
17646
2026-03-29T17:08:20Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Eutheria |parent=Theria }}"
17646
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Eutheria
|parent=Theria
}}
4z8h2w45lrlqcglzctznicpddom3z62
တမ်းပလိတ်:Taxonomy/Theria
10
3847
17647
2026-03-29T17:08:47Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=subclassis |link=Theria |parent=Tribosphenida }}"
17647
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=subclassis
|link=Theria
|parent=Tribosphenida
}}
lxbcg66xl556f8yhbxor0mofm806949
တမ်းပလိတ်:Taxonomy/Tribosphenida
10
3848
17648
2026-03-29T17:09:22Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Tribosphenida |parent=Zatheria }}"
17648
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Tribosphenida
|parent=Zatheria
}}
k3fjqqwo5di9ckt1w3hnomxvughshzd
တမ်းပလိတ်:Taxonomy/Zatheria
10
3849
17649
2026-03-29T17:09:53Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Zatheria |parent=Cladotheria }}"
17649
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Zatheria
|parent=Cladotheria
}}
01lb19ipjfln4ff3c9hr8vm39n1910s
တမ်းပလိတ်:Taxonomy/Cladotheria
10
3850
17650
2026-03-29T17:10:23Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Cladotheria |parent=Trechnotheria }}<noinclude></noinclude>"
17650
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Cladotheria
|parent=Trechnotheria
}}<noinclude></noinclude>
c3o2k5jvc73t8qs0xwhxsyekotw4gst
တမ်းပလိတ်:Taxonomy/Trechnotheria
10
3851
17651
2026-03-29T17:11:06Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Trechnotheria |parent=Theriiformes |extinct= }}"
17651
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Trechnotheria
|parent=Theriiformes
|extinct=
}}
q93oz7ra3aspib4jcdsbdjap5lx2wmc
တမ်းပလိတ်:Taxonomy/Theriiformes
10
3852
17652
2026-03-29T17:11:41Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Theriiformes |parent=Theriimorpha |refs={{cite journal |last1=Rowe |first1=T. |title=Phylogenetic Systematics and the Early History of Mammals |journal=Mammal Phylogeny |date=1993 |pages=129–145 |doi=10.1007/978-1-4613-9249-1_10}} }}"
17652
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Theriiformes
|parent=Theriimorpha
|refs={{cite journal |last1=Rowe |first1=T. |title=Phylogenetic Systematics and the Early History of Mammals |journal=Mammal Phylogeny |date=1993 |pages=129–145 |doi=10.1007/978-1-4613-9249-1_10}}
}}
qgk9dxfsmar6gvidxd6kvjlaw2g53fj
တမ်းပလိတ်:Taxonomy/Theriimorpha
10
3853
17653
2026-03-29T17:12:14Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Theriimorpha |parent=Mammalia/skip |extinct= <!--leave blank or delete this line for "not extinct"; put "yes" for "extinct" --> |refs= * {{cite journal |last1=Macrini |first1=T. E. |last2=Rougier |first2=G. W. |last3=Rowe |first3=T. |title=Description of a Cranial Endocast from the Fossil Mammal ''Vincelestes neuquenianus'' (Theriiformes) and its Relevance to the Evolution of Endocranial Characters in Therians..."
17653
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Theriimorpha
|parent=Mammalia/skip
|extinct= <!--leave blank or delete this line for "not extinct"; put "yes" for "extinct" -->
|refs=
* {{cite journal |last1=Macrini |first1=T. E. |last2=Rougier |first2=G. W. |last3=Rowe |first3=T. |title=Description of a Cranial Endocast from the Fossil Mammal ''Vincelestes neuquenianus'' (Theriiformes) and its Relevance to the Evolution of Endocranial Characters in Therians |journal=The Anatomical Record: Advances in Integrative Anatomy and Evolutionary Biology |date=2007 |volume=290 |issue=7 |pages=875–892 |doi=10.1002/ar.20551}}
* {{cite journal |last1=Rowe |first1=T. |title=Phylogenetic Systematics and the Early History of Mammals |journal=Mammal Phylogeny |date=1993 |pages=129–145 |doi=10.1007/978-1-4613-9249-1_10}}
}}
eus9hu70yl9sjs5dkccna47xm6cs8id
တမ်းပလိတ်:Taxonomy/Mammalia/skip
10
3854
17654
2026-03-29T17:12:45Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |same as=Mammalia |parent=Amniota }}"
17654
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|same as=Mammalia
|parent=Amniota
}}
gt8taofzb3sflnijh076vpa63i9etto
တမ်းပလိတ်:Taxonomy/Mammalia
10
3855
17655
2026-03-29T17:13:17Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=classis |link=နို့တိုက်သတ္တဝါ|Mammalia |parent=Mammaliaformes/skip }}"
17655
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=classis
|link=နို့တိုက်သတ္တဝါ|Mammalia
|parent=Mammaliaformes/skip
}}
ektk03h5c7i02o830fxm5l1zw0bvbje
တမ်းပလိတ်:Taxonomy/Amniota
10
3856
17656
2026-03-29T17:13:52Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=clade |link=Amniota |parent=Reptiliomorpha }}"
17656
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=clade
|link=Amniota
|parent=Reptiliomorpha
}}
qbhp2v0wvlf8mzoj3g9osixlkl5btkl
တမ်းပလိတ်:Taxonomy/Reptiliomorpha
10
3857
17657
2026-03-29T17:14:26Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=clade |link=Reptiliomorpha |parent=Tetrapoda }}"
17657
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=clade
|link=Reptiliomorpha
|parent=Tetrapoda
}}
nfxgvove5mv8mx5qf4d59rf8ooj7qx9
တမ်းပလိတ်:Taxonomy/Tetrapoda
10
3858
17658
2026-03-29T17:15:03Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=superclassis |link=ခြီလေးချောင်း သတ္တဝါ|Tetrapoda |parent=Stegocephalia }}"
17658
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=superclassis
|link=ခြီလေးချောင်း သတ္တဝါ|Tetrapoda
|parent=Stegocephalia
}}
exzehvogc3hf3r0xdq82mqm1v7tgp2w
တမ်းပလိတ်:Taxonomy/Stegocephalia
10
3859
17659
2026-03-29T17:15:38Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Stegocephalia |parent=Elpistostegalia |extinct= |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17659
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Stegocephalia
|parent=Elpistostegalia
|extinct=
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
6umy76faum2hyykpoa7al494vyd14rr
တမ်းပလိတ်:Taxonomy/Elpistostegalia
10
3860
17660
2026-03-29T17:16:16Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Elpistostegalia |parent=Eotetrapodiformes |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17660
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Elpistostegalia
|parent=Eotetrapodiformes
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
4b7ebc3jbkdw8bktbzlr46kkscuya84
တမ်းပလိတ်:Taxonomy/Eotetrapodiformes
10
3861
17661
2026-03-29T17:16:50Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Eotetrapodiformes |parent=Tetrapodomorpha |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17661
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Eotetrapodiformes
|parent=Tetrapodomorpha
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
0ya6vr1lwbykmvee2x9xwd4fasyt0lc
တမ်းပလိတ်:Taxonomy/Tetrapodomorpha
10
3862
17662
2026-03-29T17:17:21Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Tetrapodomorpha |parent=Rhipidistia |extinct= |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17662
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Tetrapodomorpha
|parent=Rhipidistia
|extinct=
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
7jnsf3i9uoubxf2zkcmb231dw0s2sr7
တမ်းပလိတ်:Taxonomy/Rhipidistia
10
3863
17663
2026-03-29T17:18:00Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Rhipidistia |parent=Sarcopterygii |extinct= |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17663
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Rhipidistia
|parent=Sarcopterygii
|extinct=
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
dswn6xidf0m5mcfrgbenky2qmdyz7a3
တမ်းပလိတ်:Taxonomy/Sarcopterygii
10
3864
17664
2026-03-29T17:18:30Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Sarcopterygii |parent=Euteleostomi }}"
17664
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Sarcopterygii
|parent=Euteleostomi
}}
j9ubljv3fwmc0kzd61ny1stavoavskt
တမ်းပလိတ်:Taxonomy/Euteleostomi
10
3865
17665
2026-03-29T17:20:32Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Euteleostomi |parent=Teleostomi |extinct= |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17665
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Euteleostomi
|parent=Teleostomi
|extinct=
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
sjte8nwk30u1qdy7bypze20bfunpezv
တမ်းပလိတ်:Taxonomy/Teleostomi
10
3866
17666
2026-03-29T17:21:00Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=clade |link=Teleostomi |parent=Eugnathostomata }}"
17666
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=clade
|link=Teleostomi
|parent=Eugnathostomata
}}
7dyeqx6n5tki3viflj4etazi6vkvl9g
တမ်းပလိတ်:Taxonomy/Eugnathostomata
10
3867
17667
2026-03-29T17:21:33Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=clade |link=Eugnathostomata |parent=Gnathostomata }}"
17667
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=clade
|link=Eugnathostomata
|parent=Gnathostomata
}}
2byglut9j8yabiid38bryjm2ss4dz2v
တမ်းပလိတ်:Taxonomy/Gnathostomata
10
3868
17668
2026-03-29T17:22:03Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=infraphylum |link=Gnathostomata |parent=Vertebrata }}"
17668
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=infraphylum
|link=Gnathostomata
|parent=Vertebrata
}}
jjc3y22zpbmoryuaxrmeitcwq23vitk
တမ်းပလိတ်:Taxonomy/Vertebrata
10
3869
17669
2026-03-29T17:22:35Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=subphylum |link=ကျောရိုးဟိသတ္တဝါ|Vertebrata |parent=Olfactores }}"
17669
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=subphylum
|link=ကျောရိုးဟိသတ္တဝါ|Vertebrata
|parent=Olfactores
}}
nk50uiy38xlar64xgmnbd54wnivwkg9
တမ်းပလိတ်:Taxonomy/Olfactores
10
3870
17670
2026-03-29T17:23:07Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Olfactores |parent=Chordata |extinct= |refs=<!--Shown on this page only; don't include <ref> tags --> }}"
17670
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Olfactores
|parent=Chordata
|extinct=
|refs=<!--Shown on this page only; don't include <ref> tags -->
}}
8xhgrq35xxrvixw05ve1hyyher1pjvq
တမ်းပလိတ်:Taxonomy/Chordata
10
3871
17671
2026-03-29T17:23:38Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=phylum |link=ကော်ဒိတ်|Chordata |parent=Deuterostomia }}"
17671
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=phylum
|link=ကော်ဒိတ်|Chordata
|parent=Deuterostomia
}}
gadejjlqs7ov4uyxc0pfq5kke5uf4im
တမ်းပလိတ်:Taxonomy/Deuterostomia
10
3872
17672
2026-03-29T17:24:11Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=superphylum |link=Deuterostomia |parent=Nephrozoa }}"
17672
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=superphylum
|link=Deuterostomia
|parent=Nephrozoa
}}
d5vpp13c06cksdx2ldgpmjdxjgl08z0
တမ်းပလိတ်:Taxonomy/Nephrozoa
10
3873
17673
2026-03-29T17:24:40Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=clade |link=Nephrozoa |parent=Bilateria }}"
17673
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=clade
|link=Nephrozoa
|parent=Bilateria
}}
k5wj5tw99ztz0034mt23zlrd2a3rlcp
တမ်းပလိတ်:Taxonomy/Bilateria
10
3874
17674
2026-03-29T17:25:15Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=clade |link=Bilateria |parent=ParaHoxozoa |refs={{Cite journal|last=Ryan|first=Joseph F.|last2=Pang|first2=Kevin|last3=Mullikin|first3=James C.|last4=Martindale|first4=Mark Q.|last5=Baxevanis|first5=Andreas D.|date=2010-10-04|title=The homeodomain complement of the ctenophore Mnemiopsis leidyi suggests that Ctenophora and Porifera diverged prior to the ParaHoxozoa|journal=EvoDevo|volume=1|issue=1|pages=9|doi=10.1186/2041-9..."
17674
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Bilateria
|parent=ParaHoxozoa
|refs={{Cite journal|last=Ryan|first=Joseph F.|last2=Pang|first2=Kevin|last3=Mullikin|first3=James C.|last4=Martindale|first4=Mark Q.|last5=Baxevanis|first5=Andreas D.|date=2010-10-04|title=The homeodomain complement of the ctenophore Mnemiopsis leidyi suggests that Ctenophora and Porifera diverged prior to the ParaHoxozoa|journal=EvoDevo|volume=1|issue=1|pages=9|doi=10.1186/2041-9139-1-9|pmid=20920347|pmc=2959044|issn=2041-9139}}
}}
o6zee4txfbr3w4l4p10u0iufekz4n49
တမ်းပလိတ်:Taxonomy/ParaHoxozoa
10
3875
17675
2026-03-29T17:25:50Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=cladus |link=ParaHoxozoa |parent=Eumetazoa |extinct=<!--leave blank or delete this line for "not extinct"; put "yes" for "extinct" --> |refs= *{{Cite journal|last=Giribet|first=Gonzalo|year=2016|title=Genomics and the animal tree of life: conflicts and future prospects|journal=Zoologica Scripta|language=en|volume=45|pages=14–21|doi=10.1111/zsc.12215|issn=1463-6409}} *{{Cite journal|last=Ryan|first=Joseph F.|last2=Pang|fi..."
17675
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=ParaHoxozoa
|parent=Eumetazoa
|extinct=<!--leave blank or delete this line for "not extinct"; put "yes" for "extinct" -->
|refs=
*{{Cite journal|last=Giribet|first=Gonzalo|year=2016|title=Genomics and the animal tree of life: conflicts and future prospects|journal=Zoologica Scripta|language=en|volume=45|pages=14–21|doi=10.1111/zsc.12215|issn=1463-6409}}
*{{Cite journal|last=Ryan|first=Joseph F.|last2=Pang|first2=Kevin|last3=Mullikin|first3=James C.|last4=Martindale|first4=Mark Q.|last5=Baxevanis|first5=Andreas D.|year=2010|title=The homeodomain complement of the ctenophore Mnemiopsis leidyi suggests that Ctenophora and Porifera diverged prior to the ParaHoxozoa|journal=EvoDevo|volume=1|issue=1|pages=9|doi=10.1186/2041-9139-1-9|pmid=20920347|pmc=2959044|issn=2041-9139}}<!--Shown on this page only; don't include <ref> tags -->
}}
rgpuqjgcxg57rzzbzfdguihp6mamqbe
တမ်းပလိတ်:Taxonomy/Eumetazoa
10
3876
17676
2026-03-29T17:26:21Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=subregnum |link=Eumetazoa |parent=Animalia }}"
17676
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=subregnum
|link=Eumetazoa
|parent=Animalia
}}
k6qpo5lue956nsbiivvzfui9z6wd37w
တမ်းပလိတ်:Taxonomy/Animalia
10
3877
17677
2026-03-29T17:27:07Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=regnum |link=တိရစ္ဆာန်|Animalia |parent=Filozoa }}"
17677
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=regnum
|link=တိရစ္ဆာန်|Animalia
|parent=Filozoa
}}
0av4ongm5io5ruegfl8c3dflleg1ehq
တမ်းပလိတ်:Taxonomy/Filozoa
10
3878
17678
2026-03-29T17:27:39Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=unranked |parent=Holozoa |link=Filozoa }}"
17678
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=unranked
|parent=Holozoa
|link=Filozoa
}}
cgeojns0teow4fv2nbswu558cqwd5po
တမ်းပလိတ်:Taxonomy/Holozoa
10
3879
17679
2026-03-29T17:28:09Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=unranked |parent=Opisthokonta |link=Holozoa }}"
17679
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=unranked
|parent=Opisthokonta
|link=Holozoa
}}
fer9xi94jes8jpcsy0z7i93oy915tfu
တမ်းပလိတ်:Taxonomy/Opisthokonta
10
3880
17680
2026-03-29T17:28:47Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=unranked |link=Opisthokont|Opisthokonta |parent=Unikonta }}"
17680
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=unranked
|link=Opisthokont|Opisthokonta
|parent=Unikonta
}}
afxj7pfi5vawqdbjkpw1590ntxlfiar
တမ်းပလိတ်:Taxonomy/Unikonta
10
3881
17681
2026-03-29T17:29:19Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}}|{{{1}}} |rank=unranked |link=Unikont|Unikonta |parent=Eukaryota }}"
17681
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}|{{{1}}}
|rank=unranked
|link=Unikont|Unikonta
|parent=Eukaryota
}}
7t1nmgqjhp9uluq9g2f51a6fylu97we
တမ်းပလိတ်:Taxonomy/Eukaryota
10
3882
17682
2026-03-29T17:31:04Z
YaThaWinTha
42
Created page with "{{Don't edit this line {{{machine code|}}} |rank=domain |parent=Life |link=နြူးကလိယအစစ်ပါ သက်ဟိ|ယူကာယုတ် }}"
17682
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=domain
|parent=Life
|link=နြူးကလိယအစစ်ပါ သက်ဟိ|ယူကာယုတ်
}}
76hhjwjbz0mc7v5pzedh4v9gtnackaw