Module:Ordinal
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
Summary
This module converts an integer value into a numeral followed by ordinal indicator. Intended to be used by:
The internationalization of the ordinal schemes can be found at Module:I18n/ordinal.
Using this module from templates
Ordinal
This function converts an integer value into a numeral followed by ordinal indicator. The output string might contain HTML tags unless you set nosup to 'y'. Unless debug is 'y', any error results in parameter 1 being echoed to the output. This reproduces the behavior of the original Ordinal template. If an error message is returned, the error message will contain code to categorize pages into Category:Errors reported by Module Ordinal.
Usage:
{{#invoke:Ordinal|Ordinal|1=|lang=|style=|gender=|nosup=|debug=}}
Parameters:
- 1 — Positive integer number.
- lang — language to be used.
- style — Presentation style. Different options for different languages. In English there is "style=d" adding -d suffixes to all numbers.
- gender — Gender is used by ordinals in several language (including French and Polish). Use 'm' for male, 'f' for female and 'n' for neuter.
- nosup — Set nosup to 'y' to display the ordinals without superscript.
- debug — Set debug to 'y' to output error messages.
Example:
{{#invoke:Ordinal|Ordinal|34}}
produces 34th
Using this module from Lua code
In order to use the functions in this module from another Lua module you first have to import this module.
Example:
local ordinal = require('Module:Ordinal')
_Ordinal
This function converts an integer value into a numeral followed by ordinal indicator. The output string might contain HTML tags unless you set nosup to true. Unless debug is true, any error results in the value being echoed to the output.
Usage:
ordinal_string = ordinal._Ordinal(value, lang, style, gender, nosup, debug)
Parameters:
- value — Numeral as a positive integer or string.
- lang — Language code as a string (e.g. 'en', 'de', etc.).
- style — Presentation style as a string (e.g. 'd', 'roman', etc.).
- gender — Gender as a string ('m', 'f', 'n'). Use empty string to leave gender unspecified.
- nosup — Boolean, set to true to force the ordinals to display without superscript.
- debug — Boolean, set to true to output error messages.
Example:
ordinal_string = ordinal._Ordinal(34, 'en', '', '', false, false)
See Also
Modules related to internationalization (i18n) of dates | ||||
---|---|---|---|---|
{| class="wikitable sortable" border="1" | ||||
Module Name | Uses Module | Used by Module | Used by Template | Comment |
Module:DateI18n | Module:I18n/date | Module:ISOdate | Template:Date | Create date string in any language |
Module:ISOdate | Module:DateI18n | Module:Complex date | Template:ISOdate & Template:ISOyear | Parse YYYY-MM-DD date string |
Module:Roman | Module:Complex date Module:Ordinal |
Template:Roman | Create Roman numerals | |
Module:Ordinal | Module:I18n/ordinal Module:Roman |
Module:Complex date | Template:Ordinal | Create Ordinal numerals |
Module:Complex date | Module:I18n/complex date Module:ISOdate Module:Roman Module:Ordinal |
Template:Other date (not deployed yet) | Create complex date phrases in many languages |
|}
Code
--[[
This template will add the appropriate ordinal suffix to a given integer.
Please do not modify this code without applying the changes first at Module:Ordinal/sandbox and testing
at Module:Ordinal/sandbox/testcases and Module talk:Ordinal/sandbox/testcases.
Authors and maintainers:
* User:RP88
]]
-- =======================================
-- === Dependencies ======================
-- =======================================
local i18n = require('Module:I18n/ordinal') -- get localized translations of ordinals
local yesno = require('Module:Yesno') -- boolean value interpretation
local formatnum = require('Module:Formatnum') -- number formatting
-- =======================================
-- === Private Functions =================
-- =======================================
------------------------------------------------------------------------------
-- code equivalent to https://commons.wikimedia.org/wiki/Template:LangSwitch
local function langSwitch(list,lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList,1,lang)
table.insert(langList,math.max(#langList,2),'default')
for i,language in ipairs(langList) do
if list[language] then
return list[language]
end
end
return nil
end
--[[
Helper function to generate superscripted content
]]
local function Superscript( str, superscript, nosup, period )
if superscript and (not nosup) and (str ~= '') then
return period .. '<sup>' .. str .. '</sup>'
else
return str
end
end
--[[
This function returns a string containing the input value formatted as a Roman numeral.
It works for values between 0 and 3999.
]]
local function Roman(value)
local d0, d1, d2, d3, i0, i1, i2, i3
d0 = { [0] = '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' }
d1 = { [0] = '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC' }
d2 = { [0] = '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM' }
d3 = { [0] = '', 'M', 'MM', 'MMM'}
local result = ''
if ((value >= 0) and (value < 4000)) then
i3 = math.floor(value / 1e3)
i2 = math.floor(value / 1e2) % 10
i1 = math.floor(value / 1e1) % 10
i0 = math.floor(value / 1e0) % 10
result = d3[i3] .. d2[i2] .. d1[i1] .. d0[i0]
end
return result
end
--[[
Helper function to call Formatnum.
]]
local function FormatNum( value, lang )
if lang == 'roman' then
return Roman(value)
else
return formatnum.formatNum(value, lang)
end
end
--[[
Helper function to add append a category to a message.
]]
local function output_cat( message, category )
return message .. '[[Category:' .. category .. ']]'
end
--[[
Helper function to handle error messages.
]]
local function output_error( error_str, value )
error_str = '<strong class="error"><span title="Error: ' .. error_str .. '">' .. value .. '</span></strong>'
return output_cat(error_str, 'Errors reported by Module Ordinal');
end
--[[
This function is the core functionality for adding the appropriate ordinal suffix to a given integer.
]]
local function OrdinalCore( value, lang, style, gender, nosup )
-- Just in case someone breaks the internationalization code, fix the english scheme
if i18n.SchemeFromLang['en'] == nil then
i18n.SchemeFromLang['en'] = 'en-scheme'
end
if i18n.Scheme['en-scheme'] == nil then
i18n.Scheme['en-scheme'] = {rules = 'skip-tens', superscript = true, suffix = 'th', suffix_1 = 'st', suffix_2 = 'nd', suffix_3 = 'rd'}
end
-- Add the default scheme (i.e. "<value>.")
if i18n.SchemeFromLang['default'] == nil then
i18n.SchemeFromLang['default'] = 'period-scheme'
end
if i18n.Scheme['period-scheme'] == nil then
i18n.Scheme['period-scheme'] = {rules = 'suffix', suffix = '.'}
end
-- which scheme should we use to format the ordinal value?
-- Use Fallback module to handle languages groups that map to a supported language
local schemeSpecifier = langSwitch(i18n.SchemeFromLang, lang)
-- Look up scheme based on scheme specifier (and possibly style)
local scheme = i18n.Scheme[schemeSpecifier .. '/' .. style] or i18n.Scheme[schemeSpecifier]
-- process scheme by applying rules identified by Scheme
local output = ''
local period = (scheme.period and '.') or ''
local rules = scheme.rules
if rules == 'skip-tens' then
local suffix
local mod100 = math.floor(math.abs(value)) % 100
if (mod100 >= 10) and (mod100 <= 19) then
suffix = scheme.suffix or ''
else
local mod10 = math.floor(math.abs(value)) % 10
suffix = scheme['suffix_'..mod10] or scheme.suffix or ''
end
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'suffix' then
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( scheme.suffix or '', scheme.superscript, nosup, period)
elseif rules == 'prefix' then
output = (scheme.prefix or '') .. FormatNum(value, scheme.formatlang or lang)
elseif rules == 'mod10-suffix' then
local index = math.floor(math.abs(value)) % 10
local suffix = scheme['suffix_'..index] or scheme.suffix or ''
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'gendered-suffix' then
local suffix = scheme['suffix_'..gender] or scheme.suffix or ''
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'gendered-suffix-one' then
local suffix
if value == 1 then
suffix = scheme['suffix_1_'..gender] or scheme['suffix_1'] or scheme.suffix or ''
else
suffix = scheme['suffix_'..gender] or scheme.suffix or ''
end
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'gendered-suffix-n' then
local suffix
if value <= 9 then
suffix = scheme['suffix_'..value..'_'..gender] or scheme['suffix_'..value] or scheme['suffix_'..gender] or scheme.suffix or ''
else
suffix = scheme['suffix_'..gender] or scheme.suffix or ''
end
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'suffix-one' then
local prefix, suffix
if value == 1 then
prefix = scheme['prefix_1'] or scheme.prefix or ''
suffix = scheme['suffix_1'] or scheme.suffix or ''
else
prefix = scheme.prefix or ''
suffix = scheme.suffix or ''
end
output = prefix .. FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'mod10-gendered-suffix-skip-tens' then
local suffix
local mod100 = math.floor(math.abs(value)) % 100
if (mod100 >= 10) and (mod100 <= 19) then
suffix = scheme['suffix_'..gender] or scheme.suffix or ''
else
local mod10 = math.floor(math.abs(value)) % 10
suffix = scheme['suffix_'..mod10..'_'..gender] or scheme['suffix_'..mod10] or scheme['suffix_'..gender] or scheme.suffix or ''
end
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
elseif rules == 'uk-rules' then
local suffix
local mod100 = math.floor(math.abs(value)) % 100
local mod1000 = math.floor(math.abs(value)) % 1000
if (mod1000 == 0) then
suffix = scheme['suffix_1000_'..gender] or scheme.suffix or ''
elseif (mod100 == 40) then
suffix = scheme['suffix_40_'..gender] or scheme.suffix or ''
elseif (mod100 >= 10) and (mod100 <= 19) then
suffix = scheme['suffix_'..gender] or scheme.suffix or ''
else
local mod10 = math.floor(math.abs(value)) % 10
suffix = scheme['suffix_'..mod10..'_'..gender] or scheme['suffix_'..mod10] or scheme['suffix_'..gender] or scheme.suffix or ''
end
output = FormatNum(value, scheme.formatlang or lang) .. Superscript( suffix, scheme.superscript, nosup, period)
else
output = FormatNum(value, lang)
end
return output
end
-- =======================================
-- === Public Functions ==================
-- =======================================
local p = {}
--[[
Ordinal
This function converts an integer value into a numeral followed by ordinal indicator. The output string might
contain HTML tags unless you set nosup=y.
Usage:
{{#invoke:Ordinal|Ordinal|1=|lang=|style=|gender=|nosup=|debug=}}
{{#invoke:Ordinal|Ordinal}} - uses the caller's parameters
Parameters
1: Positive integer number.
lang: language
style: Presentation style. Different options for different languages. In English there is "style=d" adding -d suffixes to all numbers.
gender: Gender is used in French and Polish language versions. Genders: m for male, f for female and n for neuter.
nosup: Set nosup=y to display the ordinals without superscript.
debug: Set debug=y to output error messages.
Error Handling:
Unless debug=y, any error results in parameter 1 being echoed to the output. This reproduces the behavior of the original Ordinal template.
]]
function p.Ordinal( frame )
-- if no argument provided than check parent template/module args
local args = frame.args
if args[1]==nil then
args = frame:getParent().args
end
-- if we don't have a specified language, attempt to use the user's language
local lang = args.lang
if not lang or lang == '' or not mw.language.isValidCode( lang ) then
lang = frame:preprocess('{{int:lang}}')
end
local nosup = yesno(args["nosup"] or '', false) -- nosup can be true or false
local debugging = yesno(args["debug"], false) -- debugging can be nil, true, or false
-- also enable debugging if debug is unspecified, and "nosup" is false
debugging = debugging or ((debugging == nil) and not nosup)
local output = p._Ordinal(
args[1], -- positive integer number
lang, -- language
args["style"], -- allows to set presentation style
args["gender"], -- allows to specify gender (m, f, or n)
nosup, -- set nosup to "y" to suppress superscripts
debugging -- Set debug=y to output error messages
)
-- Add maintenance category
if (i18n.SchemeFromLang[lang] == nil) and debugging then
output = output_cat(output, 'Pages with calls to Module Ordinal using an unsupported language')
end
return output
end
--[[
This function will add the appropriate ordinal suffix to a given integer.
Parameters
input: Numeral as a positive integer or string.
lang: Language code as a string (e.g. 'en', 'de', etc.).
style: Presentation style as a string (e.g. 'd', 'roman', etc.).
gender: Gender as a string ('m', 'f', 'n'). Use empty string '' to leave gender unspecified.
nosup: Boolean, set to true to force the ordinals to display without superscript.
debug: Boolean, set to true to output error messages.
Error Handling:
Unless debug is true, any error results in value being echoed to the output.
]]
function p._Ordinal( input, lang, style, gender, nosup, debugging )
local output = input
if input then
local value = tonumber(input)
if value and (value > 0) then
-- Normalize style, the style 'roman year' is an alias for 'roman'
style = string.lower(style or '')
if style == 'roman year' then
style = 'roman'
end
-- Normalize gender parameter
gender = string.lower(gender or '')
if (gender ~= 'm') and (gender ~= 'f') and (gender ~= 'n') then
gender = ''
end
-- if no language is specified, default to english (caller might want to get user's language)
if not lang or lang == '' then
lang = 'en';
end
output = OrdinalCore( value, lang, style, gender, nosup )
else
if debugging then
output = output_error( "not a number", input )
end
end
else
if debugging then
output = output_error( "not a number", '' )
end
end
return output
end
return p