ဝီကီးပီးဒီးယား 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|}}}|&section={{{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|}}}|&section={{{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}}}}}||&nbsp;[[: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}}}}}||&nbsp;[[: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:&nbsp;|lang=သင်္သကရိုက်:&nbsp;|langcl=Classical Sanskrit:&nbsp;|langvd=Vedic Sanskrit:&nbsp;|pron=pronounced&nbsp;|cl=Classical Sanskrit pronunciation:&nbsp;|vd=Vedic Sanskrit pronunciation:&nbsp;|=|သင်္သကရိုက် အသံထွက်:&nbsp;}}</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:&nbsp;|lang=သင်္သကရိုက်:&nbsp;|langcl=Classical Sanskrit:&nbsp;|langvd=Vedic Sanskrit:&nbsp;|pron=pronounced&nbsp;|cl=Classical Sanskrit pronunciation:&nbsp;|vd=Vedic Sanskrit pronunciation:&nbsp;|=|သင်္သကရိုက် အသံထွက်:&nbsp;}}</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=&#91;|&nbsp;(}}{{#if:{{{WD|}}} | [[d:{{{WD}}}#sitelinks-wikipedia|<span title="&quot;{{{1}}}&quot; in other languages">Wikidata</span>]]<!-- -->{{#if:{{{reasonator|}}}|<nowiki />; [//tools.wmflabs.org/reasonator/?q={{urlencode:{{{WD}}}}} Reasonator]}} | {{Separated entries|separator=;&#32; | {{#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=;&#32; | {{#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=&#93;|)}}</{{#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&params=1_2_N_3_4_W_ or //tools.wmflabs.org/geohack/geohack.php?pagename=Example&params=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|&nbsp;}}}{{{impu|ft}}}{{#ifeq:{{{impv|0}}}|1||{{#ifeq:{{{s}}}|/||{{#ifeq:{{{impu}}}|acre|s}}}}}} ({{{metv}}}{{{s|&nbsp;}}}{{{metu|m}}})}}</includeonly><noinclude> {{documentation}} </noinclude>" 17607 wikitext text/x-wiki <includeonly>{{formatnum:{{{impv}}}{{{s|&nbsp;}}}{{{impu|ft}}}{{#ifeq:{{{impv|0}}}|1||{{#ifeq:{{{s}}}|/||{{#ifeq:{{{impu}}}|acre|s}}}}}} ({{{metv}}}{{{s|&nbsp;}}}{{{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=&nbsp;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=&nbsp;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=&nbsp;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=&nbsp;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=&nbsp;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=&nbsp;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=&nbsp;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}}}}}}}&nbsp;{{MONTHNAME|{{{2}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}}&nbsp;{{formatnum:{{#expr:{{{3}}}}}}}၊<!-- -->}} {{formatnum:{{{1}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}}&nbsp;{{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}}}}}}}&nbsp;{{MONTHNAME|{{{2}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}}&nbsp;{{formatnum:{{#expr:{{{3}}}}}}}၊<!-- -->}} {{formatnum:{{{1}}}}}<!-- -->|{{MONTHNAME|{{{2}}}}}&nbsp;{{formatnum:{{{1}}}}}<!-- -->}}<!-- -->|{{formatnum:{{{1}}}}}<!-- -->}}<!-- --><span class="noprint">{{#ifeq:{{yesno|{{{paren|{{{p|no}}}}}}}}|yes||&#059;}}<!-- -->{{#ifeq:{{yesno|{{{br|no}}}}}|yes|<br/>|&#032;}}<!-- -->{{#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">&#160;(<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 "&nbsp;&ndash;&#32;<noinclude> {{documentation}} <!-- Add categories and interwikis to the /doc subpage, not here! --> </noinclude>" 17626 wikitext text/x-wiki &nbsp;&ndash;&#32;<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 ဒေတမ်းပလိတ်မှာ '''ဆောင်းပါးတို တမ်းပလိတ်'''တခုဖြစ်တေ။ ၎င်းတမ်းပလိတ်တိအကြောင်း အကျိုင်းယှင်းလင်းချက်မှာ အောက်ပါအတိုင်းဖြစ်တေ။ အသေးစိတ်သိဟိလိုကေ [[ဝီကီးပီးဒီးယား:ဆောင်းပါးတို]]တိအကြောင်းမာ ကြည့်ရှုပါ။ === ဆောင်းပါးတိုဆိုစွာ ဇာလေ့? === '''ဆောင်းပါးတို'''ဆိုစွာမာ ဝါကျအကြောင်းရေ စိကေသျှေသာပါဟိဗျာယ်း ၎င်းနန့်သက်ဆိုင်ရေ အကြောင်းအရာအား ပြည့်စုံစွာ ခြုံငုံဖော်ပြနိူင်စွမ်းမဟိရေ စွယ်စုံကျမ်း ဆောင်းပါးအရာမမြောက်ရေ ဆောင်းပါးတစ်ပုဒ်ပင်ဖြစ်တေ။ === ဆောင်းပါးတိုကို တခုပိုင်လေ့တ်သားဖို့လဲ === * ဖြစ်နှိုင်ပါက မိမိရီးသားရေ ဆောင်းပါးတိုနန့် အသင့်တော်ဆုံး တမ်းပလိတ်ကိုသုံး၍ မှတ်သားပါ။ စာရင်းအပြည့်အစုံမှာ နောင်ရခိုင်ဝီကီး တိုးပွားစေပင်လာရေအခါ [[ဝီကီးပီးဒီးယား:ဝီကီးပရောဂျက် ဆောင်းပါးတို စီမံရီး/ဆောင်းပါးတို အမျိုးအစားတိ]] အဖြစ် ပရောဂျက်တခုအနေနန့် စီစိုင်ရန်ဖြစ်တေ။ * လိုအပ်ပါကေ ဆောင်းပါးတို တမ်းပလိတ် (၂)ခုထက်ပိုပြီးကေ သုံးနှိုင်ရေ်လည်း၊ အများဆုံး (၄)ခုထက်ပိုပြီးကေ မသုံးသင့်ပါ၊၊ * ဆောင်းပါးတို တမ်းပလိတ်ကို &ldquo;ပြင်ပချိတ်ဆက်လင့်တိ&rdquo;၊ လှည့်လည်ကြည့်ရှုရာမာ လွယ်ကူစီရန် ကူညီရေ လက်ကြားပြ တမ်းပလိတ်တိ(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;" } }, ["alpha++"] = { link = "Alpha particle", symbol = { "&alpha;", 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;" } }, ["alpha++"] = { link = "Alpha particle", symbol = { "&alpha;", TR = "++" } }, ["antib"] = { link = "B meson", symbol = { "B", anti = "yes" } }, ["antib*"] = { link = "B meson", symbol = { "B", anti = "yes", TR = "&lowast;" } }, ["antib*0"] = { link = "B meson", symbol = { "B", anti = "yes", TR = "&lowast;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 = "&lowast;" } }, ["antid*0"] = { link = "D meson", symbol = { "D", anti = "yes", TR = "&lowast;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 = "&lowast;" } }, ["antikaon*0"] = { link = "Kaon", symbol = { "K", anti = "yes", TR = "&lowast;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 = { "&mu;", TR = "+" } }, ["antineutrino"] = { link = "Antineutrino", symbol = { "&nu;", anti = "yes" } }, ["antineutrino0"] = { link = "Antineutrino", symbol = { "&nu;", 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 = { "&gamma;", anti = "yes" } }, ["antiphoton0"] = { link = "Antiphoton", symbol = { "&gamma;", anti = "yes", TR = "0" } }, ["antiproton"] = { link = "Antiproton", symbol = { "p", anti = "yes" } }, ["antiquark"] = { link = "Antiquark", symbol = { "q", anti = "yes" } }, ["antislepton"] = { link = "Slepton", symbol = { "l&#x0305;&#x0342;" } }, ["antisquark"] = { link = "Squark", symbol = { "q&#x0305;&#x0342;" } }, ["antit"] = { link = "T meson", symbol = { "T", anti = "yes" } }, ["antit*"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "&lowast;" } }, ["antit*0"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "&lowast;0" } }, ["antit0"] = { link = "T meson", symbol = { "T", anti = "yes", TR = "0" } }, ["antitau"] = { link = "Antitau", symbol = { "&tau;", TR = "+" } }, ["antitauon"] = { link = "Antitauon", symbol = { "&tau;", TR = "+" } }, ["antitritium"] = { link = "Antitritium", symbol = { "T", anti = "yes" } }, ["axino"] = { link = "", symbol = { "A&#x0342;", TR = "0" } }, ["axion"] = { link = "", symbol = { "A", TR = "0" } }, ["b"] = { link = "B meson", symbol = { "B" } }, ["b*"] = { link = "B meson", symbol = { "B", TR = "&lowast;" } }, ["b*+"] = { link = "B meson", symbol = { "B", TR = "&lowast;+" } }, ["b*+-"] = { link = "B meson", symbol = { "B", TR = "&lowast;&plusmn;" } }, ["b*-"] = { link = "B meson", symbol = { "B", TR = "&lowast;&minus;" } }, ["b*-+"] = { link = "B meson", symbol = { "B", TR = "&lowast;&#x2213;" } }, ["b*0"] = { link = "B meson", symbol = { "B", TR = "&lowast;0" } }, ["b+"] = { link = "B meson", symbol = { "B", TR = "+" } }, ["b+-"] = { link = "B meson", symbol = { "B", TR = "&plusmn;" } }, ["b-"] = { link = "B meson", symbol = { "B", TR = "&minus;" } }, ["b-+"] = { link = "B meson", symbol = { "B", TR = "&#x2213;" } }, ["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;" } }, ["beta+"] = { link = "Beta particle", symbol = { "&beta;", TR = "+" } }, ["beta+-"] = { link = "Beta particle", symbol = { "&beta;", TR = "&plusmn;" } }, ["beta-"] = { link = "Beta particle", symbol = { "&beta;", TR = "&minus;" } }, ["beta-+"] = { link = "Beta particle", symbol = { "&beta;", TR = "&#x2213;" } }, ["bino"] = { link = "Bino (particle)", symbol = { "b&#x0342;" } }, ["blue antiquark"] = { link = "Color charge", symbol = { "q", anti = "yes", BR = "B" } }, ["blue antisquark"] = { link = "Color charge", symbol = { "q&#x0305;&#x0342;", BR = "B" } }, ["blue quark"] = { link = "Color charge", symbol = { "q", BR = "B" } }, ["blue squark"] = { link = "Color charge", symbol = { "q&#x0342;", BR = "B" } }, ["bottom antiquark"] = { link = "Bottom antiquark", symbol = { "b", anti = "yes" } }, ["bottom antisquark"] = { link = "Squark", symbol = { "b&#x0305;&#x0342;" } }, ["bottom antit"] = { link = "Bottom T meson", symbol = { "T", anti = "yes", TR = "b" } }, ["bottom double top omega"] = { link = "Bottom double top omega baryon", symbol = { "&Omega;", BR = "btt" } }, ["bottom double top omega*"] = { link = "Bottom double top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "btt" } }, ["bottom double top omega*+"] = { link = "Bottom double top omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "btt" } }, ["bottom double top omega+"] = { link = "Bottom double top omega baryon", symbol = { "&Omega;", TR = "+", BR = "btt" } }, ["bottom eta"] = { link = "Bottom eta meson", symbol = { "&eta;", BR = "b" } }, ["bottom eta0"] = { link = "Bottom eta meson", symbol = { "&eta;", TR = "0", BR = "b" } }, ["bottom eta prime"] = { link = "Bottom eta prime meson", symbol = { "&eta;&prime;", BR = "b" } }, ["bottom eta prime0"] = { link = "Bottom eta prime meson", symbol = { "&eta;&prime;", TR = "0", BR = "b" } }, ["bottom lambda"] = { link = "Bottom lambda baryon", symbol = { "&Lambda;", BR = "b" } }, ["bottom lambda*"] = { link = "Bottom lambda baryon", symbol = { "&Lambda;", TR = "&lowast;", BR = "b" } }, ["bottom lambda*0"] = { link = "Bottom lambda baryon", symbol = { "&Lambda;", TR = "&lowast;0", BR = "b" } }, ["bottom lambda0"] = { link = "Bottom lambda baryon", symbol = { "&Lambda;", TR = "0", BR = "b" } }, ["bottom omega"] = { link = "Bottom omega baryon", symbol = { "&Omega;", BR = "b" } }, ["bottom omega*"] = { link = "Bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "b" } }, ["bottom omega*-"] = { link = "Bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;&minus;", BR = "b" } }, ["bottom omega-"] = { link = "Bottom omega baryon", symbol = { "&Omega;", TR = "&minus;", BR = "b" } }, ["bottom quark"] = { link = "Bottom quark", symbol = { "b" } }, ["bottom sigma"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", BR = "b" } }, ["bottom sigma*"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&lowast;", BR = "b" } }, ["bottom sigma*+"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&lowast;+", BR = "b" } }, ["bottom sigma*+-"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&lowast;&plusmn;", BR = "b" } }, ["bottom sigma*-"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&lowast;&minus;", BR = "b" } }, ["bottom sigma*-+"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&#x2213;", BR = "b" } }, ["bottom sigma*0"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&lowast;0", BR = "b" } }, ["bottom sigma+"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "+", BR = "b" } }, ["bottom sigma+-"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&plusmn;", BR = "b" } }, ["bottom sigma-"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&minus;", BR = "b" } }, ["bottom sigma-+"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "&#x2213;", BR = "b" } }, ["bottom sigma0"] = { link = "Bottom sigma baryon", symbol = { "&Sigma;", TR = "0", BR = "b" } }, ["bottom squark"] = { link = "Squark", symbol = { "b&#x0342;" } }, ["bottom t"] = { link = "Bottom T meson", symbol = { "T", TR = "b" } }, ["bottom t*"] = { link = "Bottom T meson", symbol = { "T", TR = "&lowast;", BR = "b" } }, ["bottom t*+"] = { link = "Bottom T meson", symbol = { "T", TR = "&lowast;+", BR = "b" } }, ["bottom t*+-"] = { link = "Bottom T meson", symbol = { "T", TR = "&lowast;&plusmn;", BR = "b" } }, ["bottom t*-"] = { link = "Bottom T meson", symbol = { "T", TR = "&lowast;&minus;", BR = "b" } }, ["bottom t*-+"] = { link = "Bottom T meson", symbol = { "T", TR = "&lowast;&#x2213;", BR = "b" } }, ["bottom t+"] = { link = "Bottom T meson", symbol = { "T", TR = "+", BR = "b" } }, ["bottom t+-"] = { link = "Bottom T meson", symbol = { "T", TR = "&plusmn;", BR = "b" } }, ["bottom t-"] = { link = "Bottom T meson", symbol = { "T", TR = "&minus;", BR = "b" } }, ["bottom top omega"] = { link = "Bottom top omega baryon", symbol = { "&Omega;", BR = "bt" } }, ["bottom top omega'"] = { link = "", symbol = { "&Omega;&prime;", BR = "bt" } }, ["bottom top omega'0"] = { link = "", symbol = { "&Omega;&prime;", TR = "0", BR = "bt" } }, ["bottom top omega*"] = { link = "Bottom top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "bt" } }, ["bottom top omega*0"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "bt" } }, ["bottom top omega0"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", TR = "0", BR = "bt" } }, ["bottom top xi"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", BR = "bt" } }, ["bottom top xi'"] = { link = "", symbol = { "&Xi;&prime;", BR = "bt" } }, ["bottom top xi'+"] = { link = "", symbol = { "&Xi;&prime;", TR = "+", BR = "bt" } }, ["bottom top xi'0"] = { link = "", symbol = { "&Xi;&prime;", TR = "0", BR="bt" } }, ["bottom top xi*"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "bt" } }, ["bottom top xi*+"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "bt" } }, ["bottom top xi*0"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "bt" } }, ["bottom top xi+"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", TR = "+", BR = "bt" } }, ["bottom top xi0"] = { link = "Bottom top xi baryon", symbol = { "&Xi;", TR = "0", BR = "bt" } }, ["bottom xi"] = { link = "Bottom xi baryon", symbol = { "&Xi;", BR = "b" } }, ["bottom xi'"] = { link = "Bottom xi baryon", symbol = { "&Xi;&prime;", BR = "b" } }, ["bottom xi'-"] = { link = "Bottom xi baryon", symbol = { "&Xi;&prime;", TR = "&minus;", BR = "b" } }, ["bottom xi'0"] = { link = "Bottom xi baryon", symbol = { "&Xi;&prime;", TR = "0", BR = "b" } }, ["bottom xi*"] = { link = "Bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "b" } }, ["bottom xi*-"] = { link = "Bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;&minus;", BR = "b" } }, ["bottom xi*0"] = { link = "Bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "b" } }, ["bottom xi-"] = { link = "Bottom xi baryon", symbol = { "&Xi;", TR = "&minus;", BR = "b" } }, ["bottom xi0"] = { link = "Bottom xi baryon", symbol = { "&Xi;", TR = "0", BR = "b" } }, ["cascade b"] = { link = "Charmed xi baryon", symbol = { "&Xi;", BR = "b" } }, ["chargino+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "+" } }, ["chargino+-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&plusmn;" } }, ["chargino-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&minus;" } }, ["chargino-+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&#x2213;" } }, ["chargino 1+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "+", BR = "1" } }, ["chargino 1+-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&plusmn;", BR = "1" } }, ["chargino 1-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&minus;", BR = "1" } }, ["chargino 1-+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&#x2213;", BR = "1" } }, ["chargino 2+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "+", BR = "2" } }, ["chargino 2+-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&plusmn;", BR = "2" } }, ["chargino 2-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&minus;", BR = "2" } }, ["chargino 2-+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&#x2213;", BR = "2" } }, ["chargino i+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "+", BR = "i" } }, ["chargino i+-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&plusmn;", BR = "i" } }, ["chargino i-"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&minus;", BR = "i" } }, ["chargino i-+"] = { link = "Chargino", symbol = { "C&#x0342;", TR = "&#x2213;", BR = "i" } }, ["charm antiquark"] = { link = "Charm antiquark", symbol = { "c", anti = "yes" } }, ["charm antisquark"] = { link = "Squark", symbol = { "c&#x0305;&#x0342;" } }, ["charm quark"] = { link = "Charm quark", symbol = { "c" } }, ["charm squark"] = { link = "Squark", symbol = { "c&#x0342;" } }, ["charmed antib"] = { link = "Charmed B meson", symbol = { "B", anti = "yes", BR = "c" } }, ["charmed antib*"] = { link = "Charmed B meson", symbol = { "B", anti = "yes", TR = "&lowast;", BR = "c" } }, ["charmed antit"] = { link = "Charmed T meson", symbol = { "T", anti = "yes", BR = "c" } }, ["charmed antit*"] = { link = "", symbol = { "T", anti = "yes", TR = "&lowast;", 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 = "&lowast;0", BR = "c" } }, ["charmed b"] = { link = "Charmed B meson", symbol = { "B", BR = "c" } }, ["charmed b*"] = { link = "Charmed B meson", symbol = { "B", TR = "&lowast;", BR = "c" } }, ["charmed b*+"] = { link = "Charmed B meson", symbol = { "B", TR = "&lowast;+", BR = "c" } }, ["charmed b*+-"] = { link = "Charmed B meson", symbol = { "B", TR = "&lowast;&plusmn;", BR = "c" } }, ["charmed b*-"] = { link = "Charmed B meson", symbol = { "B", TR = "&lowast;&minus;", BR = "c" } }, ["charmed b*-+"] = { link = "Charmed B meson", symbol = { "B", TR = "&lowast;&#x2213;", BR = "c" } }, ["charmed b+"] = { link = "Charmed B meson", symbol = { "B", TR = "+", BR = "c" } }, ["charmed b+-"] = { link = "Charmed B meson", symbol = { "B", TR = "&plusmn;", BR = "c" } }, ["charmed b-"] = { link = "Charmed B meson", symbol = { "B", TR = "&minus;", BR = "c" } }, ["charmed b-+"] = { link = "Charmed B meson", symbol = { "B", TR = "&#x2213;", BR = "c" } }, ["charmed bottom omega"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;", BR = "cb" } }, ["charmed bottom omega'"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;&prime;", BR = "cb" } }, ["charmed bottom omega'0"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;&prime;", TR = "0", BR = "cb" } }, ["charmed bottom omega*"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "cb" } }, ["charmed bottom omega*0"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "cb" } }, ["charmed bottom omega0"] = { link = "Charmed bottom omega baryon", symbol = { "&Omega;", TR = "0", BR = "cb" } }, ["charmed bottom top omega"] = { link = "Charmed bottom top omega baryon", symbol = { "&Omega;", BR = "cbt" } }, ["charmed bottom top omega*"] = { link = "Charmed bottom top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "cbt" } }, ["charmed bottom top omega*+"] = { link = "Charmed bottom top omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "cbt" } }, ["charmed bottom top omega+"] = { link = "Charmed bottom top omega baryon", symbol = { "&Omega;", TR = "+", BR = "cbt" } }, ["charmed bottom xi"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", BR = "cc" } }, ["charmed bottom xi'"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;&prime;", BR = "cc" } }, ["charmed bottom xi'+"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;&prime;", TR = "+", BR = "cb" } }, ["charmed bottom xi'0"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;&prime;", TR = "0", BR = "cb" } }, ["charmed bottom xi*"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "cc" } }, ["charmed bottom xi*+"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "cb" } }, ["charmed bottom xi*0"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "cb" } }, ["charmed bottom xi+"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", TR = "+", BR = "cb" } }, ["charmed bottom xi0"] = { link = "Charmed bottom xi baryon", symbol = { "&Xi;", TR = "0", BR = "cb" } }, ["charmed double bottom omega"] = { link = "Charmed double bottom omega baryon", symbol = { "&Omega;", BR = "cbb" } }, ["charmed double bottom omega*"] = { link = "Charmed double bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "cbb" } }, ["charmed double bottom omega*0"] = { link = "Charmed double bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "cbb" } }, ["charmed double bottom omega0"] = { link = "Charmed double bottom omega baryon", symbol = { "&Omega;", TR = "0", BR = "cbb" } }, ["charmed double top omega"] = { link = "Charmed double top omega baryon", symbol = { "&Omega;", BR = "ctt" } }, ["charmed double top omega*"] = { link = "Charmed double top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "ctt" } }, ["charmed double top omega*++"] = { link = "Charmed double top omega baryon", symbol = { "&Omega;", TR = "&lowast;++", BR = "ctt" } }, ["charmed double top omega++"] = { link = "Charmed double top omega baryon", symbol = { "&Omega;", TR = "++", BR = "ctt" } }, ["charmed eta"] = { link = "Charmed eta meson", symbol = { "&eta;", BR = "c" } }, ["charmed eta0"] = { link = "Charmed eta meson", symbol = { "&eta;", TR = "0", BR = "c" } }, ["charmed eta prime"] = { link = "Charmed eta prime meson", symbol = { "&eta;&prime;", BR = "c" } }, ["charmed eta prime0"] = { link = "Charmed eta prime meson", symbol = { "&eta;&prime;", TR = "0", BR = "c" } }, ["charmed lambda"] = { link = "Charmed lambda baryon", symbol = { "&Lambda;", BR = "c" } }, ["charmed lambda*"] = { link = "Charmed lambda baryon", symbol = { "&Lambda;", TR = "&lowast;", BR = "c" } }, ["charmed lambda*+"] = { link = "Charmed lambda baryon", symbol = { "&Lambda;", TR = "&lowast;+", BR = "c" } }, ["charmed lambda+"] = { link = "Charmed lambda baryon", symbol = { "&Lambda;", TR = "+", BR = "c" } }, ["charmed omega"] = { link = "Charmed omega baryon", symbol = { "&Omega;", BR = "c" } }, ["charmed omega*"] = { link = "Charmed omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "c" } }, ["charmed omega*0"] = { link = "Charmed omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "c" } }, ["charmed omega0"] = { link = "Charmed omega baryon", symbol = { "&Omega;", TR = "0", BR = "c" } }, ["charmed sigma"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", BR = "c" } }, ["charmed sigma*"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "&lowast;", BR = "c" } }, ["charmed sigma*+"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "&lowast;+", BR = "c" } }, ["charmed sigma*++"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "&lowast;++", BR = "c" } }, ["charmed sigma*0"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "&lowast;0", BR = "c" } }, ["charmed sigma+"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "+", BR = "c" } }, ["charmed sigma++"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "++", BR = "c" } }, ["charmed sigma0"] = { link = "Charmed sigma baryon", symbol = { "&Sigma;", TR = "0", BR = "c" } }, ["charmed t"] = { link = "Charmed T meson", symbol = { "T", BR = "c" } }, ["charmed t*"] = { link = "Charmed T meson", symbol = { "T", TR = "&lowast;", BR = "c" } }, ["charmed t*0"] = { link = "Charmed T meson", symbol = { "T", TR = "&lowast;0", BR = "c" } }, ["charmed t0"] = { link = "Charmed T meson", symbol = { "T", TR = "0", BR = "c" } }, ["charmed theta0"] = { link = "Pentaquark", symbol = { "&Theta;", TR = "0", BR = "c" } }, ["charmed top omega"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", BR = "ct" } }, ["charmed top omega'"] = { link = "", symbol = { "&Omega;&prime;", BR = "ct" } }, ["charmed top omega'+"] = { link = "", symbol = { "&Omega;&prime;", TR = "+", BR = "ct" } }, ["charmed top omega*"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "ct" } }, ["charmed top omega*+"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "ct" } }, ["charmed top omega+"] = { link = "Charmed top omega baryon", symbol = { "&Omega;", TR = "+", BR = "ct" } }, ["charmed top xi"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", BR = "ct" } }, ["charmed top xi'"] = { link = "", symbol = { "&Xi;&prime;", BR = "ct" } }, ["charmed top xi'+"] = { link = "", symbol = { "&Xi;&prime;", TR = "+", BR = "ct" } }, ["charmed top xi'++"] = { link = "", symbol = { "&Xi;&prime;", TR = "++", BR = "ct" } }, ["charmed top xi*"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "ct" } }, ["charmed top xi*+"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "ct" } }, ["charmed top xi*++"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", TR = "&lowast;++", BR = "ct" } }, ["charmed top xi+"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", TR = "+", BR = "ct" } }, ["charmed top xi++"] = { link = "Charmed top xi baryon", symbol = { "&Xi;", TR = "++", BR = "ct" } }, ["charmed xi"] = { link = "Charmed xi baryon", symbol = { "&Xi;", BR = "c" } }, ["charmed xi'"] = { link = "Charmed xi baryon", symbol = { "&Xi;&prime;", BR = "c" } }, ["charmed xi'+"] = { link = "Charmed xi baryon", symbol = { "&Xi;&prime;", TR = "+", BR = "c" } }, ["charmed xi'0"] = { link = "Charmed xi baryon", symbol = { "&Xi;&prime;", TR = "0", BR = "c" } }, ["charmed xi*"] = { link = "Charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "c" } }, ["charmed xi*+"] = { link = "Charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "c" } }, ["charmed xi*0"] = { link = "Charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "c" } }, ["charmed xi+"] = { link = "Charmed xi baryon", symbol = { "&Xi;", TR = "+", BR = "c" } }, ["charmed xi0"] = { link = "Charmed xi baryon", symbol = { "&Xi;", TR = "0", BR = "c" } }, ["d"] = { link = "D meson", symbol = { "D" } }, ["d*"] = { link = "D meson", symbol = { "D", TR = "&lowast;" } }, ["d*+"] = { link = "D meson", symbol = { "D", TR = "&lowast;+" } }, ["d*+-"] = { link = "D meson", symbol = { "D", TR = "&lowast;&plusmn;" } }, ["d*-"] = { link = "D meson", symbol = { "D", TR = "&lowast;&minus;" } }, ["d*-+"] = { link = "D meson", symbol = { "D", TR = "&lowast;&#x2213;" } }, ["d*0"] = { link = "D meson", symbol = { "D", TR = "&lowast;0" } }, ["d+"] = { link = "D meson", symbol = { "D", TR = "+" } }, ["d+-"] = { link = "D meson", symbol = { "D", TR = "&plusmn;" } }, ["d-"] = { link = "D meson", symbol = { "D", TR = "&minus;" } }, ["d-+"] = { link = "D meson", symbol = { "D", TR = "&#x2213;" } }, ["d0"] = { link = "D meson", symbol = { "D", TR = "0" } }, ["delta"] = { link = "Delta baryon", symbol = { "&Delta;" } }, ["delta+"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "+" } }, ["delta++"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "++" } }, ["delta+-"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "&plusmn;" } }, ["delta-"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "&minus;" } }, ["delta-+"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "&#x2213;" } }, ["delta0"] = { link = "Delta baryon", symbol = { "&Delta;", TR = "0" } }, ["deuterium"] = { link = "", symbol = { "D" } }, ["double bottom omega"] = { link = "Double bottom omega baryon", symbol = { "&Omega;", BR = "bb" } }, ["double bottom omega*"] = { link = "Double bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "bb" } }, ["double bottom omega*-"] = { link = "Double bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;&minus;", BR = "bb" } }, ["double bottom omega-"] = { link = "Double bottom omega baryon", symbol = { "&Omega;", TR = "&minus;", BR = "bb" } }, ["double bottom top omega"] = { link = "Double bottom top omega baryon", symbol = { "&Omega;", BR = "bbt" } }, ["double bottom top omega*"] = { link = "Double bottom top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "bbt" } }, ["double bottom top omega*0"] = { link = "Double bottom top omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "bbt" } }, ["double bottom top omega0"] = { link = "Double bottom top omega baryon", symbol = { "&Omega;", TR = "0", BR = "bbt" } }, ["double bottom xi"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", BR = "bb" } }, ["double bottom xi*"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "bb" } }, ["double bottom xi*-"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;&minus;", BR = "bb" } }, ["double bottom xi*0"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "bb" } }, ["double bottom xi-"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", TR = "&minus;", BR = "bb" } }, ["double bottom xi0"] = { link = "Double bottom xi baryon", symbol = { "&Xi;", TR = "0", BR = "bb" } }, ["double charmed bottom omega"] = { link = "Double charmed bottom omega baryon", symbol = { "&Omega;", BR = "ccb" } }, ["double charmed bottom omega*"] = { link = "Double charmed bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "ccb" } }, ["double charmed bottom omega*+"] = { link = "Double charmed bottom omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "ccb" } }, ["double charmed bottom omega+"] = { link = "Double charmed bottom omega baryon", symbol = { "&Omega;", TR = "+", BR = "ccb" } }, ["double charmed omega"] = { link = "Double charmed omega baryon", symbol = { "&Omega;", BR = "cc" } }, ["double charmed omega*"] = { link = "Double charmed omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "cc" } }, ["double charmed omega*+"] = { link = "Double charmed omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "cc" } }, ["double charmed omega+"] = { link = "Double charmed omega baryon", symbol = { "&Omega;", TR = "+", BR = "cc" } }, ["double charmed top omega"] = { link = "Double charmed top omega baryon", symbol = { "&Omega;", BR = "cct" } }, ["double charmed top omega*"] = { link = "Double charmed top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "cct" } }, ["double charmed top omega*++"] = { link = "Double charmed top omega baryon", symbol = { "&Omega;", TR = "&lowast;++", BR = "cct" } }, ["double charmed top omega++"] = { link = "Double charmed top omega baryon", symbol = { "&Omega;", TR = "++", BR = "cct" } }, ["double charmed xi"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", BR = "cc" } }, ["double charmed xi*"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "cc" } }, ["double charmed xi*+"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "cc" } }, ["double charmed xi*++"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", TR = "&lowast;++", BR = "cc" } }, ["double charmed xi+"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", TR = "+", BR = "cc" } }, ["double charmed xi++"] = { link = "Double charmed xi baryon", symbol = { "&Xi;", TR = "++", BR = "cc" } }, ["double top omega"] = { link = "Double top omega baryon", symbol = { "&Omega;", BR = "tt" } }, ["double top omega*"] = { link = "Double top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "tt" } }, ["double top omega*+"] = { link = "Double top omega baryon", symbol = { "&Omega;", TR = "&lowast;+", BR = "tt" } }, ["double top omega+"] = { link = "Double top omega baryon", symbol = { "&Omega;", TR = "+", BR = "tt" } }, ["double top xi"] = { link = "Double top xi baryon", symbol = { "&Xi;", BR = "tt" } }, ["double top xi*"] = { link = "Double top xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "tt" } }, ["double top xi*+"] = { link = "Double top xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "tt" } }, ["double top xi*++"] = { link = "Double top xi baryon", symbol = { "&Xi;", TR = "&lowast;++", BR = "tt" } }, ["double top xi+"] = { link = "Double top xi baryon", symbol = { "&Xi;", TR = "+", BR = "tt" } }, ["double top xi++"] = { link = "Double top xi baryon", symbol = { "&Xi;", TR = "++", BR = "tt" } }, ["down antiquark"] = { link = "Down antiquark", symbol = { "d", anti = "yes" } }, ["down antisquark"] = { link = "Squark", symbol = { "d&#x0305;&#x0342;" } }, ["down quark"] = { link = "Down quark", symbol = { "d" } }, ["down squark"] = { link = "Squark", symbol = { "d&#x0342;" } }, ["electron"] = { link = "Electron", symbol = { "e", TR = "&minus;" } }, ["electron+"] = { link = "Positron", symbol = { "e", TR = "+" } }, ["electron+-"] = { link = "", symbol = { "e", TR = "&plusmn;" } }, ["electron-"] = { link = "Electron", symbol = { "e", TR = "&minus;" } }, ["electron-+"] = { link = "Electron", symbol = { "e", TR = "&#x2213;" } }, ["electron antineutrino"] = { link = "Electron antineutrino", symbol = { "&nu;", anti = "yes", BR = "e" } }, ["electron antineutrino0"] = { link = "Electron antineutrino", symbol = { "&nu;", anti = "yes", TR = "0", BR = "e" } }, ["electron neutrino"] = { link = "Electron neutrino", symbol = { "&nu;", BR = "e" } }, ["electron neutrino0"] = { link = "Electron neutrino", symbol = { "&nu;", TR = "0", BR = "e" } }, ["eta"] = { link = "Eta meson", symbol = { "&eta;" } }, ["eta0"] = { link = "Eta meson", symbol = { "&eta;", TR = "0" } }, ["eta prime"] = { link = "Eta prime meson", symbol = { "&eta;&prime;" } }, ["eta prime0"] = { link = "Eta prime meson", symbol = { "&eta;&prime;", TR = "0" } }, ["gamma"] = { link = "Gamma ray", symbol = { "&gamma;" } }, ["gluino"] = { link = "Gluino", symbol = { "g&#x0342;" } }, ["gluon"] = { link = "Gluon", symbol = { "g" } }, ["gluon0"] = { link = "Gluon", symbol = { "g", TR = "0" } }, ["gravitino"] = { link = "Gravitino", symbol = { "G&#x0342;" } }, ["graviton"] = { link = "", symbol = { "G" } }, ["green antiquark"] = { link = "Color charge", symbol = { "q", anti = "yes", BR = "G" } }, ["green antisquark"] = { link = "Color charge", symbol = { "q&#x0305;&#x0342;", BR = "G" } }, ["green quark"] = { link = "Color charge", symbol = { "q", BR = "G" } }, ["green squark"] = { link = "Color charge", symbol = { "q&#x0342;", BR = "G" } }, ["helium"] = { link = "", symbol = { "He" } }, ["higgs boson"] = { link = "Higgs boson", symbol = { "H", TR = "0" } }, ["higgsino"] = { link = "Higgsino", symbol = { "H&#x0342;" } }, ["hydrogen"] = { link = "", symbol = { "H" } }, ["j/psi"] = { link = "J/psi meson", symbol = { "J/&psi;" } }, ["j/psi0"] = { link = "J/psi meson", symbol = { "J/&psi;", TR = "0" } }, ["k-long"] = { link = "Kaon", symbol = { "K", BR = "L" } }, ["k-long*"] = { link = "Kaon", symbol = { "K", TR = "&lowast;", BR = "L" } }, ["k-long*0"] = { link = "Kaon", symbol = { "K", TR = "&lowast;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 = "&lowast;", BR = "S" } }, ["k-short*0"] = { link = "Kaon", symbol = { "K", TR = "&lowast;0", BR = "S" } }, ["k-short0"] = { link = "Kaon", symbol = { "K", TR = "0", BR = "S" } }, ["kaon"] = { link = "Kaon", symbol = { "K" } }, ["kaon*"] = { link = "Kaon", symbol = { "K", TR = "&lowast;" } }, ["kaon*+"] = { link = "Kaon", symbol = { "K", TR = "&lowast;+" } }, ["kaon*+-"] = { link = "Kaon", symbol = { "K", TR = "&lowast;&plusmn;" } }, ["kaon*-"] = { link = "Kaon", symbol = { "K", TR = "&lowast;&minus;" } }, ["kaon*-+"] = { link = "Kaon", symbol = { "K", TR = "&lowast;&#x2213;" } }, ["kaon*0"] = { link = "Kaon", symbol = { "K", TR = "&lowast;0" } }, ["kaon+"] = { link = "Kaon", symbol = { "K", TR = "+" } }, ["kaon+-"] = { link = "Kaon", symbol = { "K", TR = "&plusmn;" } }, ["kaon-"] = { link = "Kaon", symbol = { "K", TR = "&minus;" } }, ["kaon-+"] = { link = "Kaon", symbol = { "K", TR = "&#x2213;" } }, ["kaon0"] = { link = "Kaon", symbol = { "K", TR = "0" } }, ["lambda"] = { link = "Lambda baryon", symbol = { "&Lambda;" } }, ["lambda*"] = { link = "Lambda baryon", symbol = { "&Lambda;", TR = "&lowast;" } }, ["lambda*0"] = { link = "Lambda baryon", symbol = { "&Lambda;", TR = "&lowast;0" } }, ["lambda0"] = { link = "Lambda baryon", symbol = { "&Lambda;", TR = "0" } }, ["lepton"] = { link = "Lepton", symbol = { "ℓ" } }, ["lepton+"] = { link = "Antilepton", symbol = { "ℓ", TR = "+" } }, ["lepton+-"] = { link = "Lepton", symbol = { "ℓ", TR = "&plusmn;" } }, ["lepton-"] = { link = "Lepton", symbol = { "ℓ", TR = "&minus;" } }, ["lepton-+"] = { link = "Lepton", symbol = { "ℓ", TR = "&#x2213;" } }, ["lepton0"] = { link = "Neutrino", symbol = { "ℓ", TR = "0" } }, ["lepton antineutrino"] = { link = "Antineutrino", symbol = { "&nu;", anti = "yes", BR = "l" } }, ["lepton antineutrino0"] = { link = "Antineutrino", symbol = { "&nu;", anti = "yes", TR = "0", BR = "l" } }, ["lepton neutrino"] = { link = "Neutrino", symbol = { "&nu;", BR = "l" } }, ["lepton neutrino0"] = { link = "Neutrino", symbol = { "&nu;", TR = "0", BR = "l" } }, ["majorino"] = { link = "", symbol = { "J&#x0342;" } }, ["majoron"] = { link = "Majoron", symbol = { "J" } }, ["muon"] = { link = "Muon", symbol = { "&mu;", TR = "&minus;" } }, ["muon+"] = { link = "Antimuon", symbol = { "&mu;", TR = "+" } }, ["muon+-"] = { link = "Muon", symbol = { "&mu;", TR = "&plusmn;" } }, ["muon-"] = { link = "Muon", symbol = { "&mu;", TR = "&minus;" } }, ["muon-+"] = { link = "Muon", symbol = { "&mu;", TR = "&#x2213;" } }, ["muon antineutrino"] = { link = "Muon antineutrino", symbol = { "&nu;", anti = "yes", BR = "&mu;" } }, ["muon antineutrino0"] = { link = "Muon antineutrino", symbol = { "&nu;", anti = "yes", TR = "0", BR = "&mu;" } }, ["muon neutrino"] = { link = "Muon neutrino", symbol = { "&nu;", BR = "&mu;" } }, ["muon neutrino0"] = { link = "Muon neutrino", symbol = { "&nu;", TR = "0", BR = "&mu;" } }, ["neutralino"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0" } }, ["neutralino 1"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0", BR = "1" } }, ["neutralino 2"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0", BR = "2" } }, ["neutralino 3"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0", BR = "3" } }, ["neutralino 4"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0", BR = "4" } }, ["neutralino i"] = { link = "Neutralino", symbol = { "N&#x0342;", TR = "0", BR = "i" } }, ["neutrino"] = { link = "Neutrino", symbol = { "&nu;" } }, ["neutrino0"] = { link = "Neutrino", symbol = { "&nu;", 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;" } }, ["omega-"] = { link = "Omega baryon", symbol = { "&Omega;", TR = "&minus;" } }, ["omega meson"] = { link = "Omega meson", symbol = { "&omega;" } }, ["omega meson0"] = { link = "Omega meson", symbol = { "&omega;", 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 = { "&Phi;", TR = "&minus;&minus;" } }, ["phi0"] = { link = "Pentaquark", symbol = { "&Phi;", TR = "0" } }, ["phi meson"] = { link = "Phi meson", symbol = { "ϕ" } }, ["phi meson0"] = { link = "Phi meson", symbol = { "ϕ", TR = "0" } }, ["photino"] = { link = "Photino", symbol = { "&gamma;&#x0342;" } }, ["photon"] = { link = "Photon", symbol = { "&gamma;" } }, ["photon0"] = { link = "Photon", symbol = { "&gamma;", TR = "0" } }, ["pion"] = { link = "Pion", symbol = { "&pi;" } }, ["pion+"] = { link = "Pion", symbol = { "&pi;", TR = "+" } }, ["pion+-"] = { link = "Pion", symbol = { "&pi;", TR = "&plusmn;" } }, ["pion-"] = { link = "Pion", symbol = { "&pi;", TR = "&minus;" } }, ["pion-+"] = { link = "Pion", symbol = { "&pi;", TR = "&#x2213;" } }, ["pion0"] = { link = "Pion", symbol = { "&pi;", 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&#x0305;&#x0342;", BR = "R" } }, ["red quark"] = { link = "Color charge", symbol = { "q", BR = "R" } }, ["red squark"] = { link = "Color charge", symbol = { "q&#x0342;", BR = "R" } }, ["rho"] = { link = "Rho meson", symbol = { "&rho;" } }, ["rho+"] = { link = "Rho meson", symbol = { "&rho;", TR = "+" } }, ["rho+-"] = { link = "Rho meson", symbol = { "&rho;", TR = "&plusmn;" } }, ["rho-"] = { link = "Rho meson", symbol = { "&rho;", TR = "&minus;" } }, ["rho-+"] = { link = "Rho meson", symbol = { "&rho;", TR = "&#x2213;" } }, ["rho0"] = { link = "Rho meson", symbol = { "&rho;", 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&#x0342;", TR = "&minus;" } }, ["sigma"] = { link = "Sigma baryon", symbol = { "&Sigma;" } }, ["sigma*"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;" } }, ["sigma*+"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;+" } }, ["sigma*+-"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;&plusmn;" } }, ["sigma*-"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;&minus;" } }, ["sigma*-+"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;&#x2213;" } }, ["sigma*0"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&lowast;0" } }, ["sigma+"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "+" } }, ["sigma+-"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&plusmn;" } }, ["sigma-"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&minus;" } }, ["sigma-+"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "&#x2213;" } }, ["sigma0"] = { link = "Sigma baryon", symbol = { "&Sigma;", TR = "0" } }, ["slepton"] = { link = "Slepton", symbol = { "l&#x0342;" } }, ["squark"] = { link = "Squark", symbol = { "q&#x0342;" } }, ["strange antib"] = { link = "Strange B meson", symbol = { "B", anti = "yes", BR = "s" } }, ["strange antib*"] = { link = "Strange B meson", symbol = { "B", anti = "yes", TR = "&lowast;", BR = "s" } }, ["strange antib*0"] = { link = "Strange B meson", symbol = { "B", anti = "yes", TR = "&lowast;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&#x0305;&#x0342;" } }, ["strange antit"] = { link = "Strange T meson", symbol = { "T", anti = "yes", BR = "s" } }, ["strange antit*"] = { link = "Strange T meson", symbol = { "T", anti = "yes", TR = "&lowast;&plusmn;", BR = "s" } }, ["strange b"] = { link = "Strange B meson", symbol = { "B", BR = "s" } }, ["strange b*"] = { link = "Strange B meson", symbol = { "B", TR = "&lowast;", BR = "s" } }, ["strange b*0"] = { link = "Strange B meson", symbol = { "B", TR = "&lowast;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 = "&lowast;", BR = "s" } }, ["strange d*+"] = { link = "Strange D meson", symbol = { "D", TR = "&lowast;+", BR = "s" } }, ["strange d*+-"] = { link = "Strange D meson", symbol = { "D", TR = "&lowast;&plusmn;", BR = "s" } }, ["strange d*-"] = { link = "Strange D meson", symbol = { "D", TR = "&lowast;&minus;", BR = "s" } }, ["strange d*-+"] = { link = "Strange D meson", symbol = { "D", TR = "&lowast;&#x2213;", BR = "s" } }, ["strange d+"] = { link = "Strange D meson", symbol = { "D", TR = "+", BR = "s" } }, ["strange d+-"] = { link = "Strange D meson", symbol = { "D", TR = "&plusmn;", BR = "s" } }, ["strange d-"] = { link = "Strange D meson", symbol = { "D", TR = "&minus;", BR = "s" } }, ["strange d-+"] = { link = "Strange D meson", symbol = { "D", TR = "&#x2213;", BR = "s" } }, ["strange quark"] = { link = "Strange quark", symbol = { "s" } }, ["strange squark"] = { link = "Squark", symbol = { "s&#x0342;" } }, ["strange t"] = { link = "Strange T meson", symbol = { "T", BR = "s" } }, ["strange t*"] = { link = "Strange T meson", symbol = { "T", TR = "&lowast;", BR = "s" } }, ["strange t*+"] = { link = "Strange T meson", symbol = { "T", TR = "&lowast;+", BR = "s" } }, ["strange t*+-"] = { link = "Strange T meson", symbol = { "T", TR = "&lowast;&plusmn;", BR = "s" } }, ["strange t*-"] = { link = "Strange T meson", symbol = { "T", TR = "&lowast;&minus;", BR = "s" } }, ["strange t*-+"] = { link = "Strange T meson", symbol = { "T", TR = "&lowast;&#x2213;", BR = "s" } }, ["strange t+"] = { link = "Strange T meson", symbol = { "T", TR = "+", BR = "s" } }, ["strange t+-"] = { link = "Strange T meson", symbol = { "T", TR = "&plusmn;", BR = "s" } }, ["strange t-"] = { link = "Strange T meson", symbol = { "T", TR = "&minus;", BR = "s" } }, ["t"] = { link = "T meson", symbol = { "T" } }, ["t*"] = { link = "T meson", symbol = { "T", TR = "&lowast;" } }, ["t*+"] = { link = "T meson", symbol = { "T", TR = "&lowast;+" } }, ["t*+-"] = { link = "T meson", symbol = { "T", TR = "&lowast;&plusmn;" } }, ["t*-"] = { link = "T meson", symbol = { "T", TR = "&lowast;&minus;" } }, ["t*-+"] = { link = "T meson", symbol = { "T", TR = "&lowast;&#x2213;" } }, ["t*0"] = { link = "T meson", symbol = { "T", TR = "&lowast;0" } }, ["t+"] = { link = "T meson", symbol = { "T", TR = "+" } }, ["t+-"] = { link = "T meson", symbol = { "T", TR = "&plusmn;" } }, ["t-"] = { link = "T meson", symbol = { "T", TR = "&minus;" } }, ["t-+"] = { link = "T meson", symbol = { "T", TR = "&#x2213;" } }, ["t0"] = { link = "T meson", symbol = { "T", TR = "0" } }, ["tau"] = { link = "Tau (particle)", symbol = { "&tau;", TR = "&minus;" } }, ["tau+"] = { link = "Antitauon", symbol = { "&tau;", TR = "+" } }, ["tau+-"] = { link = "Tauon", symbol = { "&tau;", TR = "&plusmn;" } }, ["tau-"] = { link = "Tauon", symbol = { "&tau;", TR = "&minus;" } }, ["tau-+"] = { link = "Tauon", symbol = { "&tau;", TR = "&#x2213;" } }, ["tau antineutrino"] = { link = "Tauon antineutrino", symbol = { "&nu;", anti = "yes", BR = "&tau;" } }, ["tau antineutrino0"] = { link = "Tauon antineutrino", symbol = { "&nu;", anti = "yes", TR = "0", BR = "&tau;" } }, ["tau neutrino"] = { link = "Tau neutrino", symbol = { "&nu;", BR = "&tau;" } }, ["tau neutrino0"] = { link = "Tauon neutrino", symbol = { "&nu;", TR = "0", BR = "&tau;" } }, ["tauon"] = { link = "Tauon", symbol = { "&tau;", TR = "&minus;" } }, ["tauon+"] = { link = "Antitauon", symbol = { "&tau;", TR = "+" } }, ["tauon+-"] = { link = "Tauon", symbol = { "&tau;", TR = "&plusmn;" } }, ["tauon-"] = { link = "Tauon", symbol = { "&tau;", TR = "&minus;" } }, ["tauon-+"] = { link = "Tauon", symbol = { "&tau;", TR = "&#x2213;" } }, ["tauon antineutrino"] = { link = "Tauon antineutrino", symbol = { "&nu;", anti = "yes", BR = "&tau;" } }, ["tauon antineutrino0"] = { link = "Tauon antineutrino", symbol = { "&nu;", anti = "yes", TR = "0", BR = "&tau;" } }, ["tauon neutrino"] = { link = "Tauon neutrino", symbol = { "&nu;", BR = "&tau;" } }, ["tauon neutrino0"] = { link = "Tauon neutrino", symbol = { "&nu;", TR = "0", BR = "&tau;" } }, ["theta+"] = { link = "Pentaquark", symbol = { "&Theta;", TR = "+" } }, ["theta meson"] = { link = "Theta meson", symbol = { "&theta;" } }, ["top antiquark"] = { link = "Top antiquark", symbol = { "t", anti = "yes" } }, ["top antisquark"] = { link = "Squark", symbol = { "t&#x0305;&#x0342;" } }, ["top eta"] = { link = "Top eta meson", symbol = { "&eta;", BR = "t" } }, ["top eta0"] = { link = "Top eta meson", symbol = { "&eta;", TR = "0", BR = "t" } }, ["top eta prime"] = { link = "Top eta prime meson", symbol = { "&eta;&prime;", BR = "t" } }, ["top eta prime0"] = { link = "Top eta prime meson", symbol = { "&eta;&prime;", TR = "0", BR = "t" } }, ["top lambda"] = { link = "Top lambda baryon", symbol = { "&Lambda;", BR = "t" } }, ["top lambda*"] = { link = "Top lambda baryon", symbol = { "&Lambda;", TR = "&lowast;", BR = "t" } }, ["top lambda*+"] = { link = "Top lambda baryon", symbol = { "&Lambda;", TR = "&lowast;+", BR = "t" } }, ["top lambda+"] = { link = "Top lambda baryon", symbol = { "&Lambda;", TR = "+", BR = "t" } }, ["top omega"] = { link = "Top omega baryon", symbol = { "&Omega;", BR = "t" } }, ["top omega*"] = { link = "Top omega baryon", symbol = { "&Omega;", TR = "&lowast;", BR = "t" } }, ["top omega*0"] = { link = "Top omega baryon", symbol = { "&Omega;", TR = "&lowast;0", BR = "t" } }, ["top omega0"] = { link = "Top omega baryon", symbol = { "&Omega;", TR = "0", BR = "t" } }, ["top quark"] = { link = "Top quark", symbol = { "t" } }, ["top sigma"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "++", BR = "t" } }, ["top sigma*"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "&lowast;", BR = "t" } }, ["top sigma*+"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "&lowast;+", BR = "t" } }, ["top sigma*++"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "&lowast;++", BR = "t" } }, ["top sigma*0"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "&lowast;0", BR = "t" } }, ["top sigma+"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "+", BR = "t" } }, ["top sigma++"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "++", BR = "t" } }, ["top sigma0"] = { link = "Top sigma baryon", symbol = { "&Sigma;", TR = "0", BR = "t" } }, ["top squark"] = { link = "Squark", symbol = { "t&#x0342;" } }, ["top xi"] = { link = "Top xi baryon", symbol = { "&Xi;", BR = "t" } }, ["top xi'"] = { link = "", symbol = { "&Xi;&prime;", BR = "t" } }, ["top xi'+"] = { link = "", symbol = { "&Xi;&prime;", TR = "+", BR = "t" } }, ["top xi'0"] = { link = "", symbol = { "&Xi;&prime;", TR = "0", BR = "t" } }, ["top xi*"] = { link = "Top xi baryon", symbol = { "&Xi;", TR = "&lowast;", BR = "t" } }, ["top xi*+"] = { link = "Top xi baryon", symbol = { "&Xi;", TR = "&lowast;+", BR = "t" } }, ["top xi*0"] = { link = "Top xi baryon", symbol = { "&Xi;", TR = "&lowast;0", BR = "t" } }, ["top xi+"] = { link = "Top xi baryon", symbol = { "&Xi;", TR = "+", BR = "t" } }, ["top xi0"] = { link = "Top xi baryon", symbol = { "&Xi;", TR = "0", BR = "t" } }, ["triple bottom omega"] = { link = "Triple bottom omega baryon", symbol = { "&Omega;", BR = "bbb" } }, ["triple bottom omega-"] = { link = "Triple bottom omega baryon", symbol = { "&Omega;", TR = "&minus;", BR = "bbb" } }, ["triple charmed omega"] = { link = "Triple charmed omega baryon", symbol = { "&Omega;", BR = "ccc" } }, ["triple charmed omega++"] = { link = "Triple charmed omega baryon", symbol = { "&Omega;", TR = "++", BR = "ccc" } }, ["triple top omega"] = { link = "Triple top omega baryon", symbol = { "&Omega;", BR = "ttt" } }, ["triple top omega++"] = { link = "Triple top omega baryon", symbol = { "&Omega;", TR = "++", BR = "ttt" } }, ["tritium"] = { link = "", symbol = { "T" } }, ["up antiquark"] = { link = "Up antiquark", symbol = { "u", anti = "yes" } }, ["up antisquark"] = { link = "Squark", symbol = { "u&#x0305;&#x0342;" } }, ["up quark"] = { link = "Up quark", symbol = { "u" } }, ["up squark"] = { link = "Squark", symbol = { "u&#x0342;" } }, ["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 = "&plusmn;" } }, ["w boson-"] = { link = "W boson", symbol = { "W", TR = "&minus;" } }, ["w boson-+"] = { link = "W boson", symbol = { "W", TR = "∓" } }, ["w boson0"] = { link = "W boson", symbol = { "W", TR = "0" } }, ["wino"] = { link = "Wino (particle)", symbol = { "W&#x0342;" } }, ["wino+"] = { link = "Wino (particle)", symbol = { "W&#x0342;", TR = "+" } }, ["wino+-"] = { link = "Wino (particle)", symbol = { "W&#x0342;", TR = "&plusmn;" } }, ["wino-"] = { link = "Wino (particle)", symbol = { "W&#x0342;", TR = "&minus;" } }, ["wino-+"] = { link = "Wino (particle)", symbol = { "W&#x0342;", TR = "&#x2213;" } }, ["wino0"] = { link = "Wino (particle)", symbol = { "W&#x0342;", TR = "0" } }, ["x boson"] = { link = "X boson", symbol = { "X" } }, ["xi"] = { link = "Xi baryon", symbol = { "&Xi;" } }, ["xi*"] = { link = "Xi baryon", symbol = { "&Xi;", TR = "&lowast;" } }, ["xi*-"] = { link = "Xi baryon", symbol = { "&Xi;", TR = "&lowast;&minus;" } }, ["xi*0"] = { link = "Xi baryon", symbol = { "&Xi;", TR = "&lowast;0" } }, ["xi-"] = { link = "Xi baryon", symbol = { "&Xi;", TR = "&minus;" } }, ["xi0"] = { link = "Xi baryon", symbol = { "&Xi;", TR = "0" } }, ["xino"] = { link = "", symbol = { "X&#x0342;" } }, ["y boson"] = { link = "Y boson", symbol = { "Y" } }, ["yino"] = { link = "", symbol = { "Y&#x0342;" } }, ["z boson"] = { link = "Z boson", symbol = { "Z" } }, ["z boson0"] = { link = "Z boson", symbol = { "Z", TR = "0" } }, ["zino"] = { link = "Zino (particle)", symbol = { "Z&#x0342;" } }, ["zino0"] = { link = "Zino (particle)", symbol = { "Z&#x0342;", 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|}}}|&nbsp;–&nbsp;via&nbsp;{{{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|}}}|&nbsp;–&nbsp;via&nbsp;{{{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