From ed74ea621df4e908ea3fcedb6cf8284382be230e Mon Sep 17 00:00:00 2001 From: Martin Munilla Date: Fri, 5 Jan 2024 12:44:09 +0100 Subject: [PATCH 1/5] feat: support format date strings --- packages/use-intl/src/core/IntlError.tsx | 3 +- .../use-intl/src/core/createFormatter.tsx | 32 ++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/use-intl/src/core/IntlError.tsx b/packages/use-intl/src/core/IntlError.tsx index cfce8f64b..2a5accb9f 100644 --- a/packages/use-intl/src/core/IntlError.tsx +++ b/packages/use-intl/src/core/IntlError.tsx @@ -5,7 +5,8 @@ export enum IntlErrorCode { INSUFFICIENT_PATH = 'INSUFFICIENT_PATH', INVALID_MESSAGE = 'INVALID_MESSAGE', INVALID_KEY = 'INVALID_KEY', - FORMATTING_ERROR = 'FORMATTING_ERROR' + INVALID_FORMAT = 'INVALID_FORMAT', + FORMATTING_ERROR = 'FORMATTING_ERROR', } export default class IntlError extends Error { diff --git a/packages/use-intl/src/core/createFormatter.tsx b/packages/use-intl/src/core/createFormatter.tsx index ac6bfc35f..235f1b2ca 100644 --- a/packages/use-intl/src/core/createFormatter.tsx +++ b/packages/use-intl/src/core/createFormatter.tsx @@ -1,10 +1,10 @@ import DateTimeFormatOptions from './DateTimeFormatOptions'; import Formats from './Formats'; -import IntlError, {IntlErrorCode} from './IntlError'; +import IntlError, { IntlErrorCode } from './IntlError'; import NumberFormatOptions from './NumberFormatOptions'; import RelativeTimeFormatOptions from './RelativeTimeFormatOptions'; import TimeZone from './TimeZone'; -import {defaultOnError} from './defaults'; +import { defaultOnError } from './defaults'; const SECOND = 1; const MINUTE = SECOND * 60; @@ -31,7 +31,7 @@ const UNIT_SECONDS: Record = { quarter: QUARTER, quarters: QUARTER, year: YEAR, - years: YEAR + years: YEAR, } as const; function resolveRelativeTimeUnit(seconds: number) { @@ -75,7 +75,7 @@ export default function createFormatter({ locale, now: globalNow, onError = defaultOnError, - timeZone: globalTimeZone + timeZone: globalTimeZone, }: Props) { function resolveFormatOrOptions( typeFormats: Record | undefined, @@ -128,7 +128,7 @@ export default function createFormatter({ function dateTime( /** If a number is supplied, this is interpreted as a UTC timestamp. */ - value: Date | number, + value: Date | number | string, /** If a time zone is supplied, the `value` is converted to that time zone. * Otherwise the user time zone will be used. */ formatOrOptions?: string | DateTimeFormatOptions @@ -140,7 +140,7 @@ export default function createFormatter({ (options) => { if (!options?.timeZone) { if (globalTimeZone) { - options = {...options, timeZone: globalTimeZone}; + options = { ...options, timeZone: globalTimeZone }; } else { onError( new IntlError( @@ -153,6 +153,22 @@ export default function createFormatter({ } } + if (typeof value === 'string') { + const str = value; + value = new Date(value); + if (isNaN(value.getTime())) { + onError( + new IntlError( + IntlErrorCode.INVALID_FORMAT, + process.env.NODE_ENV !== 'production' + ? `The \`value\` string parameter does not follow a valid ISO 8601 format. For more information check: https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format` + : undefined + ) + ); + return str; + } + } + return new Intl.DateTimeFormat(locale, options).format(value); } ); @@ -219,7 +235,7 @@ export default function createFormatter({ const value = calculateRelativeTimeValue(seconds, unit); return new Intl.RelativeTimeFormat(locale, { - numeric: 'auto' + numeric: 'auto', }).format(value, unit); } catch (error) { onError( @@ -238,5 +254,5 @@ export default function createFormatter({ ); } - return {dateTime, number, relativeTime, list}; + return { dateTime, number, relativeTime, list }; } From 656e7015ed11c109e4d9a776be4b1fc1cb1f0aa8 Mon Sep 17 00:00:00 2001 From: Martin Munilla Date: Fri, 5 Jan 2024 12:51:28 +0100 Subject: [PATCH 2/5] chore: add tests --- .../test/core/createFormatter.test.tsx | 68 +++++++++++-------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/packages/use-intl/test/core/createFormatter.test.tsx b/packages/use-intl/test/core/createFormatter.test.tsx index b5ce28407..6019123cc 100644 --- a/packages/use-intl/test/core/createFormatter.test.tsx +++ b/packages/use-intl/test/core/createFormatter.test.tsx @@ -1,15 +1,27 @@ -import {parseISO} from 'date-fns'; -import {it, expect} from 'vitest'; -import {createFormatter} from '../../src'; +import { parseISO } from 'date-fns'; +import { it, expect } from 'vitest'; +import { createFormatter } from '../../src'; it('formats a date and time', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.dateTime(parseISO('2020-11-20T10:36:01.516Z'), { - dateStyle: 'medium' + dateStyle: 'medium', + }) + ).toBe('Nov 20, 2020'); +}); + +it('formats a ISO 8601 datetime string', () => { + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin', + }); + expect( + formatter.dateTime('2020-11-20T10:36:01.516Z', { + dateStyle: 'medium', }) ).toBe('Nov 20, 2020'); }); @@ -17,7 +29,7 @@ it('formats a date and time', () => { it('formats a number', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect(formatter.number(123456)).toBe('123,456'); }); @@ -25,7 +37,7 @@ it('formats a number', () => { it('formats a bigint', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect(formatter.number(123456789123456789n)).toBe('123,456,789,123,456,789'); }); @@ -33,22 +45,22 @@ it('formats a bigint', () => { it('formats a number as currency', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( - formatter.number(123456.789, {style: 'currency', currency: 'USD'}) + formatter.number(123456.789, { style: 'currency', currency: 'USD' }) ).toBe('$123,456.79'); }); it('formats a bigint as currency', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.number(123456789123456789n, { style: 'currency', - currency: 'USD' + currency: 'USD', }) ).toBe('$123,456,789,123,456,789.00'); }); @@ -56,7 +68,7 @@ it('formats a bigint as currency', () => { it('formats a relative time with the second unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -69,7 +81,7 @@ it('formats a relative time with the second unit', () => { it('formats a relative time with the minute unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -82,7 +94,7 @@ it('formats a relative time with the minute unit', () => { it('formats a relative time with the hour unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -95,7 +107,7 @@ it('formats a relative time with the hour unit', () => { it('formats a relative time with the day unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -108,7 +120,7 @@ it('formats a relative time with the day unit', () => { it('formats a relative time with the month unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -121,7 +133,7 @@ it('formats a relative time with the month unit', () => { it('formats a relative time with the year unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -134,7 +146,7 @@ it('formats a relative time with the year unit', () => { it('supports the future relative time', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime( @@ -147,12 +159,12 @@ it('supports the future relative time', () => { it('formats a relative time with options', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime(parseISO('2020-11-20T08:30:00.000Z'), { now: parseISO('2020-11-20T10:36:00.000Z'), - unit: 'day' + unit: 'day', }) ).toBe('today'); }); @@ -160,12 +172,12 @@ it('formats a relative time with options', () => { it('supports the quarter unit', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime(parseISO('2020-01-01T00:00:00.000Z'), { now: parseISO('2020-11-01T01:00:00.000Z'), - unit: 'quarter' + unit: 'quarter', }) ).toBe('3 quarters ago'); }); @@ -174,11 +186,11 @@ it('formats a relative time with a globally defined `now`', () => { const formatter = createFormatter({ locale: 'en', now: parseISO('2020-11-20T01:00:00.000Z'), - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.relativeTime(parseISO('2020-11-20T00:00:00.000Z'), { - unit: 'day' + unit: 'day', }) ).toBe('today'); }); @@ -186,21 +198,21 @@ it('formats a relative time with a globally defined `now`', () => { it('formats a list', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( - formatter.list(['apple', 'banana', 'orange'], {type: 'disjunction'}) + formatter.list(['apple', 'banana', 'orange'], { type: 'disjunction' }) ).toBe('apple, banana, or orange'); }); it('formats a set', () => { const formatter = createFormatter({ locale: 'en', - timeZone: 'Europe/Berlin' + timeZone: 'Europe/Berlin', }); expect( formatter.list(new Set(['apple', 'banana', 'orange']), { - type: 'disjunction' + type: 'disjunction', }) ).toBe('apple, banana, or orange'); }); From 8bbaaa75579346ce53328d8c15c092b3e41c2e12 Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Tue, 21 May 2024 13:58:45 +0200 Subject: [PATCH 3/5] Enhance comment --- packages/use-intl/src/core/createFormatter.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/use-intl/src/core/createFormatter.tsx b/packages/use-intl/src/core/createFormatter.tsx index eb507b1fe..f6504bc82 100644 --- a/packages/use-intl/src/core/createFormatter.tsx +++ b/packages/use-intl/src/core/createFormatter.tsx @@ -147,7 +147,8 @@ export default function createFormatter({ } function dateTime( - /** If a number is supplied, this is interpreted as a UTC timestamp. */ + /** If a number is supplied, this is interpreted as a UTC timestamp. + * If a string is supplied, this is interpreted as an ISO 8601 string. */ value: Date | number | string, /** If a time zone is supplied, the `value` is converted to that time zone. * Otherwise the user time zone will be used. */ From fa44e7427b39e7f80b4c0b4476b3d1f1c91bc278 Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Tue, 21 May 2024 21:09:26 +0200 Subject: [PATCH 4/5] Finish feature --- packages/next-intl/package.json | 2 +- packages/use-intl/package.json | 2 +- .../src/core/RelativeTimeFormatOptions.tsx | 2 +- .../use-intl/src/core/createFormatter.tsx | 95 +++++++++++------- .../test/core/createFormatter.test.tsx | 98 ++++++++++++++++++- .../use-intl/test/react/useFormatter.test.tsx | 7 +- 6 files changed, 164 insertions(+), 42 deletions(-) diff --git a/packages/next-intl/package.json b/packages/next-intl/package.json index 6315e9268..59033ba2e 100644 --- a/packages/next-intl/package.json +++ b/packages/next-intl/package.json @@ -114,7 +114,7 @@ "size-limit": [ { "path": "dist/production/index.react-client.js", - "limit": "15.765 KB" + "limit": "15.81 KB" }, { "path": "dist/production/index.react-server.js", diff --git a/packages/use-intl/package.json b/packages/use-intl/package.json index d1ce4fc15..10a58f5b4 100644 --- a/packages/use-intl/package.json +++ b/packages/use-intl/package.json @@ -90,7 +90,7 @@ "size-limit": [ { "path": "dist/production/index.js", - "limit": "15.26 kB" + "limit": "15.305 kB" } ] } diff --git a/packages/use-intl/src/core/RelativeTimeFormatOptions.tsx b/packages/use-intl/src/core/RelativeTimeFormatOptions.tsx index a40d8b436..0045c582a 100644 --- a/packages/use-intl/src/core/RelativeTimeFormatOptions.tsx +++ b/packages/use-intl/src/core/RelativeTimeFormatOptions.tsx @@ -1,5 +1,5 @@ type RelativeTimeFormatOptions = { - now?: number | Date; + now?: Date | number | string; unit?: Intl.RelativeTimeFormatUnit; numberingSystem?: string; style?: Intl.RelativeTimeFormatStyle; diff --git a/packages/use-intl/src/core/createFormatter.tsx b/packages/use-intl/src/core/createFormatter.tsx index f6504bc82..9f106dba7 100644 --- a/packages/use-intl/src/core/createFormatter.tsx +++ b/packages/use-intl/src/core/createFormatter.tsx @@ -63,6 +63,20 @@ function calculateRelativeTimeValue( return Math.round(seconds / UNIT_SECONDS[unit]); } +function isDate(candidate: unknown): candidate is Date { + return candidate instanceof Date; +} + +type DateInput = Date | number | string; + +function isDateInput(candidate: unknown): candidate is DateInput { + return ( + isDate(candidate) || + typeof candidate === 'number' || + typeof candidate === 'string' + ); +} + type Props = { locale: string; timeZone?: TimeZone; @@ -146,62 +160,76 @@ export default function createFormatter({ } } - function dateTime( - /** If a number is supplied, this is interpreted as a UTC timestamp. - * If a string is supplied, this is interpreted as an ISO 8601 string. */ - value: Date | number | string, - /** If a time zone is supplied, the `value` is converted to that time zone. - * Otherwise the user time zone will be used. */ - formatOrOptions?: string | DateTimeFormatOptions - ) { - let formattableValue: Date | number; - if (typeof value === 'string') { - const str = value; - formattableValue = new Date(value); + function toDate(value: DateInput): Date { + const formattable = new Date(value); - if (isNaN(formattableValue.getTime())) { + if (process.env.NODE_ENV !== 'production') { + if ( + isNaN(formattable.getTime()) || + (typeof value === 'string' && + !value.match( + // https://stackoverflow.com/a/3143231/343045 + /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/ + )) + ) { onError( new IntlError( IntlErrorCode.FORMATTING_ERROR, - process.env.NODE_ENV !== 'production' - ? `The \`value\` string parameter does not follow a valid ISO 8601 format. For more information check: https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format` - : undefined + typeof value === 'string' + ? `Invalid ISO 8601 date string received: ${value}. Note that all parts of ISO 8601 are required: year, month, date, hour, minute, seconds, milliseconds and the timezone (e.g. '2024-02-21T07:11:36.398Z').` + : `Invalid date value received: ${value}.` ) ); - return str; } - } else { - formattableValue = value; } + return formattable; + } + + function dateTime( + /** If a number is supplied, this is interpreted as a UTC timestamp. + * If a string is supplied, this is interpreted as an ISO 8601 string. */ + value: Date | number | string, + /** If a time zone is supplied, the `value` is converted to that time zone. + * Otherwise the user time zone will be used. */ + formatOrOptions?: string | DateTimeFormatOptions + ) { + const valueDate = toDate(value); + return getFormattedValue( formatOrOptions, formats?.dateTime, (options) => { options = applyTimeZone(options); - return new Intl.DateTimeFormat(locale, options).format( - formattableValue - ); + return new Intl.DateTimeFormat(locale, options).format(valueDate); }, () => String(value) ); } function dateTimeRange( - /** If a number is supplied, this is interpreted as a UTC timestamp. */ - start: Date | number, - /** If a number is supplied, this is interpreted as a UTC timestamp. */ - end: Date | number, + /** If a number is supplied, this is interpreted as a UTC timestamp. + * If a string is supplied, this is interpreted as an ISO 8601 string. */ + start: Date | number | string, + /** If a number is supplied, this is interpreted as a UTC timestamp. + * If a string is supplied, this is interpreted as an ISO 8601 string. */ + end: Date | number | string, /** If a time zone is supplied, the values are converted to that time zone. * Otherwise the user time zone will be used. */ formatOrOptions?: string | DateTimeFormatOptions ) { + const startDate = toDate(start); + const endDate = toDate(end); + return getFormattedValue( formatOrOptions, formats?.dateTime, (options) => { options = applyTimeZone(options); - return new Intl.DateTimeFormat(locale, options).formatRange(start, end); + return new Intl.DateTimeFormat(locale, options).formatRange( + startDate, + endDate + ); }, () => [dateTime(start), dateTime(end)].join(' – ') ); @@ -236,8 +264,9 @@ export default function createFormatter({ } function relativeTime( - /** The date time that needs to be formatted. */ - date: number | Date, + /** If a number is supplied, this is interpreted as a UTC timestamp. + * If a string is supplied, this is interpreted as an ISO 8601 string. */ + date: Date | number | string, /** The reference point in time to which `date` will be formatted in relation to. */ nowOrOptions?: RelativeTimeFormatOptions['now'] | RelativeTimeFormatOptions ) { @@ -245,11 +274,11 @@ export default function createFormatter({ let nowDate: Date | undefined, unit: Intl.RelativeTimeFormatUnit | undefined; const opts: Intl.RelativeTimeFormatOptions = {}; - if (nowOrOptions instanceof Date || typeof nowOrOptions === 'number') { - nowDate = new Date(nowOrOptions); + if (isDateInput(nowOrOptions)) { + nowDate = toDate(nowOrOptions); } else if (nowOrOptions) { if (nowOrOptions.now != null) { - nowDate = new Date(nowOrOptions.now); + nowDate = toDate(nowOrOptions.now); } else { nowDate = getGlobalNow(); } @@ -263,7 +292,7 @@ export default function createFormatter({ nowDate = getGlobalNow(); } - const dateDate = new Date(date); + const dateDate = toDate(date); const seconds = (dateDate.getTime() - nowDate.getTime()) / 1000; if (!unit) { diff --git a/packages/use-intl/test/core/createFormatter.test.tsx b/packages/use-intl/test/core/createFormatter.test.tsx index a8ea57d99..7794558fa 100644 --- a/packages/use-intl/test/core/createFormatter.test.tsx +++ b/packages/use-intl/test/core/createFormatter.test.tsx @@ -1,6 +1,6 @@ import {parseISO} from 'date-fns'; -import {it, expect, describe} from 'vitest'; -import {createFormatter} from '../../src'; +import {it, expect, describe, vi} from 'vitest'; +import {IntlError, IntlErrorCode, createFormatter} from '../../src'; describe('dateTime', () => { it('formats a date and time', () => { @@ -40,6 +40,24 @@ describe('dateTime', () => { }) ).toBe('Nov 20, 2020'); }); + + it('warns when an incomplete ISO 8601 datetime string is provided', () => { + const onError = vi.fn(); + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin', + onError + }); + expect(formatter.dateTime('2020-11-20', {dateStyle: 'medium'})).toBe( + 'Nov 20, 2020' + ); + expect(onError).toHaveBeenCalledTimes(1); + const error: IntlError = onError.mock.calls[0][0]; + expect(error.code).toBe(IntlErrorCode.FORMATTING_ERROR); + expect(error.message).toBe( + "FORMATTING_ERROR: Invalid ISO 8601 date string received: 2020-11-20. Note that all parts of ISO 8601 are required: year, month, date, hour, minute, seconds, milliseconds and the timezone (e.g. '2024-02-21T07:11:36.398Z')." + ); + }); }); describe('number', () => { @@ -292,6 +310,50 @@ describe('relativeTime', () => { }) ).toBe('in 2 days'); }); + + it('accepts ISO 8601 datetime strings', () => { + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin' + }); + expect( + formatter.relativeTime( + '2020-11-20T10:36:01.516Z', + '2020-11-22T11:36:01.516Z' + ) + ).toBe('2 days ago'); + }); + + it('accepts an ISO 8601 datetime string for `opts.now`', () => { + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin' + }); + expect( + formatter.relativeTime('2020-11-20T10:36:01.516Z', { + now: '2020-11-22T11:36:01.516Z' + }) + ).toBe('2 days ago'); + }); + + it('warns when an incomplete ISO 8601 datetime string is provided', () => { + const onError = vi.fn(); + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin', + onError + }); + expect(formatter.relativeTime('2020-11-20', '2020-11-22')).toBe( + '2 days ago' + ); + expect(onError).toHaveBeenCalledTimes(2); + onError.mock.calls.forEach((call) => { + expect(call[0].code).toBe(IntlErrorCode.FORMATTING_ERROR); + expect(call[0].message).toContain( + 'FORMATTING_ERROR: Invalid ISO 8601 date string received' + ); + }); + }); }); describe('dateTimeRange', () => { @@ -361,6 +423,38 @@ describe('dateTimeRange', () => { ) ).toBe('Jan 10, 2007, 4:00:00 AM – Jan 10, 2008, 5:00:00 AM'); }); + + it('formats ISO 8601 datetime strings', () => { + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin' + }); + expect( + formatter.dateTimeRange( + '2020-11-20T10:36:01.516Z', + '2020-11-22T11:36:01.516Z' + ) + ).toBe('11/20/2020 – 11/22/2020'); + }); + + it('warns when an incomplete ISO 8601 datetime string is provided', () => { + const onError = vi.fn(); + const formatter = createFormatter({ + locale: 'en', + timeZone: 'Europe/Berlin', + onError + }); + expect(formatter.dateTimeRange('2020-11-20', '2020-11-22')).toBe( + '11/20/2020 – 11/22/2020' + ); + expect(onError).toHaveBeenCalledTimes(2); + onError.mock.calls.forEach((call) => { + expect(call[0].code).toBe(IntlErrorCode.FORMATTING_ERROR); + expect(call[0].message).toContain( + 'FORMATTING_ERROR: Invalid ISO 8601 date string received' + ); + }); + }); }); describe('list', () => { diff --git a/packages/use-intl/test/react/useFormatter.test.tsx b/packages/use-intl/test/react/useFormatter.test.tsx index c2a53f897..8b79c2fff 100644 --- a/packages/use-intl/test/react/useFormatter.test.tsx +++ b/packages/use-intl/test/react/useFormatter.test.tsx @@ -448,8 +448,7 @@ describe('relativeTime', () => { function Component() { const format = useFormatter(); - // @ts-expect-error Provoke an error - const date = 'not a number' as number; + const date = {} as number; return <>{format.relativeTime(date, -20)}; } @@ -461,10 +460,10 @@ describe('relativeTime', () => { const error: IntlError = onError.mock.calls[0][0]; expect(error.message).toBe( - 'FORMATTING_ERROR: Value need to be finite number for Intl.RelativeTimeFormat.prototype.format()' + 'FORMATTING_ERROR: Invalid date value received: [object Object].' ); expect(error.code).toBe(IntlErrorCode.FORMATTING_ERROR); - expect(container.textContent).toBe('not a number'); + expect(container.textContent).toBe('[object Object]'); }); it('reports an error when no `now` value is available', () => { From d9d31c5566515bbea4191f71bc1125911fc28588 Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Tue, 21 May 2024 21:11:10 +0200 Subject: [PATCH 5/5] Decrease size limit --- packages/next-intl/package.json | 2 +- packages/use-intl/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-intl/package.json b/packages/next-intl/package.json index 59033ba2e..8a1d07e9e 100644 --- a/packages/next-intl/package.json +++ b/packages/next-intl/package.json @@ -114,7 +114,7 @@ "size-limit": [ { "path": "dist/production/index.react-client.js", - "limit": "15.81 KB" + "limit": "15.801 KB" }, { "path": "dist/production/index.react-server.js", diff --git a/packages/use-intl/package.json b/packages/use-intl/package.json index 10a58f5b4..d299e38ca 100644 --- a/packages/use-intl/package.json +++ b/packages/use-intl/package.json @@ -90,7 +90,7 @@ "size-limit": [ { "path": "dist/production/index.js", - "limit": "15.305 kB" + "limit": "15.3 kB" } ] }