Module:Wordify
This module provides a number-formatting function. This function can be used from #invoke or from other Lua modules.
This module is used by {{FXConvert}}
Use from other Lua modules
To use the module from normal wiki pages, no special preparation is needed. If you are using the module from another Lua module, first you need to load it, like this:
<syntaxhighlight lang="lua"> local mf = require('Module:Wordify') </syntaxhighlight>
(The mf
variable stands for Module wordiFy; you can choose something more descriptive if you prefer.)
Most functions in the module have a version for Lua and a version for #invoke. It is possible to use the #invoke functions from other Lua modules, but using the Lua functions has the advantage that you do not need to access a Lua frame object. Lua functions are preceded by _
, whereas #invoke functions are not.
main
{{#invoke:Wordify|main|x|prec=|lk=|numsys=|lang=|script=|state=|case=|class=|possessed=|person=|plural=|exclude=|simplify=}}
<syntaxhighlight lang="lua"> mf._wordify(x, prec, lk, numsys, lang, script, state, case, class, possessed, person, plural, exclude, simplify) </syntaxhighlight>
Simplify a number x using a word denoting an order of magnitude.
numsys
can beshort
(short scale, the default),ind
(Indian scale), orlong
(long scale)prec
is the digits of precision to output- if
lk
is true, the words will be linked to an explanation lang
allows to specify the locale for formatting and wordingscript
allows to specify a script if the language supports more than onestate
can be indefinite, definite, or constructcase
allows to specify a grammatical caseclass
allows to specify a noun class- if
possessed
is true, it designates that there are multiple possessed objects person
designates the person (1
,2
,3
)- if
plural
is true, it indicates that the person is plural exclude
indicates the persons to exclude (2
,3
)- if
simplify
is true, only the order of magnitude words will be output
Notes
- The function is currently not applying declensions beyond the base case for some of the supported languages.
- If a case that does not exist in a certain language is requested, the function may give an error or just return the base result.
- The function understands case arguments that are not a word in a single language, like "akkusative".
Examples
Scales, links, scripts, capitalization
{{#invoke:Wordify|main|9876000}}
displays 10 million.{{#invoke:Wordify|main|9876000|lk=yes|prec=2}}
displays 9.88 million.{{#invoke:Wordify|main|9876000|numsys=ind}}
displays 1 crore.{{#invoke:Wordify|main|9876000|numsys=ind|lk=yes|prec=2}}
displays 98.76 lakh.{{#invoke:Wordify|main|1000000000000}}
displays 1 trillion.{{#invoke:Wordify|main|1000000000000|numsys=long}}
displays 1 billion.{{#invoke:Wordify|main|1000000000000|numsys=ind}}
displays 1 lakh crore.{{#invoke:Wordify|main|100000000000000}}
displays 100 trillion.{{#invoke:Wordify|main|100000000000000|numsys=ind}}
displays 1 crore crore.{{#invoke:Wordify|main|100000000000000|lang=de}}
displays 100 Billionen.{{#invoke:Wordify|main|100000000000000|lang=ko}}
displays 100조.{{#invoke:Wordify|main|100000000000000|lang=ko|script=hanja}}
displays 100兆.
State, case
{{#invoke:Wordify|main|1000000000000|lang=sv}}
displays 1 biljon.{{#invoke:Wordify|main|1000000000000|lang=sv|state=d}}
displays 1 biljonen.{{#invoke:Wordify|main|1000000000000|lang=sv|case=g}}
displays 1 biljons.{{#invoke:Wordify|main|1000000000000|lang=sv|state=d|case=g}}
displays 1 biljonens.{{#invoke:Wordify|main|100000000000000|lang=sv}}
displays 100 biljoner.{{#invoke:Wordify|main|100000000000000|lang=sv|state=d}}
displays 100 biljonerna.{{#invoke:Wordify|main|100000000000000|lang=sv|case=g}}
displays 100 biljoners.{{#invoke:Wordify|main|100000000000000|lang=sv|state=d|case=g}}
displays 100 biljonernas.
Simplification
{{#invoke:Wordify|main|1000000000|lang=fr|lk=yes}}
displays 1 milliard.
{{#invoke:Wordify|main|1000000000|lang=fi}}
displays tuhat miljoonaa.{{#invoke:Wordify|main|1000000000|lang=fi|simplify=yes}}
displays tuhat miljoonaa.{{#invoke:Wordify|main|10000000000|lang=fi}}
displays 10 tuhatta miljoonaa.{{#invoke:Wordify|main|10000000000|lang=fi|simplify=yes}}
displays tuhat miljoonaa.{{#invoke:Wordify|main|1000000000000|lang=fi}}
displays 1 biljoona.{{#invoke:Wordify|main|1000000000000|lang=fi|simplify=yes}}
displays biljoona.{{#invoke:Wordify|main|10000000000000|lang=fi}}
displays 10 biljoonaa.{{#invoke:Wordify|main|10000000000000|lang=fi|simplify=yes}}
displays biljoonat.
Noun class agreement
{{#invoke:Wordify|main|2000000|lang=la}}
displays 2 millionia.{{#invoke:Wordify|main|2000000|lang=la|class=n}}
displays 2 millionia.{{#invoke:Wordify|main|2000000|lang=la|class=m}}
displays 2 milliones.{{#invoke:Wordify|main|2000000|lang=la|class=f}}
displays 2 milliones.
Slavic numerals
{{#invoke:Wordify|main|1000000|lang=sl}}
displays 1 milijon.{{#invoke:Wordify|main|2000000|lang=sl}}
displays 2 milijona.{{#invoke:Wordify|main|3000000|lang=sl}}
displays 3 milijone.{{#invoke:Wordify|main|4000000|lang=sl}}
displays 4 milijone.{{#invoke:Wordify|main|5000000|lang=sl}}
displays 5 milijonov.{{#invoke:Wordify|main|10000000|lang=sl}}
displays 10 milijonov.{{#invoke:Wordify|main|1000000000|lang=sl}}
displays 1 milijarda.{{#invoke:Wordify|main|2000000000|lang=sl}}
displays 2 milijardi.{{#invoke:Wordify|main|3000000000|lang=sl}}
displays 3 milijarde.{{#invoke:Wordify|main|4000000000|lang=sl}}
displays 4 milijarde.{{#invoke:Wordify|main|5000000000|lang=sl}}
displays 5 milijard.{{#invoke:Wordify|main|10000000000|lang=sl}}
displays 10 milijard.{{#invoke:Wordify|main|2500000|lang=sl|prec=1}}
displays 2,5 milijona.{{#invoke:Wordify|main|2500000000|lang=sl|prec=1}}
displays 2,5 milijarde.
{{#invoke:Wordify|main|1000000|lang=pl}}
displays 1 milion.{{#invoke:Wordify|main|2000000|lang=pl}}
displays 2 miliony.{{#invoke:Wordify|main|3000000|lang=pl}}
displays 3 miliony.{{#invoke:Wordify|main|4000000|lang=pl}}
displays 4 miliony.{{#invoke:Wordify|main|5000000|lang=pl}}
displays 5 milionów.{{#invoke:Wordify|main|11000000|lang=pl}}
displays 11 milionów.{{#invoke:Wordify|main|12000000|lang=pl}}
displays 12 milionów.{{#invoke:Wordify|main|13000000|lang=pl}}
displays 13 milionów.{{#invoke:Wordify|main|14000000|lang=pl}}
displays 14 milionów.{{#invoke:Wordify|main|15000000|lang=pl}}
displays 15 milionów.{{#invoke:Wordify|main|21000000|lang=pl}}
displays 21 milionów.{{#invoke:Wordify|main|22000000|lang=pl}}
displays 22 miliony.{{#invoke:Wordify|main|23000000|lang=pl}}
displays 23 miliony.{{#invoke:Wordify|main|24000000|lang=pl}}
displays 24 miliony.{{#invoke:Wordify|main|25000000|lang=pl}}
displays 25 milionów.{{#invoke:Wordify|main|2500000|lang=pl|prec=1}}
displays 2,5 miliona.{{#invoke:Wordify|main|2500000000|lang=pl|prec=1}}
displays 2,5 miliarda.
Possessive cases
{{#invoke:Wordify|main|1000000|case=possessive}}
displays 1 million's.{{#invoke:Wordify|main|10000000|case=possessive}}
displays 10 million's.{{#invoke:Wordify|main|1000000|case=possessive|simplify=yes}}
displays million's.{{#invoke:Wordify|main|10000000|case=possessive|simplify=yes}}
displays millions'.{{#invoke:Wordify|main|1000000|lang=hu|case=possessi}}
displays 1 millióé.{{#invoke:Wordify|main|2000000|lang=hu|case=possessi}}
displays 2 millióké.{{#invoke:Wordify|main|1000000000|lang=hu|case=possessi}}
displays 1 milliárdé.{{#invoke:Wordify|main|2000000000|lang=hu|case=possessi}}
displays 2 milliárdoké.{{#invoke:Wordify|main|1000000|lang=hu|case=possessi|possessed=true}}
displays 1 millióéi.{{#invoke:Wordify|main|2000000|lang=hu|case=possessi|possessed=true}}
displays 2 milliókéi.{{#invoke:Wordify|main|1000000000|lang=hu|case=possessi|possessed=true}}
displays 1 milliárdéi.{{#invoke:Wordify|main|2000000000|lang=hu|case=possessi|possessed=true}}
displays 2 milliárdokéi.
Possessive forms
{{#invoke:Wordify|main|1000000|lang=hu|person=1}}
displays 1 millióm.{{#invoke:Wordify|main|2000000|lang=hu|person=1}}
displays 2 millióim.{{#invoke:Wordify|main|1000000000|lang=hu|person=1}}
displays 1 milliárdom.{{#invoke:Wordify|main|2000000000|lang=hu|person=1}}
displays 2 milliárdaim.{{#invoke:Wordify|main|1000000|lang=hu|person=2}}
displays 1 milliód.{{#invoke:Wordify|main|2000000|lang=hu|person=2}}
displays 2 millióid.{{#invoke:Wordify|main|1000000000|lang=hu|person=2}}
displays 1 milliárdod.{{#invoke:Wordify|main|2000000000|lang=hu|person=2}}
displays 2 milliárdjaid.{{#invoke:Wordify|main|1000000|lang=hu|person=3}}
displays 1 milliója.{{#invoke:Wordify|main|2000000|lang=hu|person=3}}
displays 2 milliói.{{#invoke:Wordify|main|1000000000|lang=hu|person=3}}
displays 1 milliárdja.{{#invoke:Wordify|main|2000000000|lang=hu|person=3}}
displays 2 milliárdjai.{{#invoke:Wordify|main|1000000|lang=hu|person=1|plural=yes}}
displays 1 milliónk.{{#invoke:Wordify|main|2000000|lang=hu|person=1|plural=yes}}
displays 2 millióink.{{#invoke:Wordify|main|1000000000|lang=hu|person=1|plural=yes}}
displays 1 milliárdunk.{{#invoke:Wordify|main|2000000000|lang=hu|person=1|plural=yes}}
displays 2 millióink.{{#invoke:Wordify|main|1000000|lang=hu|person=2|plural=yes}}
displays 1 milliótok.{{#invoke:Wordify|main|2000000|lang=hu|person=2|plural=yes}}
displays 2 millióitok.{{#invoke:Wordify|main|1000000000|lang=hu|person=2|plural=yes}}
displays 1 milliárdotok.{{#invoke:Wordify|main|2000000000|lang=hu|person=2|plural=yes}}
displays 2 milliárdjaitok.{{#invoke:Wordify|main|1000000|lang=hu|person=3|plural=yes}}
displays 1 milliójuk.{{#invoke:Wordify|main|2000000|lang=hu|person=3|plural=yes}}
displays 2 millióik.{{#invoke:Wordify|main|1000000000|lang=hu|person=3|plural=yes}}
displays 1 milliárdjuk.{{#invoke:Wordify|main|2000000000|lang=hu|person=3|plural=yes}}
displays 2 milliárdjaik.
Support for additional languages
New languages can be added by creating a corresponding object.
The possessive
field conforms to the following grammar:
<syntaxhighlight lang="bnf"> <possessive-rules> ::= "{}" | <string> | "{" <possessor-cases> "}" | <possessive-function> <possessor-cases> ::= <singular-possessors> | <singular-posessors> "," <plural-posessors> <singular-possessors> ::= "{" <singular-possessor-cases> "}" <singular-posessor-cases> := <simple-posessor-case> | <simple-possessor-case> "," <singular-possessor-cases> <simple-posessor-case> := "{ {" <singular-possessed> "," <plural-possessed> "} }" | <possessor-function> <singular-possessed> ::= <possessed> <plural-possessed> ::= <possessed> <possessed> ::= <string> | "{" <possessed-cases> "}" | <possessed-function> <plural-posessors> ::= "{" <plural-possessor-cases> "}" <plural-possessor-cases> := <plural-posessor-case> | <plural-possessor-case> "," <plural-possessor-cases> <plural-possessor-case> ::= "{" <clusivity-cases> "}" <clusivity-cases> ::= <simple-possessor-case> | <simple-possessor-case> "," <clusivity-cases> </syntaxhighlight>
The inflection
field conforms to the following grammar:
<syntaxhighlight lang="bnf"> <inflection-rules> ::= "{}" | "{" <stem-statement> "}" | "{" <number-cases> "}" | "{" <stem-statement> "," <number-cases> "}" <stem-statement> ::= "stem" "=" <stem-function> <number-cases> ::= <number-case> | <number-case> "," <number-cases> <number-case> ::= <number-index> <number-rule> <number-index> ::= "" | "[" <integer> "]" "=" | | "[" "fraction" "]" "=" <number-rule> ::= <string> | <ending-cases-list> | <state-cases> | <number-function> <ending-cases-list> ::= "{" <ending-cases> "}" <ending-cases> ::= <ending-case> | <ending-case> "," <ending-cases> <ending-case> ::= <string-index> "=" <ending-rule> <ending-rule> ::= <string> | <class-cases-list> | <state-cases> | <ending-function> <class-cases-list> ::= "{" <class-cases> "}" <class-cases> ::= <class-case> | <class-case> "," <class-cases> <class-case> ::= <string-index> "=" <class-rule> <class-rule> ::= <string> | <grammatical-cases-list> | <state-cases> | <class-function> <state-cases> ::= "{" <indefinite-rule> "}" | "{" <indefinite-rule> "," <definite-rule> "}" | "{" <indefinite-rule> "," <definite-rule> "," <construct-rule> "}" <indefinite-rule> ::= <state-rule> <definite-rule> ::= <state-rule> <construct-rule> ::= <state-rule> <state-rule> ::= <string> | <grammatical-cases-list> | <state-function> <grammatical-cases-list> ::= "{" <grammatical-cases> "}" <grammatical-cases> ::= <grammatical-case> | <grammatical-case> "," <grammatical-cases> <grammatical-case> ::= <string-index> "=" <grammatical-rule> <grammatical-rule> ::= <string> | <simple-class-cases-list> | "{" <possessed-cases> "}" | <grammatical-function> <simple-class-cases-list> ::= "{" <simple-class-cases> "}" <simple-class-cases> ::= <simple-class-case> | <simple-class-case> "," <simple-class-cases> <simple-class-case> ::= <string-index> "=" <simple-class-rule> <simple-class-rule> ::= <string> | <simple-ending-cases-list> | <class-function> <simple-ending-cases-list> ::= "{" <simple-ending-cases> "}" <simple-ending-cases> ::= <simple-ending-case> | <simple-ending-case> "," <simple-ending-cases> <simple-ending-case> ::= <string-index> "=" <simple-ending-rule> <simple-ending-rule> ::= <string> | <ending-function> </syntaxhighlight>
Common elements:
<syntaxhighlight lang="bnf"> <possessed-cases> ::= <possessed-case> | <possessed-case> "," <possessed-cases> <possessed-case> ::= <string-index> "=" <possessed-rule> <string-index> ::= <identifier> | "[" <string> "]" <possessed-rule> ::= <string> | <possessed-function> </syntaxhighlight>
The elements <identifier>, <string>, and <integer> are as defined for the Lua language and those ending in -function
are Lua functions with signatures that can be found in the code.
A certain language might not be supported by the current algorithm, in this case it should be extended for the new kind.
See also
- Long and short scales
- Indian numbering system
- Orders of magnitude (numbers)
- Writing system
- Clusivity
- Grammatical gender
- Definiteness
- Grammatical case
- Possessive
- Wiktionary
- Backus–Naur form
Template:Language grammars Template:Math templates
local mf = require('Module:Formatnum') local yesno = require('Module:Yesno') local p = {} -- Holds functions to be returned from #invoke, and functions to make available to other Lua modules. --[[ Helper functions used to avoid redundant code. ]] local function err(msg) -- Generates wikitext error messages. return mw.ustring.format('<strong class="error">Formatting error: %s</strong>', msg) end local function getArgs(frame) local args = {} for key, value in pairs(frame:getParent().args) do args[key] = value end for key, value in pairs(frame.args) do args[key] = value end return args end local function getCurrentLanguage() local result = mw.title.getCurrentTitle().pageLanguage if not result then result = mw.language.getContentLanguage():getCode() end return result end local function _round(value, precision) local rescale = math.pow(10, precision or 0); return math.floor(value * rescale + 0.5) / rescale; end --[[ ------------------------------------------------------------------------------------ -- tableLength -- -- This function returns the number of keys in a table. ------------------------------------------------------------------------------------ --]] local function tableLength(t) local count = 0 for _ in pairs(t) do count = count + 1 end return count end --[[ ------------------------------------------------------------------------------------ -- singleEntry -- -- If a table contains a single entry, it returns the key and value, otherwise nil. ------------------------------------------------------------------------------------ --]] local function singleEntry(t) local count = 0 local resultk, resultv for k, v in pairs(t) do if count > 0 then return nil else count = count + 1 resultk = k resultv = v end end if count == 1 then return resultk, resultv else return nil end end --[[ ------------------------------------------------------------------------------------ -- isPositiveInteger -- -- This function returns true if the given value is a positive integer, and false -- if not. Although it doesn't operate on tables, it is included here as it is -- useful for determining whether a given table key is in the array part or the -- hash part of a table. ------------------------------------------------------------------------------------ --]] local function isPositiveInteger(v) return type(v) == 'number' and v >= 1 and math.floor(v) == v and v < math.huge end --[[ ------------------------------------------------------------------------------------ -- reverseNumKeys -- -- This takes a table and returns an array containing the numbers of any numerical -- keys that have non-nil values, sorted in reverse numerical order. ------------------------------------------------------------------------------------ --]] local function reverseNumKeys(t) local nums = {} local ispi = isPositiveInteger for k, _ in pairs(t) do if ispi(k) then nums[#nums + 1] = k end end table.sort(nums, function(a, b) return a > b end) return nums end --[[ ------------------------------------------------------------------------------------ -- reverseSparseIpairs -- -- This is a reverse iterator for sparse arrays. It can be used like a reversed ipairs, but can -- handle nil values. ------------------------------------------------------------------------------------ --]] local function reverseSparseIpairs(t) local nums = reverseNumKeys(t) local i = 0 local lim = #nums return function () i = i + 1 if i <= lim then local key = nums[i] return key, t[key] else return nil, nil end end end --[[ ------------------------------------------------------------------------------------ -- addMultipleKeys -- -- This takes a table and adds all the values in an array as keys to a single object ------------------------------------------------------------------------------------ --]] local function addMultipleKeys(arr, keys, val) if keys then for _, v in ipairs(keys) do arr[v] = val end end end --[[ ------------------------------------------------------------------------------------ -- deepReverseTable -- -- This takes a table and returns a new table where the values are keys and vice versa ------------------------------------------------------------------------------------ --]] local function deepReverseTable(t) local rev = {} for k, v in pairs(t) do if type(v) == 'table' then addMultipleKeys(rev, v, k) else rev[v] = k end end return rev end --[[ ------------------------------------------------------------------------------------ -- makeLengthTable -- -- This takes a table and returns a new table where keys are the lengths of the string in each subtable ------------------------------------------------------------------------------------ --]] local function makeLengthTable(t) local result = {} local ulen = mw.ustring.len local ins = table.insert for _, v in pairs(t) do local len = ulen(v) local subr = result[len] if subr then ins(subr, v) else result[len] = { v } end end return result end --[[ ------------------------------------------------------------------------------------ -- Object -- -- Root object ------------------------------------------------------------------------------------ --]] local Object = {} function Object:new (o) o = o or {} -- create object if user does not provide one o.super = self setmetatable(o, self) self.__index = self return o end function Object:tableInherit(name, k) repeat local field = rawget(self, name) local result = field and field[k] if result then return result else self = rawget(self, 'super') end until not self return nil end local parameters = {} local parameter_lookup = {} local Parameter = Object:new{ defaults = {} } function Parameter:new (o) local result = self.super.new(self, o) result.lookup = deepReverseTable(result.values) local code = rawget(result, 'code') if code and code ~= '' then parameters[code] = result end parameter_lookup[code] = code addMultipleKeys(parameter_lookup, result.names, code) return result end function Parameter:default(lang, arg, arg2) if arg and arg ~= '' then return arg:lower() else if lang and lang ~= '' then local d = rawget(self, 'defaults') if d then local l = d[lang] if type(l) == 'table' then l = l[arg2] end if l then return l end end end local fallback = rawget(self, 'fallback') if type(fallback) == 'function' then return fallback() else return fallback end end end function Parameter:get(arg) local result = rawget(self, 'lookup')[arg] if result then return result else return nil end end function Parameter:getArgument(args) local code = self.code if code and code ~= '' then local result = args[code] if result then return result else local names = rawget(self, 'names') if names then for _, v in pairs(names) do result = args[v] if result then return result end end end end end return nil end local function setupParameters() for k, v in pairs(parameters) do parameter_lookup[k] = k local names = rawget(v, 'names') addMultipleKeys(parameter_lookup, names, k) end end local function translateParameters(args) local result = {} for k, v in pairs(args) do local c if tonumber(k) then c = k else c = parameter_lookup[k] end --[[ if not c then return err('Illegal parameter: " .. k) end ]] if c then result[c] = v end end return result end --[[ wordify Usage: {{#invoke:Wordify | main | x | prec= | lk= | numsys= | lang= | state= | case= | class= | simplify= }} --]] function p.main(frame) local args = getArgs(frame) local translated = translateParameters(args) if type(translated) ~= 'table' then return err('Illegal argument: ' .. translated) end local x = args[1] local numsys = parameters.numsys:getArgument(translated) local prec = parameters.prec:getArgument(translated) local lk = parameters.lk:getArgument(translated) local lang = parameters.lang:getArgument(translated) local script = parameters.script:getArgument(translated) local state = parameters.state:getArgument(translated) local case = parameters.case:getArgument(translated) local class = parameters.class:getArgument(translated) local possessed = parameters.possessed:getArgument(translated) local person = parameters.person:getArgument(translated) local plural = parameters.plural:getArgument(translated) local exclude = parameters.exclude:getArgument(translated) local simplify = parameters.simplify:getArgument(translated) return p._wordify(x, prec, yesno(lk), numsys, lang, script, state, case, class, yesno(possessed), tonumber(person), yesno(plural), tonumber(exclude), yesno(simplify)) end local language = Parameter:new{ code = 'lang', names = { 'language' }, values = {}, fallback = getCurrentLanguage } local precision = Parameter:new{ code = 'prec', names = { 'precision' }, values = {}, fallback = 0 } local link = Parameter:new{ code = 'lk', names = { 'link' }, values = {}, fallback = false } local number_systems = Parameter:new{ code = 'numsys', names = { 'scale' }, values = { indian = { 'indian', 'ind' }, myriad = { 'myriad' }, long = { 'long', 'fra' }, short = {'short', 'usa' } }, defaults = {}, fallback = 'long' } local possessed = Parameter:new{ code = 'possessed', values = {}, fallback = false } local person = Parameter:new{ code = 'person', values = {}, fallback = false } local plural = Parameter:new{ code = 'plural', values = {}, fallback = false } local exclude = Parameter:new{ code = 'exclude', values = {}, fallback = false } local simplify = Parameter:new{ code = 'simplify', values = {}, fallback = false } local scripts = Parameter:new{ code = 'script', values = { arab = { 'arabic' }, aran = { 'nastaliq' }, armn = { 'armenian' }, bali = { 'balinese' }, beng = { 'bengali' }, bugi = { 'buginese', 'lontara' }, cans = { 'cans' }, cher = { 'cherokee' }, cyrl = { 'cyrilic' }, deva = { 'devanagari' }, ethi = { 'ethiopic', "ge'ez" }, geor = { 'georgian' }, geok = { 'khutsuri' }, grek = { 'greek' }, gujr = { 'gujarati' }, guru = { 'gurmunkhi' }, hang = { 'hangul' }, hani = { 'hanzi', 'kanji', 'hanja' }, hans = { 'han simplified', 'simplified han', 'simplified chinese', 'chinese simplified' }, hant = { 'han traditional', 'traditional han', 'traditional chinese', 'chinese traditional' }, hebr = { 'hebrew' }, java = { 'javanese' }, khmr = { 'khmer' }, knda = { 'kannada' }, laoo = { 'lao'}, latn = { 'latin' }, mong = { 'mongolian' }, mlym = { 'malayalam' }, mymr = { 'myanmar', 'burmese' }, orya = { 'oriya', 'odia' }, rohg = { 'hanifi rohingya' }, sinh = { 'sinhala' }, sund = { 'sundanese' }, syrc = { 'syriac' }, syre = { 'ʾesṭrangēlā' }, syrj = { 'western syriac' }, syrn = { 'eastern syriac' }, taml = { 'tamil'}, tavt = { 'tai viet' }, telu = { 'telugu' }, tfng = { 'tifinagh' }, tglg = { 'tagalog' }, thaa = { 'thaana' }, thai = { 'thai' }, tibt = { 'tibetan' }, yiii = { 'yi' } }, defaults = {}, fallback = 'latin' } local states = Parameter:new{ code = 'state', values = { c = { 'construct' }, d = { 'definite' }, i = { 'indefinite' } }, fallback = 'indefinite' } local classes = Parameter:new{ code = 'class', values = { an = { 'animate' }, ['cl-1'] = { 'class 1', 'class i' }, ['cl-1a'] = { 'class 1a' }, ['cl-2'] = { 'class 2', 'class ii' }, ['cl-2a'] = { 'class 2a' }, ['cl-3'] = { 'class 3', 'class iii' }, ['cl-4'] = { 'class 4', 'class iv' }, ['cl-5'] = { 'class 5', 'class v' }, ['cl-6'] = { 'class 6', 'class vi' }, ['cl-7'] = { 'class 7', 'class vii' }, ['cl-8'] = { 'class 8', 'class viii' }, ['cl-9'] = { 'class 9', 'class ix' }, ['cl-10'] = { 'class 10', 'class x' }, co = { 'common' }, f = { 'feminine' }, ['in'] = { 'inanimate' }, m = { 'masculine' }, ['m-an'] = { 'masculine animate' }, ['m-i'] = { 'masculine inanimate' }, n = { 'neuter' }, ve = { 'vegetable' }, x = { 'x' }, y = { 'y' } }, fallback = 'neuter', class_strings = { 'kategória', 'κατηγορία', 'osztály', 'flokkur', 'classe', 'clâsse', 'klasse', 'luokka', 'darasa', 'razred', 'разред', 'разряд', 'ประเภท', 'clase', 'klase', 'klaso', 'klasa', 'clasă', 'class', 'klass', 'kelas', 'aicme', 'sinif', 'třída', 'είδος', 'класс', 'класа', 'קלאַס', 'พรรค์', 'မျိုး', 'صِنْف', 'صَنْف', 'clas', 'klas', 'klad', 'rühm', 'τάξη', 'клас', 'しゅるい', 'ชนิด', 'ຊະນິດ', 'کلاس', 'դաս', 'صنف', 'رده', 'cl', '種類', '种类', '類', '类' } } classes.class_lengths = makeLengthTable(classes.class_strings) function classes:get(class) local function matchSimilarClasses(class, classlen, pos, t, len, lr) local function makeNumberedClass(class, affixlen) local rest if lr then rest = mw.ustring.sub(class, affixlen+1) else rest = mw.ustring.sub(class, 1, -(affixlen+1)) if mw.ustring.sub(rest, -1, -1) == "." then rest = mw.ustring.sub(rest, 1, -2) -- 1. Klasse end end local num = tonumber(rest) if num then return 'cl-' .. tostring(num) else return nil end end local len1 = len + 1 if classlen > len1 then local cand if lr then cand = mw.ustring.sub(class, 1, len) else cand = mw.ustring.sub(class, -len) end for _, v in pairs(t) do if cand == v then return makeNumberedClass(class, len1) end end end return nil end local result = self.super.get(self, class) if result then return result else local l = mw.ustring.len(class) local bstart, bend = string.find(class, ' ') local dstart, dend = string.find(class, '-') if bstart or dstart then local pos if bstart and dstart then if bstart > dstart then pos = dstart else pos = bstart end elseif bstart then pos = bstart else pos = dstart end if pos > 1 then local len = pos-1 local v = self.class_lengths[len] if v then local cls = matchSimilarClasses(class, l, pos, v, len, true) if cls then return cls end end end if bstart then bstart, bend = string.find(class, " [^ ]*$") end if dstart then dstart, dend = string.find(class, "-[^-]*$") end if bstart and dstart then if bstart > dstart then pos = bstart else pos = dstart end elseif bstart then pos = bstart else pos = dstart end if pos < l then local len = l-pos local v = self.class_lengths[len] if v then local cls = matchSimilarClasses(class, l, pos, v, len, true) if cls then return cls end end end end local plain = mw.ustring.gsub(class, '-', '') return self.lookup[plain] end end local cases = Parameter:new{ code = 'case', names = {}, values = { abe = { 'abessiv' }, abl = { 'ablativ' }, abs = { 'absolutiv' }, accus = { 'accusativ', 'akkusativ', 'wenfall', 'acusativo', 'akuzativ', 'tožilnik', 'biernik', 'galininkas', 'þolfall', 'вини́тельный' }, ['accus-n'] = { 'accusative-nominative', 'akkusativ-nominativ', 'acusativo-nominativo', 'nominatiiviakkusatiivi' }, ['accus-g'] = { 'accusative-genitive', 'akkusativ-genitiv', 'acusativo-genitivo', 'genetiiviakkusatiivi' }, accud = { 'accudativ', 'akkudativ' }, adel = { 'adelativ' }, ades = { 'adessiv', 'adesyvas' }, adv = { 'adverbial' }, al = { 'allativ', 'adlativ', 'direktiv', 'aliatyvas' }, av = { 'aversiv' }, ag = { 'agentiv' }, an = { 'antessiv' }, ap = { 'apudessiv' }, b = { 'benefactiv', 'benefaktiv', 'destinativ' }, ca = { 'causal' }, ['ca-fi'] = { 'causal-final' }, comi = { 'comitativ', 'komitativ', 'assoziativ' }, comp = { 'comparativ' }, da = { 'dativ', 'wemfall', 'dajalnik', 'celownik', 'naudininkas', 'þágufall', 'да́тельный' }, de = { 'delativ' }, di = { 'distributiv' }, ['di-tem'] = { 'distributive-temporal' }, eg = { 'egressiv' }, el = { 'elativ' }, eq = { 'equativ', 'äquativ' }, er = { 'ergativ' }, ['er-g'] = { 'ergative-genitive' }, es = { 'essiv' }, ['es-fo'] = { 'essive-formal' }, ['es-mod'] = { 'essive-modal' }, ex = { 'exessiv' }, fo = { 'formal' }, g = { 'genitiv', 'wesfall', 'wessenfall', 'genetiv', 'rodilnik', 'dopełniacz', 'kilmininkas', 'eignarfall', 'роди́тельный' }, id = { 'identical' }, il = { 'illativ', 'kryptininkas' }, ine = { 'inessiv' }, ini = { 'initiativ' }, intran = { 'intransitiv' }, intrat = { 'intrativ' }, instruc = { 'instructiv', 'instruktiv' }, instrum = { 'instrumental', 'instrumentál', 'orodnik', 'narzędnik', 'įnagininkas', 'твори́тельный' }, ['instrum-comi'] = { 'instrumental-comitativ' }, la = { 'lativ' }, li = { 'limitativ' }, lo = { 'locativ', 'lokativ', 'lokál', 'mestnik', 'miejscownik', 'vietininkas' }, mod = { 'modal' }, n = { 'nominativ', 'werfall', 'rektus', 'rectus', 'imenovalnik', 'mianownik', 'vardininkas', 'nefnifall', 'имени́тельный' }, obl = { 'oblique', 'obliquus', 'oblik' }, obj = { 'objectiv' }, ['obj/obl'] = { 'objective/oblique' }, ori = { 'orientativ' }, orn = { 'ornativ' }, pa = { 'partitiv' }, peg = { 'pegativ' }, perl = { 'perlativ' }, pert = { 'pertingent' }, possesse = { 'possessed' }, possessi = { 'possessiv' }, postel = { 'postelativ' }, postes = { 'postessiv' }, pre = { 'prepositional', 'präpositiv', 'предло́жный' }, pri = { 'privativ' }, pro = { 'prolativ' }, r = { 'revertiv' }, se = { 'semblativ' }, so = { 'sociativ' }, sube = { 'subessiv' }, subl = { 'sublativ' }, supere = { 'superessiv' }, superl = { 'superlativ' }, tem = { 'temporal' }, ter = { 'terminativ' }, tr = { 'translativ' }, v = { 'vocativ', 'vokativ', 'wołacz', 'šauksmininkas' } }, fallback = 'nominative' } function cases:get(case) local result = self.super.get(self, case) if result then return result else local l = mw.ustring.len(case) local matched if l > 4 then local last = mw.ustring.sub(case, -4, -1) if last == 'ivus' then matched = true case = mw.ustring.sub(case, 1, -3) result = self.lookup[case] if result then return result end elseif last == 'iivi' then matched = true case = mw.ustring.sub(case, 1, -4) .. 'v' result = self.lookup[case] if result then return result end end end if l > 3 and not matched then local last = mw.ustring.sub(case, -3, -1) if last == 'ive' or last == 'ivo' then matched = true case = mw.ustring.sub(case, 1, -2) result = self.lookup[case] if result then return result end end end if l > 2 and not matched then local last = mw.ustring.sub(case, -2, -1) if last == 'if' then matched = true case = mw.ustring.sub(case, 1, -2) .. 'v' result = self.lookup[case] if result then return result end end end local plain = mw.ustring.gsub(case, '-', '') return self.lookup[plain] end end local function linkBegin(lang) if not lang or lang == '' then return "[[" else return "[[:" .. lang .. ":" end end local function linkEnd(u) if not u or u == '' then return "]]" else return "|" .. u .. "]]" end end local function link_en(i, stem, u) return (i > 39 and "Names of large numbers" or ("Orders of magnitude (numbers)#10" .. i)) .. linkEnd(u) end local Adder = Object:new{} function Adder:getAdditional(lang, i) local one, simplify local top = self:tableInherit('additional', i) if top then local entry = (top and lang and top[lang]) or top if entry then one, simplify = entry[1], entry.simplify end end return one, simplify end --[[ Rules grammars <possessive-rules> ::= "{}" | <string> | "{" <possessor-cases> "}" | <possessive-function> <possessor-cases> ::= <singular-possessors> | <singular-posessors> "," <plural-posessors> <singular-possessors> ::= "{" <singular-possessor-cases> "}" <singular-posessor-cases> := <simple-posessor-case> | <simple-possessor-case> "," <singular-possessor-cases> <simple-posessor-case> := "{ {" <singular-possessed> "," <plural-possessed> "} }" | <possessor-function> <singular-possessed> ::= <possessed> <plural-possessed> ::= <possessed> <possessed> ::= <string> | "{" <possessed-cases> "}" | <possessed-function> <plural-posessors> ::= "{" <plural-possessor-cases> "}" <plural-possessor-cases> := <plural-posessor-case> | <plural-possessor-case> "," <plural-possessor-cases> <plural-possessor-case> ::= "{" <clusivity-cases> "}" <clusivity-cases> ::= <simple-possessor-case> | <simple-possessor-case> "," <clusivity-cases> <inflection-rules> ::= "{}" | "{" <stem-statement> "}" | "{" <number-cases> "}" | "{" <stem-statement> "," <number-cases> "}" <stem-statement> ::= "stem" "=" <stem-function> <number-cases> ::= <number-case> | <number-case> "," <number-cases> <number-case> ::= <number-index> <number-rule> <number-index> ::= "" | "[" <integer> "]" "=" | | "[" "fraction" "]" "=" <number-rule> ::= <string> | <ending-cases-list> | <state-cases> | <number-function> <ending-cases-list> ::= "{" <ending-cases> "}" <ending-cases> ::= <ending-case> | <ending-case> "," <ending-cases> <ending-case> ::= <string-index> "=" <ending-rule> <ending-rule> ::= <string> | <class-cases-list> | <state-cases> | <ending-function> <class-cases-list> ::= "{" <class-cases> "}" <class-cases> ::= <class-case> | <class-case> "," <class-cases> <class-case> ::= <string-index> "=" <class-rule> <class-rule> ::= <string> | <grammatical-cases-list> | <state-cases> | <class-function> <state-cases> ::= "{" <indefinite-rule> "}" | "{" <indefinite-rule> "," <definite-rule> "}" | "{" <indefinite-rule> "," <definite-rule> "," <construct-rule> "}" <indefinite-rule> ::= <state-rule> <definite-rule> ::= <state-rule> <construct-rule> ::= <state-rule> <state-rule> ::= <string> | <grammatical-cases-list> | <state-function> <grammatical-cases-list> ::= "{" <grammatical-cases> "}" <grammatical-cases> ::= <grammatical-case> | <grammatical-case> "," <grammatical-cases> <grammatical-case> ::= <string-index> "=" <grammatical-rule> <grammatical-rule> ::= <string> | <simple-class-cases-list> | "{" <possessed-cases> "}" | <grammatical-function> <simple-class-cases-list> ::= "{" <simple-class-cases> "}" <simple-class-cases> ::= <simple-class-case> | <simple-class-case> "," <simple-class-cases> <simple-class-case> ::= <string-index> "=" <simple-class-rule> <simple-class-rule> ::= <string> | <simple-ending-cases-list> | <class-function> <simple-ending-cases-list> ::= "{" <simple-ending-cases> "}" <simple-ending-cases> ::= <simple-ending-case> | <simple-ending-case> "," <simple-ending-cases> <simple-ending-case> ::= <string-index> "=" <simple-ending-rule> <simple-ending-rule> ::= <string> | <ending-function> <possessed-cases> ::= <possessed-case> | <possessed-case> "," <possessed-cases> <possessed-case> ::= <string-index> "=" <possessed-rule> <string-index> ::= <identifier> | "[" <string> "]" <possessed-rule> ::= <string> | <possessed-function> ]] local families = { indian = {}, myriad = {}, short = {}, long = {} } local Family = Object:new{} function Family:setDefaults(defscale) local name = self.code if name and name ~= '' then local langs = number_systems.defaults if not langs then langs = {} number_systems.defaults = langs end if defscale then langs[name] = defscale end local scale = self.scale if scale then for k, v in pairs(scale) do families[k][name] = self if not defscale and v.default then langs[name] = k end local s = v.default_script if not s then local script = v.script if script then s = singleEntry(script) end end if s then local scales = scripts.defaults if not scales then scales = {} scripts.defaults = scales end local ls = scales[name] if not ls then ls = {} scales[name] = ls end ls[k] = s end end end end return nil end function Family:new (o) local result = Object.new(self, o) local name = result.code if name and name ~= '' then local k = result.default_scale if not k then local scale = result.scale if scale then k = singleEntry(scale) end end result:setDefaults(k) end local pars = rawget(result, 'parameters') if pars then for k, v in pairs(pars) do local p = parameters[k] local names = v.names if names then for _, n in names do local ns = p.names if not ns then ns = {} p.names = ns end table.insert(ns, n) end addMultipleKeys(parameter_lookup, names, name) end local vales = v.values if values then for i, n in values do local ns = p.lookup if not ns then ns = {} p.lookup = ns end ns[n] = i end end end end return result end local Script = Adder:new{} local hant_script = Script:new{ code = 'hani', additional = { [4] = { '萬' }, [8] = { '億' }, [12] = { '兆' }, [16] = { '京' }, [20] = { '垓' }, [24] = { '秭' }, [28] = { '穣' }, [32] = { '溝' }, [36] = { '澗' }, [40] = { '正' }, [44] = { '載' }, [48] = { '極' } } } local hanja_script = hant_script:new{} local kanji_script = hant_script:new{ additional = { [4] = { '万' } } } local hans_script = kanji_script:new{ code = 'hans', additional = { [8] = { '亿' }, [32] = { '沟' }, [36] = { '涧' }, [44] = { '载' }, [48] = { '极' } } } local hangul_script = Script:new{ code = 'hang', additional = { [4] = { '만' }, [8] = { '억' }, [12] = { '조' }, [16] = { '경' }, [20] = { '해' }, [24] = { '자' }, [28] = { '양' }, [32] = { '구' }, [36] = { '간' }, [40] = { '정' }, [44] = { '재' }, [48] = { '극' } } } local language_ko = Family:new{ code = 'ko', scale = { myriad = Adder:new{ top = 48, link = '큰_수의_이름', script = { hang = hangul_script, hani = hanja_script }, default_script = 'hang' } } } local language_ja = Family:new{ code = 'ja', scale = { myriad = Adder:new{ top = 48, link = '10の冪', script = { hani = kanji_script } } } } local language_zh = Family:new{ code = 'zh', scale = { myriad = Adder:new{ top = 48, link = '中文数字', script = { hans = hans_script, hant = hant_script }, default_script = 'hans' } } } local latin = Family:new{ code = 'la', space = true, root = 'lli', suffix = { 'o', 'ard' }, prefix = { 'mi', 'bi', 'tri', 'quadri', 'quinti', 'sexti', 'septi', 'octi', 'noni', 'deci', [20] = 'viginti', [30] = 'triginti', [40] = 'quadraginti', [50] = 'quinquaginti', [60] = 'sexaginti', [70] = 'septuaginti', [80] = 'octoginti', [90] = 'nonaginti', [100] = 'centi' }, unit_prefix = { 'un', 'duo', 'tre', 'quattuor', 'quin', 'sex', 'septen', 'octo', 'novem' }, prefix_exception = { [16] = { la = 'sedeci' } }, unit_prefix_exception = {}, inflection = { { o = { { [''] = '', g = 'nis', da = 'ni', accus = { [''] = 'nem', n = ''}, abl = 'ni' } }, [''] = { { [''] = 'um', g = 'i', da = 'o', abl = 'o' } } }, { o = { { [''] = { [''] = 'nes', n = 'nia' }, g = 'nium', da = 'nibus', abl = 'nibus' } }, [''] = { { [''] = 'a', g = 'orum', da = 'is', abl = 'is' } } } }, scale = { long = Adder:new{ top = 306, link = 'Nomina permagnorum numerorum' } } } local function makeArdMaker(minval, thousand) return function (scale, i, step, args, r, simplify) if i < minval then return nil end local j = math.floor(i / step) if (j*step)+3 == i then local u, simp, stem = scale:unit(i-3, args, 1000, false) return thousand .. " " .. u, (r == 1), stem else return nil end end end local language_ia = latin:new{ code = 'ia', suffix = { 'on', 'ardo' }, inflection = { stem = makeArdMaker(15, "mille"), '', function (u, args, r, simplify) if mw.ustring.sub(u, 1, 6) == "mille " then return u else local n = mw.ustring.len(u) if mw.ustring.sub(u, n, n) == "o" then return u .. "s" else return u .. "es" end end end }, scale = { long = Adder:new{ top = 18, link = function(i, stem, u) local start, finish = string.find(u, ' ') if not start then return stem .. linkEnd(u) else local first = mw.ustring.sub(u, 1, start - 1) local second = mw.ustring.sub(u, finish + 1) local secondlink = linkBegin('ia') .. stem .. linkEnd(second) return first .. " " .. secondlink, true end end } } } local language_is = latin:new{ code = 'is', root = 'llj', suffix = { 'ón', 'arð' }, prefix = { [4] = 'kvaðri', [5] = 'kvinti' }, inflection = { { n = { { [''] = '', g = 'ar' }, { n = 'in', accus = 'ina', da = 'inni', g = 'arinnar' } }, [''] = { { n = 'ur', accus = '', da = 'i', g = 's' }, { n = 'urinn', accus = 'inn', da = 'inum', g = 'sins' } } }, { n = { { [''] = 'ir', da = 'um', g = 'a' }, { [''] = 'irnar', da = 'unum', g = 'anna' } }, [''] = { { n = 'ar', accus = 'a', da = 'um', g = 'a' } , { n = 'arnir', accus = 'ana', da = 'unum', g = 'anna' } } } }, scale = { long = Adder:new{ top = 30, link = 'Stórar tölur' } } } local language_nl = latin:new{ code = 'nl', root = 'lj', suffix = { 'oen', 'ard' }, prefix_exception = { [16] = { nl = 'sedeci' } }, inflection = {}, scale = { long = Adder:new{ top = 141, link = 'Lijst van machten van tien' } } } local language_af = language_nl:new{ code = 'af', prefix = { [4] = 'kwadri', [5] = 'kwinti', [6] = 'seksti', [8] = 'okti', [10] = 'desi' }, scale = { long = Adder:new{ top = 63, link = 'Kort en lang skaalverdeling' } } } local c_family = latin:new{ code = '', capitalize = true } local language_de = c_family:new{ code = 'de', suffix = { 'on', 'arde' }, prefix = { [8] = 'Okti', [10] = 'dezi' }, unit_prefix = { [2] = 'Do', [6] = 'Se', [8] = 'Okto' }, inflection = { '', { e = 'n', [''] = 'en' } }, scale = { long = Adder:new{ top = 306, link = 'Zahlennamen' } } } local language_lb = c_family:new{ code = 'lb', suffix = { 'oun', 'ard' }, inflection = { '', 'en' }, scale = { long = Adder:new{ top = 27, link = 'Lëscht vun de Prefixe fir Moosseenheeten' } } } local li_family = latin:new{ code = '', root = 'li' } local language_ca = li_family:new{ code = 'ca', suffix = { 'ó', 'ard' }, inflection = { '', { d = 's', [''] = function (u, args, r, simplify) return mw.ustring.sub(u, 1, -2) .. "ons" end } }, scale = { long = Adder:new{ top = 306, link = 'Escales curta i llarga' } } } local language_eo = li_family:new{ code = 'eo', suffix = { 'ono', 'ardo' }, prefix = { [2] = 'dui', [4] = 'kvari', [5] = 'kvini', [6] = 'sesi', [7] = 'sepi', [8] = 'oki', [9] = 'naŭi', [10] = 'deki' }, unit_prefix = { [4] = 'kvatuor', [5] = 'kvin', [6] = 'seks', [8] = 'okto' }, inflection = { '', 'j' }, scale = { long = Adder:new{ top = 177, link = 'Vortoj por grandegaj nombroj' } } } local language_it = li_family:new{ code = 'it', suffix = { 'one', 'ardo' }, inflection = { '', function (u, args, r, simplify) return mw.ustring.sub(u, 1, -2) .. "i" end }, scale = { long = Adder:new{ top = 63, link = function(i, stem, u) return ("Ordini di grandezza (numeri)#10" .. i) .. linkEnd(u) end, exception = { [36] = 'none', [39] = 'none', [42] = 'none', [45] = 'none', [48] = 'none', [51] = 'none', [54] = 'none', [57] = 'none' } } } } local language_scn = li_family:new{ code = 'scn', suffix = { 'uni', 'ardu' }, inflection = { '', function (u, args, r, simplify) local n = mw.ustring.len(u) if mw.ustring.sub(u, n, n) == "i" then return u else return mw.ustring.sub(u, 1, -2) .. "i" end end}, scale = { long = Adder:new{ top = 63, exception = { [30] = 'none', [33] = 'none', [36] = 'none', [39] = 'none', [42] = 'none', [45] = 'none', [48] = 'none', [51] = 'none', [54] = 'none', [57] = 'none' } } } } local language_pl = li_family:new{ code = 'pl', suffix = { 'on', 'ard' }, prefix = { [3] = 'try', [4] = 'kwadry', [5] = 'kwinty', [6] = 'seksty', [7] = 'septy', [8] = 'okty', [10] = 'decy' }, inflection = { { { n = '', g = 'a', da = 'owi', accus = '', instrum = 'em', [''] = { n = 'ie', [''] = 'zie' } } }, { { [''] = 'y', g = 'ów', da = 'om', instrum = 'ami', lo = 'ach' } }, [5] = { { [''] = function (u, args, r, simplify) local floor = math.floor local n = floor(r/100) local m = r - n * 100 if m < 2 or (m > 4 and m < 22) then return u .. 'ów' elseif m < 5 then return u .. 'y' else local o = floor(m/10) local p = m - o * 10 if p > 1 and p < 5 then return u .. 'y' else return u .. 'ów' end end end, g = 'ów', da = 'om', instrum = 'ami', lo = 'ach', v = 'y' } }, fraction = 'a' }, scale = { long = Adder:new{ top = 75, link = 'Liczebniki główne potęg tysiąca' } } } local language_pt = li_family:new{ code = 'pt', suffix = { 'ão' }, inflection = { stem = makeArdMaker(9, "mil"), '', function (u, args, r, simplify) if mw.ustring.sub(u, 1, 4) == "mil " then return u else return mw.ustring.sub(u, 1, -3) .. "ões" end end }, scale = { long = Adder:new{ top = 60, exception = { [6] = { 'milhão' } } } } } local ib_family = latin:new{ code = '', root = 'll', suffix = { 'ón', 'ardo' } } local milArdMaker = makeArdMaker(9, "mil") local language_an = ib_family:new{ code = 'an', prefix = { [4] = 'quatri' }, inflection = { stem = milArdMaker, '', function (u, args, r, simplify) if mw.ustring.sub(u, 1, 4) == "mil " then return u else local n = mw.ustring.len(u) if mw.ustring.sub(u, n, n) == "o" then return u .. "s" else return mw.ustring.sub(u, 1, -3) .. "ons" end end end }, scale = { long = Adder:new{ top = 24, link = 'Potencia de diez' } } } local language_gl = ib_family:new{ code = 'gl', inflection = { stem = milArdMaker, '', function (u, args, r, simplify) if mw.ustring.sub(u, 1, 4) == "mil " then return u else return u .. "s" end end }, scale = { long = Adder:new{ top = 18 } } } local es_family = ib_family:new{ code = '', prefix = { [4] = 'cuatri' }, plural = function (u, args, r, simplify) if mw.ustring.sub(u, 1, 4) == "mil " then return u else local n = mw.ustring.len(u) if mw.ustring.sub(u, n, n) == "o" then return u .. "s" else return mw.ustring.sub(u, 1, -3) .. "ones" end end end } local language_ast = es_family:new{ code = 'ast', inflection = { stem = milArdMaker, '', es_family.plural }, scale = { long = Adder:new{ top = 30, link = 'Escales numbériques llarga y curtia' } } } local language_es = es_family:new{ code = 'es', unit_prefix = { [4] = 'cuatro', [9] = 'noven' }, inflection = { stem = makeArdMaker(15, "mil"), '', es_family.plural }, scale = { long = Adder:new{ top = 120, link = function(i, stem, u) return ("Orden de magnitud (números)#10" .. i) .. linkEnd(u) end } } } local onard_family = latin:new{ code = '', suffix = { 'on', 'ard' }, } local language_en = onard_family:new{ code = 'en', inflection = { { { n = '', possessi = "'s" } }, { { n = function (u, args, r, simplify) if simplify then return u .. 's' else return u end end, possessi = function (u, args, r, simplify) if simplify then return u .. "s'" else return u .. "'s" end end } } }, default_scale = 'short', scale = { long = Adder:new{ top = 306, link = link_en, additional = { [100] = { 'googol' } } }, short = Adder:new{ top = 303, link = link_en, additional = { [100] = { 'googol' } } }, indian = Adder:new{ top = 14, link = function(i, stem, u) local start, finish = string.find(u, ' ') if not start then return u .. linkEnd(u) else local first = mw.ustring.sub(u, 1, start - 1) local second = mw.ustring.sub(u, finish + 1) local firstlink = linkBegin('en') .. first .. linkEnd(first) if first == second then return firstlink .. " " .. second, true else return firstlink .. " " .. linkBegin('en') .. second .. linkEnd(second), true end end end, additional = { [5] = { 'lakh' }, [7] = { 'crore' }, [12] = { 'lakh crore' }, [14] = { 'crore crore' } } } } } local language_fr = onard_family:new{ code = 'fr', prefix = { [10] = 'déci' }, unit_prefix = { [3] = 'tré', [9] = 'noni' }, inflection = { '', 's' }, scale = { long = Adder:new{ top = 57, link = function(i, stem, u) return (i > 36 and "Noms des grands nombres" or ("Ordres de grandeur de nombres#10" .. i)) .. linkEnd(u) end } } } local k_family = onard_family:new{ code = '', prefix = { [4] = 'kvadri', [5] = 'kvinti', [8] = 'okti' } } local language_hu = k_family:new{ code = 'hu', suffix = { 'ó', 'árd' }, prefix = { [6] = 'szexti', [7] = 'szepti' }, unit_prefix = { [3] = 'tri', [4] = 'kva', [5] = 'kvint', [6] = 'szex' }, inflection = { { d = { { n = '', accus = 'ot', da = 'nak', instrum = 'dal', ['ca-fi'] = 'ért', tr = 'dá', ter = 'ig', ['es-fo'] = 'ként', ine = 'ban', supere = 'on', ades = 'nál', il = 'ba', subl = 'ra', al = 'hoz', el = 'ból', de = 'ról', abl = 'tól', possessi = { 'é', 'éi' } } }, [''] = { { n = '', accus = 't', da = 'nak', instrum = 'val', ['ca-fi'] = 'ért', tr = 'vá', ter = 'ig', ['es-fo'] = 'ként', ine = 'ban', supere = 'n', ades = 'nál', il = 'ba', subl = 'ra', al = 'hoz', el = 'ból', de = 'ról', abl = 'tól', possessi = { 'é', 'éi' } } } }, { d = { { n = 'ok', accus = 'okat', da = 'oknak', instrum = 'okkal', ['ca-fi'] = 'okért', tr = 'okká', ter = 'okig', ['es-fo'] = 'okként', ine = 'okban', supere = 'okon', ades = 'oknál', il = 'okba', subl = 'okra', al = 'okhoz', el = 'okból', de = 'okról', abl = 'októl', possessi = { 'oké', 'okéi' } } }, [''] = { { n = 'k', accus = 'kat', da = 'knak', instrum = 'kkal', ['ca-fi'] = 'kért', tr = 'kká', ter = 'kig', ['es-fo'] = 'kként', ine = 'kban', supere = 'kon', ades = 'knál', il = 'kba', subl = 'kra', al = 'khoz', el = 'kból', de = 'król', abl = 'któl', possessi = { 'ké', 'kéi' } } } } }, possessive = { d = { { { { 'om', 'aim' } }, { { 'od', 'jaid' } }, { { 'ja', 'jai'} } }, { { { 'unk', 'jaink' } }, { { 'otok', 'jaitok' } }, { { 'juk', 'jaik'} } } }, [''] = { { { { 'm', 'im' } }, { { 'd', 'id' } }, { { 'ja', 'i'} } }, { { { 'nk', 'ink' } }, { { 'tok', 'itok' } }, { { 'juk', 'ik'} } } } }, scale = { long = Adder:new{ top = 96, link = 'Tíz hatványai' } } } local language_sv = k_family:new{ code = 'sv', root = 'lj', inflection = { { { n = '', g = 's' }, { n = 'en', g = 'ens' } }, { { n = 'er', g = 'ers' }, { n = 'erna', g = 'ernas' } } }, scale = { long = Adder:new{ top = 177, link = 'Namn på stora tal' } } } local s_family = k_family:new{ code = '', prefix = { [6] = 'seksti' } } local language_da = s_family:new{ code = 'da', inflection = { { { n = '', possessi = "s" }, { n = 'en', possessi = "ens" } }, { { n = 'er', possessi = "ers" }, { n = 'erne', possessi = "ernes" } } }, scale = { long = Adder:new{ top = 63, link = 'Store tal' } } } local language_fi = s_family:new{ code = 'fi', root = 'lj', suffix = { 'oon' }, prefix = { [9] = 'novi', [10] = 'deki' }, inflection = { stem = makeArdMaker(9, "tuhat"), function (u, args, r, simplify) local case = args.case if mw.ustring.sub(u, 1, 6) == "tuhat " then local base = 'tuha' local cases = { n = 't', ['accus-n'] = 't', ['accus-g'] = 'nnen', g = 'nnen', pa = 'tta', ine = 'nnessa', el = 'nnesta', il = 'nteen', ades = 'nnella', abl = 'nnelta', al = 'nnelle', es = 'netena', tr = 'nneksi', abe = 'nnetta' } return base .. cases[case] .. mw.ustring.sub(u, 6) else local cases = { n = 'a', ['accus-n'] = 'a', ['accus-g'] = 'an', g = 'an', pa = 'aa', ine = 'assa', el = 'asta', il = 'aan', ades = 'alla', abl = 'alta', al = 'alle', es = 'ana', tr = 'aksi', abe = 'atta', } return u .. cases[case] end end, function (u, args, r, simplify) local case = args.case if mw.ustring.sub(u, 1, 6) == "tuhat " then local base = 'tuha' local cases = { n = 'tta', ['accus-n'] = 'nnet', g = 'nsien', pa = 'nsia', ine = 'nsissa', el = 'nsista', il = 'nsiin', ades = 'nsilla', abl = 'nsilta', al = 'nsille', es = 'nsina', tr = 'nsiksi', instruc = 'nsin', abe = 'nsitta', comi = 'nsine' } if simplify and (case == '' or case == 'n') then return u else return base .. cases[case] .. mw.ustring.sub(u, 6) end else local cases = { n = 'aa', ['accus-n'] = 'at', g = 'ien', pa = 'ia', ine = 'issa', el = 'ista', il = 'iin', ades = 'illa', abl = 'ilta', al = 'ille', es = 'ina', tr = 'iksi', instruc = 'in', abe = 'itta', comi = 'ine' } if simplify and (case == '' or case == 'n') then return u .. 'at' else return u .. cases[case] end end end }, scale = { long = Adder:new{ top = 63, link = 'Suurten lukujen nimet' } } } local language_no = s_family:new{ code = 'no', prefix = { [10] = 'desi' }, unit_prefix = { [2] = 'do', [5] = 'kvin', [6] = 'seks', [8] = 'okto' }, inflection = { { { n = '', g = 's' }, { n = 'en', g = 'ens' } }, { { n = 'er', g = 'ers' }, { n = 'ene', g = 'enes' } } }, scale = { long = Adder:new{ top = 81, link = 'Navn på store tall' } } } local language_sl = s_family:new{ code = 'sl', root = 'lij', inflection = { { n = '', [''] = 'a' }, { d = 'i', [''] = 'a' }, 'e', [5] = { d = '', [''] = 'ov' }, fraction = { d = 'e', [''] = 'a' } }, scale = { long = Adder:new{ top = 63, link = 'Imena velikih števil' } } } local u_family = k_family:new{ code = '', root = 'li', unit_prefix = { [4] = 'kvadro', [5] = 'kvin' } } local language_cs = u_family:new{ code = 'cs', prefix = { [50] = 'kvinkvaginti' }, inflection = { { n = { { n = '', [''] = 'u', accus = '', instrum = 'em', v = 'e'} }, [''] = { { n = 'a', g = 'y', [''] = 'ě', accus = 'u', instrum = 'ou', v = 'o'} } }, { n = { { [''] = 'y', g = 'ů', da = 'ům', lo = 'ech'} }, [''] = { { [''] = 'y', g = '', da = 'ám', instrum = 'ami', lo = 'ách'} } }, [5] = { n = { { [''] = 'ů', da = 'ům', instrum = 'y', lo = 'ech', v = 'y' } }, [''] = { { [''] = '', da = 'ám', instrum = 'ami', lo = 'ách', v = 'y' } } }, fraction = { n = 'u', [''] = 'y' } }, scale = { long = Adder:new{ top = 99, link = 'Desítková soustava#Názvy velkých čísel' } } } local function ardInflectGenitivePlural_sk(u, args, r, simplify) return mw.ustring.sub(u, 1, -4) .. "árd" end local language_sk = u_family:new{ code = 'sk', suffix = { 'ón', 'ard' }, prefix = { [40] = 'kvadraginti', [50] = 'kvinginti', [60] = 'seksaaginti', [80] = 'oktoginti', [90] = 'nonaginti' }, unit_prefix = { [8] = 'okto' }, inflection = { { n = { { [''] = '', g = 'a', da = 'u', instrum = 'om', lo = 'e' } }, [''] = { { n = 'a', g = 'y', accus = 'u', instrum = 'ou', [''] = 'e' } } }, { n = { { [''] = 'y', g = 'ov', da = 'om', instrum = 'mi', lo = 'och' } }, [''] = { { n = 'y', da = 'ám', accus = 'y', instrum = 'ami', lo = 'ách', g = ardInflectGenitivePlural_sk } } }, [5] = { n = { { [''] = 'ov', da = 'om', instrum = 'mi', lo = 'och' } }, [''] = { { [''] = ardInflectGenitivePlural_sk, da = 'ám', instrum = 'ami', lo = 'ách' } } }, fraction = { n = 'a', [''] = ardInflectGenitivePlural_sk } }, scale = { long = Adder:new{ top = 306, link = 'Veľké čísla' } } } function Family:getPrefix(i) return self:tableInherit('prefix', i) end function Family:getUnitPrefix(i) return self:tableInherit('unit_prefix', i) end function Family:makePrefix(j) local entry = self.prefix_exception[j] and self.prefix_exception[j][self.code] local p if entry then p = entry else p = self:getPrefix(j) if not p then if j < 11 then return nil elseif j < 100 then local k = math.floor(j / 10) local d = k * 10 local l = j - d local unitentry = self.unit_prefix_exception[l] and self.unit_prefix_exception[l][self.code] local u if unitentry then u = unitentry else u = self:getUnitPrefix(l) end local decentry = self.prefix_exception[d] and self.prefix_exception[d][self.code] local x if decentry then x = decentry else x = self:getPrefix(d) end p = u .. x else return nil end end end if self.capitalize then return mw.ustring.upper(mw.ustring.sub(p, 1, 1)) .. mw.ustring.sub(p, 2) else return p end end function Family:buildOne(i, step) local k = i / 3 if k ~= _round(k, 0) then return nil end local j if step == 3 then j = math.floor((i - 3)/ step) else j = math.floor(i / step) end if j < 1 then return nil else local pref = self:makePrefix(j) local suf if step == 3 then suf = self.suffix[1] else suf = (j * step) == i and self.suffix[1] or self.suffix[2] end return pref .. self.root .. suf end end local Scale = Adder:new{} local indian_scale = Scale:new{ name = 'indian', step = 1, family = families['indian'] } local myriad_scale = Scale:new{ name = 'myriad', step = 4, family = families['myriad'] } local scale3 = Scale:new{ build = true } local short_scale = scale3:new{ name = 'short', step = 3, family = families['short'] } local long_scale = scale3:new{ name = 'long', step = 6, family = families['long'] } local scales = { indian = indian_scale, long = long_scale, myriad = myriad_scale, short = short_scale, ind = indian_scale, fra = long_scale, usa = short_scale } function Scale:getLanguage(lang) local family = self.family return family and family[lang] end function Scale:getField(name, lang, top) local family = self.family local language = family and family[lang] local scales = language and language.scale local special = scales and scales[self.name] local result = special and special[name] if result then return result, true -- overriden else local v = self[name] if top then return v, false else return v and v[lang], false end end end function Scale:getOne(i, args, r) local lang = args.lang local one, simplify local function getAdditional(o, lang) local one, simplify local script = o.script if script then local top = (lang and script[lang]) or script local scr = top and top[args.script] if scr then one, simplify = scr:getAdditional(nil, i) end end if not one then one, simplify = o:getAdditional(lang, i) end return one, simplify end do local exception, over = self:getField('exception', lang, true) if exception then local top = exception[i] local entry = top and ((over or type(top) == 'string') and top or top[lang]) if entry then one, simplify = entry[1], entry.simplify end end end local language = args.language if not one then local scales = language.scale local special = scales and scales[self.name] if special then one, simplify = getAdditional(special, nil) end end if not one then one, simplify = getAdditional(self, lang) end if one then return one, simplify elseif language.inflection and language.inflection.stem then local d = language.inflection.stem if type(d) == 'function' then return d(self, i, self.step, args, r, simplify) end else return nil end end function Scale:unit(i, args, r, simplify) local language, one, stem, entry, inflectState, inflectEndings, inflectClass local function makeApplier(simplify, f) return function (d, arg) if not d then return nil elseif type(d) == 'function' then return d(one, args, r, simplify), simplify, stem elseif type(d) == 'table' then return f(d, arg) else return one .. d, simplify, stem end end end local function makeDoer(topn, ensure, arr, simplify, f) return function (n, arg) local d = arr[n] if d then return f(d, arg) else if topn > 1 and n > 2 then d = arr[2] if d then return f(d, arg) end end if topn > 0 and n > 1 then d = arr[1] if d then return f(d, arg) end end if ensure then return one, simplify, stem else return nil end end end end local function doMain(arr, simplify, ensure, applier, doer, f) if arr then return f(applier, doer) elseif ensure then return one, simplify, stem else return nil end end local function doFun(arr, simplify, topn, ensure, application, main) local applier = makeApplier(simplify, application) local doer if topn then doer = makeDoer(topn, ensure, arr, simplify, applier) end return doMain(arr, implify, ensure, applier, doer, main) end local function inflectPossessed(arr, other, simplify) return doFun(arr, simplify, 1, true, function(d, arg) return inflectEndings(d, simplify, false, false, false) end, function (applier, doer) if (other and args.possessed) or ((not other) and r > 1) then return doer(2) else return doer(1) end end) end local function declineCase(d, simplify, docla) local applyCase = makeApplier(simplify, function(d, arg) if docla then local result, simp, s = inflectClass(d, simplify, false, true, false) if result then return result, simp, s end end return inflectPossessed(d, true, simplify) end) local c = d[args.case] if not c then c = d[''] -- default inflection end return applyCase(c) end inflectClass = function(t, simplify, dosta, dosub, docas) local class = args.class return doFun(t, simplify, 0, false, function(v, arg) local result, simp, s if dosub then result, simp, s = inflectEndings(v, simplify, false, false, false) end if result then return result, simp, s elseif docas then result, simp, s = declineCase(v, simplify, false) end if result then return result, simp, s elseif dosta then return inflectState(v, simplify, false) else return nil end end, function(applier, doer) local done, elsevalue for k, v in pairs(t) do if k == '' then elsevalue = v if done then break end elseif not done and type(k) == 'string' then local result, simp, s = doer(class) if result then return result, simp, s else if elsevalue then break else done = true end end end end return applier(elsevalue) end) end inflectState = function(arr, simplify, docla) return doFun(arr, simplify, 1, true, function(d, arg) return declineCase(d, simplify, docla) end, function(applier, doer) local state = args.state if state == 'c' then return doer(3) elseif state == 'd' then return doer(2) else return doer(1) end end) end local function possessiveClusivity(arr, n, plural, simplify) return doFun(arr, simplify, 1, true, function(d, arg) return inflectPossessed(d, false, simplify) end, function(applier, doer) if plural then local exclude = args.exclude if not exclude or n ~= 2 then return doer(1) elseif exclude == 3 then return doer(2) elseif exclude == 2 then return doer(3) else return doer(1) end else return doer(1) end end) end local function possessivePerson(arr, plural, arg, simplify) return doFun(arr, simplify, 2, true, function(d, arg) return possessiveClusivity(d, arg, plural, simplify) end, function(applier, doer) return doer(args.person, args.person) end) end local function possessivePlural(arr, simplify) return doFun(arr, simplify, 1, true, function(d, arg) return possessivePerson(d, arg, nil, simplify) end, function(applier, doer) if args.plural then return doer(2, true) else return doer(1, false) end end) end inflectEndings = function(t, simplify, docla, dosta, dopos) return doFun(t, simplify, nil, true, function(v, arg) local result, simp, s if docla then result, simp, s = inflectClass(v, simplify, true, false, true) end if result then return result, simp, s elseif dosta then return inflectState(v, simplify, docla) elseif dopos then return possessivePlural(v, simplify) else return nil end end, function(applier, doer) local olen, elsevalue local ulen = mw.ustring.len local usub = mw.ustring.sub for k, v in pairs(t) do if k == '' then elsevalue = v elseif type(k) == 'string' then local l = ulen(k) if not olen then olen = ulen(one) end if olen >= l then if k == usub(one, -l, -1) then return applier(v) end end end end return applier(elsevalue) end) end local function inflectNumberCase(number_case, simplify) local applyNumberCase = makeApplier(simplify, function(d, arg) local result, simp, s = inflectEndings(d, simplify, true, true, false) if result then return result, simp, s else return inflectState(d, simplify, true) end end) if entry and entry[number_case] then return entry[number_case], simplify, entry[1] or stem elseif not one then return nil elseif language.inflection then return applyNumberCase(language.inflection[number_case]) end end local function inflectNumber(number_case, simplify) local result, simp, st if number_case == 5 then result, simp, st = inflectNumberCase(5, simplify) end if result then return result, simp, st end if number_case == 5 or number_case == 3 then result, simp, st = inflectNumberCase(3, simplify) end if result then return result, simp, st end if number_case == 5 or number_case == 3 or number_case == 2 then result, simp, st = inflectNumberCase(2, simplify) end if result then return result, simp, st else result, simp, st = inflectNumberCase(1, simplify) if result then return result, simp, st else return one, simplify, stem end end end local function possessive(simplify) local applyPossessive = makeApplier(simplify, function(d, arg) local result, simp, s = inflectEndings(d, simplify, false, false, true) if result then return result, simp, s else return possessivePlural(d, simplify) end end) if entry and entry.possessive then return entry.possessive, simplify, entry.possessive elseif not one then return nil else return applyPossessive(language.possessive) end end language = args.language local s one, s, stem = self:getOne(i, args, r) local simp = simplify or s if not one then one = self.build and language and language:buildOne(i, self.step) stem = one end local exception, over = self:getField('exception', lang, true) local top = exception and exception[i] entry = top and ((over or type(top) == 'string') and top or top[lang]) if args.person then return possessive(simplify) else if r == 1 then return inflectNumber(1, simp) elseif r == 2 then return inflectNumber(2, simplify) elseif r == 3 or r == 4 then return inflectNumber(3, simplify) elseif r == _round(r, 0) then return inflectNumber(5, simplify) else local result, rs, st = inflectNumberCase('fraction', simp) if result then return result, rs, st else return inflectNumber(5, simplify) end end end end function Scale:unitLink(lk, i, stem, u, lang) if lk then local f = self:getField('link', lang) if f then if type(f) == 'function' then local l, full = f(i, stem, u) if full then return l else return linkBegin(lang) .. l end else return linkBegin(lang) .. f .. linkEnd(u) end else return linkBegin('en') .. link_en(i, stem, u) end else return u end end function Scale:found(args, i, r) local lk = args.lk local u, simp, stem = self:unit(i, args, r, args.simplify) if not u then return nil elseif args.simplify or simp then return self:unitLink(lk, i, stem, u, args.lang) else local lang = args.lang return mf.formatNum(r, lang, args.prec) .. ((args.language.space and " ") or "") .. self:unitLink(lk, i, stem, u, lang) end end function Scale:binary(x, args, top, bottom) local target, target_r local lang = args.lang local prec = args.prec local floor = math.floor local pow = math.pow local rou = _round local block, iblock if self.step == 4 then block = 10000 iblock = 4 else block = 1000 iblock = 3 end while top >= bottom do local i if top == bottom then i = top else local diff = top - bottom local d = floor(diff / 2) local m = bottom + d if m/iblock == floor(m/iblock) then i = m else i = m + 2 end end local y = x / pow(10,i) local r = rou(y, prec) local exception, over = self:getField('exception', lang, true) local entry = exception and exception[i] if not entry or (entry ~= 'none' and (over or entry[lang] ~= "none")) then if r >= block and top > i then bottom = i + iblock target = i target_r = r elseif r >= 1 then local result = self:found(args, i, r) if result then return result else top = i - iblock end else top = i - iblock end elseif r < block or top == i then top = i - iblock else local result if top > i and r >= block then result = self:binary(x, args, top, i + iblock) end if result then return result elseif i > bottom then result = self:binary(x, args, i - iblock, bottom) if result then return result end end break end end if target then local result = self:found(args, target, target_r) if result then return result else return nil end end return nil end function Scale:wordify(x, args) local prec = args.prec return mf.formatNum(_round(x, prec), args.lang, prec) end function scale3:wordify(x, args) local toptop = self:getField('top', args.lang) if toptop then do local top = toptop local bottom = 102 local result = self:binary(x, args, top, bottom) if result then return result end end if 100 <= toptop then -- allow googol local top = 100 local bottom = 100 local result = self:binary(x, args, top, bottom) if result then return result end end do local top = (99 <= toptop and 99) or toptop local bottom = 6 local result = self:binary(x, args, top, bottom) if result then return result end end end return Scale.wordify(self, x, args) end function myriad_scale:wordify(x, args) local toptop = self:getField('top', args.lang) if toptop then do local top = toptop local bottom = 4 local result = self:binary(x, args, top, bottom) if result then return result end end end return Scale.wordify(self, x, args) end function indian_scale:wordify(x, args) local pow = math.pow local rou = _round local prec = args.prec local scales = args.language.scale local special = scales and scales[self.name] local scripts = special and special.script local scr = (scripts and scripts[lang]) or special for i, _ in reverseSparseIpairs((scr and scr.additional) or self.additional) do local y = x / pow(10,i) local r = rou(y, prec) if r >= 1 then return self:found(args, i, r) end end return Scale.wordify(self, x, args) end function p._wordify(x, prec, lk, numsys, lang, script, state, case, class, possessed, person, plural, exclude, simplify) local deflang = language:default(nil, lang) local defsys = number_systems:default(deflang, numsys) local canonsys = number_systems:get(defsys) or defsys if tonumber(x) then local scale = scales[canonsys] if scale then local language = scale:getLanguage(deflang) if language then local defscript = scripts:default(deflang, script, canonsys) local canonscript = scripts:get(defscript) or defscript local defstate = states:default(deflang, state) local canonstate = states:get(defstate) or defstate local defcase = cases:default(deflang, case) local canoncase = cases:get(defcase) or defcase local defclass = classes:default(deflang, class) local canonclass = classes:get(defclass) or defclass local args = { prec = prec, lk = lk, lang = deflang, language = language, script = canonscript, state = canonstate, case = canoncase, class = canonclass, possessed = possessed, person = person, plural = plural, exclude = exclude, simplify = simplify } return scale:wordify(x, args) else return err("Language '" .. deflang .. "' not supported by number system '" .. canonsys .. "'") end else return err("number system '" .. canonsys .. "' not supported") end else return err("Not a number: " .. x) end end --[[ Helper function that interprets the input numerically. If the input does not appear to be a number, attempts evaluating it as a parser functions expression. ]] function p._cleanNumber(number_string) if type(number_string) == 'number' then -- We were passed a number, so we don't need to do any processing. return number_string, tostring(number_string) elseif type(number_string) ~= 'string' or not number_string:find('%S') then -- We were passed a non-string or a blank string, so exit. return nil, nil; end -- Attempt basic conversion local number = tonumber(number_string) -- If failed, attempt to evaluate input as an expression if number == nil then local success, result = pcall(mw.ext.ParserFunctions.expr, number_string) if success then number = tonumber(result) number_string = tostring(number) else number = nil number_string = nil end else number_string = number_string:match("^%s*(.-)%s*$") -- String is valid but may contain padding, clean it. number_string = number_string:match("^%+(.*)$") or number_string -- Trim any leading + signs. if number_string:find('^%-?0[xX]') then -- Number is using 0xnnn notation to indicate base 16; use the number that Lua detected instead. number_string = tostring(number) end end return number, number_string end return p