This library consists of APIs to format and parse numbers, dates, times and file sizes for use in D2L Brightspace.
Looking for the older
d2l-intl
library? It's still here in thev2.x
branch.
Why not just use the standard ECMAScript Internationalization API (ECMA-402) and related polyfills? Firstly, the standard doesn't include any parsing functionality. Additionally, Brightspace supports fine-grained locale customization at the organization and user levels -- configuration that simply isn't present in the native APIs.
Install from NPM:
npm install @brightspace-ui/intl
Then import
only the functionality you need:
import { formatDate, formatTime } from '@brightspace-ui/intl/lib/dateTime.js';
import { formatNumber, formatPercent } from '@brightspace-ui/intl/lib/number.js';
All of the APIs will automatically detect the document's language via the lang
attribute on the <html>
element. They'll also look for various data-
attributes that will be present in Brightspace pages to access override and timezone information.
Integer and decimal numbers can be formatted in the user's locale using formatNumber
. Percentages can be formatted using formatPercent
. Use the optional options
parameter for rounding.
import { formatNumber, formatPercent } from '@brightspace-ui/intl/lib/number.js';
const number = formatNumber(8902.72, [options]); // -> '8,902.72' in en-US
const percent = formatPercent(0.333, [options]); // -> '33.3 %' in en-US
Options:
- minimumFractionDigits: Minimum number of fraction digits to use. Possible values range from
0
to20
; the default is0
. - maximumFractionDigits: Maximum number of fraction digits to use. Possible values range from
0
to20
; the default is the larger ofminimumFractionDigits
and3
. - useGrouping: Whether to use grouping separators, such as thousands separators; the default is
true
.
Formatting as an integer (rounded to 0 decimal places):
import { formatNumber } from '@brightspace-ui/intl/lib/number.js';
const value = formatNumber(89.72, {
maximumFractionDigits: 0
}); // -> '90' in en-US
Formatting as a percentage (rounded to 2 decimal places, but always showing at least 2 decimals):
import { formatPercent } from '@brightspace-ui/intl/lib/number.js';
const value = formatPercent(0.333, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}); // -> '33.30 %' in en-US
The parseNumber
method can be used to parse an integer or decimal number written in the user's locale.
import { parseNumber } from '@brightspace-ui/intl/lib/number.js';
const value = parseNumber('-8 942,39'); // -> -8942.39 in fr-CA
Dates and times can be formatted in the user's locale using formatDate
, formatTime
, formatDateTime
, and formatRelativeDateTime
.
Timestamps (milliseconds since the epoch) can be formatted in the user's locale and timezone using formatDateTimeFromTimestamp
.
Combined dates and times are formatted using formatDateTime
:
import { formatDateTime } from '@brightspace-ui/intl/lib/dateTime.js';
const date = formatDateTime(
new Date(2015, 8, 23, 14, 5),
[options]
); // -> '2015-09-23 14:05' in sv-SE
Options:
- format: pattern to use when rendering the date-time; default is
'short'
.- full: long weekday, month names and timezone. e.g.
'Wednesday, September 23, 2015 1:25 PM EST'
- medium: short month names. e.g.
'Sept 23, 2015 1:25 PM'
- short: abbreviated date format. e.g.
'9/23/2015 1:25 PM'
- full: long weekday, month names and timezone. e.g.
To format a timestamp as a date and time:
const dateString = formatDateTimeFromTimestamp(
1607097863123,
[options]
);
Options are the same as for formatDateTime
; this method converts the timestamp to a Date
in the user's
configured time zone, then returns the results of passing this date to formatDateTime
.
To format a timestamp as a date only:
const dateString = formatDateFromTimestamp(
1607097863123,
[options]
);
Options are the same as for formatDate
; this method converts the timestamp to a Date
in the user's
configured time zone, then returns the results of passing this date to formatDate
.
To format a timestamp as a time only:
const timeString = formatTimeFromTimestamp(
1607097863123,
[options]
);
Options are the same as for formatTime
; this method converts the timestamp to a Date
in the user's
configured time zone, then returns the results of passing this date to formatTime
.
To format a date only (without the time portion), use formatDate
:
import { formatDate } from '@brightspace-ui/intl/lib/dateTime.js';
const value = formatDate(
new Date(2015, 8, 23),
{format: 'full'}
); // -> 'miércoles 23 de septiembre de 2015' in es-MX
Options:
- format: pattern to use when rendering the date; default is
'short'
.- full: long weekday and month names. e.g.
'Wednesday, September 23, 2015'
- medium: long month names. e.g.
'September 23, 2015'
- short: abbreviated date format. e.g.
'9/23/2015'
- monthYear: month and year only. e.g.
'September 2015'
- monthDay: month and day only. e.g.
'September 23'
- shortMonthDay: short month and day only. e.g.
'Sep 23'
- longDayOfWeek: long weekday only. e.g.
'Wednesday'
- shortDayOfWeek: short weekday only. e.g.
'Wed'
- longMonth: long month only. e.g.
'September'
- shortMonth: short month only. e.g.
'Sep'
- full: long weekday and month names. e.g.
To format a time only (without the date portion), use formatTime
:
import { formatTime } from '@brightspace-ui/intl/lib/dateTime.js';
const time = formatTime(
new Date(2015, 8, 23, 14, 5)
); // -> '오후 14:05' in ko-KR
Options:
- format: pattern to use when rendering the time; default is
'short'
.- full: includes timezone. e.g.
'1:25 PM EST'
- medium or short: excludes timezone e.g.
'1:25 PM'
- full: includes timezone. e.g.
To format a date/time in relative time, use formatRelativeDateTime
:
import { formatRelativeDateTime } from '@brightspace-ui/intl/lib/dateTime.js';
const relativeDateTime = formatRelativeDateTime(
new Date(2024, 8, 18)
); // If today is 2024-08-22, -> 'last week' in en-US
To parse a date written in the user's locale, use parseDate
:
import { parseDate } from '@brightspace-ui/intl/lib/dateTime.js';
const date = parseDate('2015-09-23'); // in fr-CA
date.getFullYear(); // -> 2015
date.getMonth(); // -> 8 (months are 0-11)
date.getDate(); // -> 23
To parse a time written in the user's locale, use parseTime
:
import { parseTime } from '@brightspace-ui/intl/lib/dateTime.js';
const date = parseTime('14 h 05'); // in fr-CA
date.getHours(); // -> 14
date.getMinutes(); // -> 5
To convert an object containing a UTC date to an object containing a local date corresponding to the data-timezone
attribute:
import { convertUTCToLocalDateTime } from '@brightspace-ui/intl/lib/dateTime.js';
const UTCDateTime = {
month: 12,
date: 1,
year: 2015,
hours: 8,
minutes: 0,
seconds: 0
};
const localDateTime = convertUTCToLocalDateTime(
UTCDateTime
); // -> { month: 12, date: 1, year: 2015, hours: 3, minutes: 0, seconds: 0 } in America/Toronto
To convert an object containing a local date corresponding to the data-timezone
attribute to an object containing a UTC date:
import { convertLocalToUTCDateTime } from '@brightspace-ui/intl/lib/dateTime.js';
const localDateTime = {
month: 12,
date: 1,
year: 2015,
hours: 8,
minutes: 0,
seconds: 0
};
const UTCDateTime = convertLocalToUTCDateTime(
localDateTime
); // -> { month: 12, date: 1, year: 2015, hours: 13, minutes: 0, seconds: 0 } in America/Toronto
Use formatFileSize
to format a file size appropriately for the user's locale.
import { formatFileSize } from '@brightspace-ui/intl/lib/fileSize.js';
const fileSize = formatFileSize(100); // -> '100 bytes' in en-US
Use getSeparator
to get the appropriate list separator for the current locale. This is a separator that would be used in spoken language; note that the separator includes a space, for locales where it is appropriate.
import { getSeparator } from '@brightspace-ui/intl/lib/list.js';
const separator = getSeparator(); // -> ', ' in en-US
const separator = getSeparator({ nonBreaking: true }); // -> ',\xa0' in en-US
Options:
- nonBreaking: a Boolean flag, whether to use non-breaking spaces instead of standard spaces; default is
false
The Localize
class allows text to be displayed in the user's preferred language.
Each resource is comprised of a name and a message, which must be provided as a key-value pair in a JavaScript object:
{ myMessage: "This is my message" }
Names should succinctly and uniquely describe the text being localized. camelCase
is recommended, although snake_case
and kebab-case
are also supported.
For large projects, resources may be grouped using the :
character. For example: parentGroup:subGroup:messageName
.
Messages must conform to the ICU Message Syntax format. It supports features such as: simple arguments, the select
format and pluralization.
Note: Avoid using the ICU Message Syntax number, date and time formatting functionality. Brightspace allows customization of how these are localized, so use
formatNumber
,formatDate
andformatTime
instead.
Import Localize
and create a new instance. The importFunc
option is required. It will be passed a language tag which can be used to fetch resources:
import { Localize } from '@brightspace-ui/intl/lib/localize.js';
const localizer = new Localize({
importFunc: async lang => (await import(`../lang/${lang}.js`)).default
});
Wait for resources to be available before attempting to use them:
await localizer.ready;
The localize()
method is used to localize a message.
If the message contains arguments, provide replacement values in the second parameter:
const helloText = localizer.localize('hello', { firstName: 'Mary' });
Rich formatting can be included in messages and safely converted to HTML with the localizeHTML()
method.
The following formatting elements are supported out-of-the-box:
<p>paragraphs</p>
line<br></br>breaks
(note the end tag is required)<b>bold</b>
<strong>strong</strong>
<i>italic</i>
<em>emphasis</em>
Remember that <strong>
is for content of greater importance (browsers show this visually using bold), while <b>
only bolds the text visually without increasing its importance.
Similarly <em>
emphasizes a particular piece of text (browsers show this visually using italics), whereas <i>
only italicizes the text visually without emphasis.
Example:
{
myMessage: "This is <b>bold</b> but <em>not</em> all that <strong>important</strong>."
}
More advanced formatting can be achieved by providing replacement methods for custom tags, which are similar to arguments:
{
goHome: "Go <homeLink>home</homeLink>"
}
Then, import localizeMarkup
:
import { localizeMarkup } from '@brightspace-ui/intl/lib/localize.js';
and provide a tag replacement method:
localizer.localizeHTML('goHome', {
homeLink: chunks => localizeMarkup`<d2l-link href="/home">${chunks}</d2l-link>`
});
In addition to the Basic Formatting elements, these additional elements may also be used in replacement methods:
<d2l-link>
<d2l-tooltip-help>
Provide an onResourcesChange
callback function to perform tasks when the document language is changed and updated resources are available:
const localizer = new Localize({
onResourcesChange: () => document.title = localizer.localize('pageTitle')
});
To stop listening for changes, disconnect the instance:
localizer.disconnect()
After cloning the repo, run npm install
to install dependencies.
Start a @web/dev-server that hosts the test harness:
npm start
This will let you test the intl library in a browser, and will update live with any changes.
Contributions are welcome, please submit a pull request!
This repo is configured to use semantic-release
. Commits prefixed with fix:
and feat:
will trigger patch and minor releases when merged to main
.
To learn how to create major releases and release from maintenance branches, refer to the semantic-release GitHub Action documentation.