(NOTE: This library is out of date, I’m working on version 3 which is a complete rewrite and a huge improvement)
International (or Intl), is a module for simple language-sensitive number formatting, date & time formatting, relative time formatting and plurals rule.
Where to get it?
From GitHub, or from here:
2.5.1
File (9.5 MiB)
2.5
File (9.5 MiB)
2.4
File (7.9 MiB) (All locale data version.rbxm (9.5 MiB))
2.3.1
File (7.8 MiB) (All locale data version (9.4 MB))
2.3
File (7.7 MiB) (All locale data version (9.3 MiB))
Features
toLocaleString
A formatter that directly formats numbers, dates, lists without creating its respective format. If the value is determined to be numeric (number or BigNum or BigInt) it’ll directly format the number, if the value is determined to be a date, it’ll directly format the date, if the value is determined to be a list, it’ll directly format the list.
Edit: For 2.2, Lists creates Intl.ListFormat, I was incorrect, it only directly format numbers and dates
Before 2.2
A formatter that supports date formatting, number formatting, list formatting. This is a sugar syntax, for Intl.NumberFormat.new(locale, options):Format(value)
if the value is determined to be numeric, Intl.DateFormat.new(locale, options):Format(value)
, if the value is determined to be a date, and Intl.ListFormat.new(locale, options):Format(value)
if the value is determined to be a list.
Locale - International.Locale
A powerful locale class, all input are valid as long it’s a valid IETF BCP 47 tag (no -t- extension, and -x- extension are ignored but are still required to be valid).
It supports the -u-
extension.
Number formatting - International.NumberFormat
A powerful language sensitive number formatting, even only with the en
locale, it has:
- The ability to zero pad numbers (
minimumIntegerDigits
) - Round to certain dedimal places (
minimumFractionDigits
,maximumFractionDigits
) - Round to significant digits (
minimumSignificantDigits
andmaximumSignificantDigits
) - Currency formatting (
style = "currency"
), input any valid currency code as thecurrency
option (e.g USD) and it’ll do it right away - Percent formatting (
style = "percent"
) considered too - Number abbreviation/shortening/compact number (
notation = "compact"
), oh you can customise the decimal place with (minimumFractionDigits
,maximumFractionDigits
,minimumSignificantDigits
andmaximumSignificantDigits
) This can only go up to a trillion, so 1 quadrillion will return 1000T - Not just number abbreivation, long compact numbers too (
compactDisplay = "long"
) sothousand
instead ofK
- Scientific notation support too.
- Formatting it to parts for more advanced programmer, so you can it make it look like 1,000.50 or 1.2K with enough knowledge, oh it’s laid out in the similar manner to ECMA 402 (and globalize.js) number part formatting, so if you’re used to ECMA 402, no problem
{
{ type = "integer", value = "1"},
{ type = "group", value = ","},
{ type = "integer", value = "234"},
{ type = "decimal", value = "."},
{ type = "fraction", value = "56"}
}
- Negaitve number and decimal support
- Oh, not just that, it also support infinity and nan, and that is language sensitive too.
intl.NumberFormat.new('en'):Format(math.huge) --> ∞
intl.NumberFormat.new('en'):Format(0/0) --> NaN
intl.NumberFormat.new('ar'):Format(0/0) --> ليس رقمًا
- Unit support too (
style = "unit"
), with units like inches (unit = "inch"
), metres (unit = "meter"
), kilograms (unit = "kilogram"
), celsius (unit = "celsius"
), fahrenehit (unit = "fanreheit"
) seconds (unit = "second"
), etc. - More numbering system, it’s not just 123456789, but ١٢٣٤٥٦٧٨٩, 一二三四五六七八九, ௧௨௩௪௫௬௭௮௯, ၁၂၃၄၅၆၇၈၉, etc.
-- With -u- extension and the numberingSystem option, this isn't specific to locale :)
intl.NumberFormat.new('en-u-nu-arab'):Format(12345) --> ١٢,٣٤٥
- The ability to let you choose to group the digit or not, (for versions before 2.1, true to enable grouping and false to disable grouping, and it defaults to true) for version 2.1 and over, you can choose the following:
-
never
to not group the digit -
auto
for determining what number to group depending on the locale (default expect for numeral abbreviation/compact numbers) -
min2
to not group1000
but group10 000
(if the grouping size is 3), bascially set the minimum grouping digit to 2 (regardless of the locale’s minimum grouping digit value for versions < 2.4), if it’s below 2 (for versions ≥ 2.4). (default for numeral abbreviation/compact numbers) -
always
to group the digit regardless of the locale’s minimum grouping digit value. -
thousands
to group the digit by thousands (minimum grouping digits aren’t accounted, only available on 2.4 and over)
-
- Range formatting (for 2.2 and over) with
:FormatRange()
- Infinite precision (If BigDecimal or a numeric string inputted)
- BigNum/BigInteger support (Yes BigNum/BigInteger works here unlike most number formatting modules)
- In fact a numeric string support, so it’s not limited.
print(intl.NumberFormat.new('en'):Format('9007199254740993')) --> 9,007,199,254,740,993
-- This module is capable of this :)
print(intl.NumberFormat.new('en'):Format(BigInteger.new(10) ^ 1000)) --> 10,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
-- Don't forget it's locale aware
print(intl.NumberFormat.new('de'):Format(BigInteger.new(10) ^ 1000)) --> 10.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000
Date formatting - International.DateTimeFormat
A powerful yet flexibile language-sensitive date formatting. It finds the closest pattern and with the so-called smart date format negotiation determined by what value options is inputted.
If no/empty table option is included it defaults to { dateStyle = 'medium' }
(keep in mind depending on the options, many date parts might be ignored)
print(intl.DateTimeFormat.new('en'):Format{ year = 2012, month = 3, day = 4, hour = 12, min = 34 }) --> Mar 4, 2012 12:34:00 PM
print(intl.DateTimeFormat.new('en', { dateStyle = "medium" }):Format{ year = 2012, month = 3, day = 4 }) --> Mar 4, 2012
print(intl.DateTimeFormat.new('en', { dateStyle = "full" }):Format{ year = 2012, month = 3, day = 4 }) --> Sunday, March 4, 2012
print(intl.DateTimeFormat.new('en', { month = "short", day = "numeric" }):Format{ year = 2012, month = 3, day = 4 }) --> Mar 4
print(intl.DateTimeFormat.new('en', { hour = "numeric", minute = "2-digit" }):Format{ year = 2012, month = 3, day = 4, hour = 13, minute = 45 }) --> 1:45 PM
-- 12 and 24 hours isn't tied by locale, with -u- extension and the hourCycle and hour12 option :)
print(intl.DateTimeFormat.new('en', { hour12 = false, hour = "numeric", minute = "2-digit" }):Format{ year = 2012, month = 3, day = 4, hour = 13, minute = 45 }) --> 13:45
print(intl.DateTimeFormat.new('en-u-hc-h23', { hour = "numeric", minute = "2-digit" }):Format{ year = 2012, month = 3, day = 4, hour = 13, minute = 45 }) --> 13:45
It doesn’t only support gregorian, it supports the following calendar:
- Islamic (might be one day off)
- Japanese
- Republic of China
- Buddhist
- Chinese (only from 1901 to 2100, added in 2.4)
Relative time formatting - International.RelativeTimeFormat
Language sensitive relative time formatting, positive values (and 0) indicates future and negative values indicates past, this doesn’t accept NaN
but it does accept Infinity
, it supports the following:
- years
- quarters
- months
- mondays to sundays
- week
- days
- hour
- minute
- second
(Unlike intl.NumberFormat, this doesn’t accept BigNum/BigInt, and only accepts number values that’s not NaN
or strings that can be converted to number)
local formatter = intl.RelativeTimeFormat.new('en', { numeric = "auto" })
print(formatter:Format(-2, 'day')) --> 2 days ago
print(formatter:Format(-1, 'day')) --> yesterday
print(formatter:Format(0, 'day')) --> today
print(formatter:Format(1, 'day')) --> tomorrow
print(formatter:Format(2, 'day')) --> in 2 days
-- Inserting NaN will throw an error
print(formatter:Format(tonumber('nan'), 'day')) --> Value must not be NaN
Plural rule - International.PluralRules
A language-sensitive plural rule handling, can only return the following:
zero
one
two
few
many
-
other
In English, onlyone
andother
can be returned for cardinal,one
for singular,other
for plural.
local englishPlural = intl.PluralRules.new('en');
print(englishPlural:Select(1)) --> one
print(englishPlural:Select(2)) --> other
It also supports ordinals with type = "ordinal"
option, one
for st
, two
for nd
, few
for rd
and other
for th
.
Locale display names - International.DisplayNames
Maybe there’s a case where you want to display locale names in whatever language you want? Territory names? Script names? With International, all you need to do is create a DisplayName then run the :Of
method, that’s it, regional/script/variant part in locales are dealt with.
local englishDisplayName = Intl.DisplayNames.new('en');
print(englishDisplayName:Of('en')) --> English
print(englishDisplayName:Of('en-US')) --> American English
print(englishDisplayName:Of('en-GB')) --> British English
print(englishDisplayName:Of('de')) --> German
print(englishDisplayName:Of('ja')) --> Japanese
print(englishDisplayName:Of('eo')) --> Espernato
local shortEnglishDisplayName = Intl.DisplayNames.new('en', { style = "short" });
print(shortEnglishDisplayName:Of('en-US')) --> US English
print(shortEnglishDisplayName:Of('en-GB')) --> UK English
local englishTerritoryName = Intl.DisplayNames.new('en', { type = "region" });
print(englishTerritoryName:Of('DE')) --> Germany
print(englishTerritoryName:Of('JP')) --> Japan
print(englishTerritoryName:Of('ES')) --> Spain
print(englishTerritoryName:Of('419')) --> Latin America
print(englishTerritoryName:Of('KP')) --> North Korea
print(englishTerritoryName:Of('UN')) --> United Nations
print(englishTerritoryName:Of('EU')) --> European Union
print(englishTerritoryName:Of('001')) --> World
Segmenter - International.Segmenter
Only available on version 2.3 and over
Maybe you want to split text? words? sentences? No problem, with this capable of splitting words, graphemes and sentences.
local segmenter = International.Segmenter.new('en', { granularity = "word" })
for index, segment in segmenter:Segment("hello world") do
print(index, segment)
end;
Outputs
1 hello
6
7 world
If you prefer table over iterator you can use Segmenter:Split(text)
.
With sentence suppressions depending on the locale. (Via the suppression option)
List formatting - International.ListFormat
Have you ever wanted this
{'apple', 'pears', 'oragnes'}
to become this?
apple, pears, and oranges
Sure, this is a language-sensitive list formatter, just create a ListFormat then run :Format
, the most basic usage are something like
local list = {'a', 'b', 'c'}
local listFormatter = Internatoinal.ListFormat.new()
print(listFormatter:Format{'apple', 'pears', 'oranges'}) --> apple, pears, and oranges
print(listFormatter:Format(list)) --> a, b, and c
There’s also :FormatToParts
method.
It also supports or-styled and unit lists with the type
option, conjunction
for and-styled, disjunction
for or-styled and unit
for unit, and in the style
option there’s long, short, and narrow.
Summary
- Complex Locale matcher, and better Locale system.
- Language-sensitive number formatting with an options to round to decimal placss and significant figures, with compact numbers (both short and long) with BigNum/BigInt support
- Language-senstiive date formatting with options.
- Plural rule handling
- Locale display name
- Language sensitive list formatting