Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Type-safe global formats #1346

Merged
merged 25 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7ab9a72
feat/typesafe-global-formats
dBianchii Sep 18, 2024
4c12355
fix: Make the type fallback to string
dBianchii Sep 18, 2024
090294d
fix: forgot keyof
dBianchii Sep 18, 2024
77e8de1
move to playground
dBianchii Sep 18, 2024
c56ee2f
place that space back
dBianchii Sep 18, 2024
d995336
Merge branch 'main' into feat/typesafe-global-formats
dBianchii Sep 18, 2024
a67f7ad
add tests to example-app-router-playground
dBianchii Sep 19, 2024
4f3fd08
add format test to useLocale()
dBianchii Sep 19, 2024
25ea538
fix typo and make sure I am using use while I useFormatter
dBianchii Sep 19, 2024
14fd584
Merge remote-tracking branch 'origin/main' into feat/typesafe-global-…
amannn Sep 20, 2024
3fa91e8
Minor cleanup:
amannn Sep 20, 2024
d38a229
Revert changes to lockfile
amannn Sep 20, 2024
1c7ef5f
Add docs
dBianchii Sep 21, 2024
f728ef0
Update docs/pages/docs/workflows/typescript.mdx
dBianchii Sep 23, 2024
e1ce5aa
Update docs/pages/docs/workflows/typescript.mdx
dBianchii Sep 23, 2024
88718fa
rm type import
dBianchii Sep 23, 2024
95a2f40
A few doc changes
dBianchii Sep 23, 2024
0b014b8
Add text to ## messages
dBianchii Sep 23, 2024
d43d1a6
Merge branch 'main' into feat/typesafe-global-formats
dBianchii Sep 23, 2024
506e7ce
better highlight
dBianchii Sep 23, 2024
c747f62
Merge branch 'feat/typesafe-global-formats' of https://github.com/dBi…
dBianchii Sep 23, 2024
9b3567b
Revert change to lockfile
amannn Sep 24, 2024
3789e76
Minor docs adjustments:
amannn Sep 24, 2024
b8388ef
Merge remote-tracking branch 'origin/main' into feat/typesafe-global-…
amannn Sep 24, 2024
cca5134
Fix autocomplete when formats are provided
amannn Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/example-app-router/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import en from './messages/en.json';
import {formats} from './src/i18n/request';

type Messages = typeof en;
type Formats = typeof formats;

declare global {
// Use type safe message keys with `next-intl`
interface IntlMessages extends Messages {}
interface IntlFormats extends Formats {}
}
28 changes: 26 additions & 2 deletions examples/example-app-router/src/i18n/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
import {routing} from './routing';
import { Formats } from 'next-intl';
dBianchii marked this conversation as resolved.
Show resolved Hide resolved

export const formats = {
dateTime: {
short: {
day: 'numeric',
month: 'short',
year: 'numeric'
}
},
number: {
precise: {
maximumFractionDigits: 5
}
},
list: {
enumeration: {
style: 'long',
type: 'conjunction'
}
}
} as const satisfies Partial<Formats>
dBianchii marked this conversation as resolved.
Show resolved Hide resolved

amannn marked this conversation as resolved.
Show resolved Hide resolved

export default getRequestConfig(async ({locale}) => {
// Validate that the incoming `locale` parameter is valid
Expand All @@ -12,6 +35,7 @@ export default getRequestConfig(async ({locale}) => {
? // When using Turbopack, this will enable HMR for `en`
import('../../messages/en.json')
: import(`../../messages/${locale}.json`))
).default
};
).default,
formats
}
});
8 changes: 4 additions & 4 deletions packages/use-intl/src/core/createFormatter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default function createFormatter({
value: Date | number,
/** 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
formatOrOptions?: keyof IntlFormats['dateTime'] | DateTimeFormatOptions
dBianchii marked this conversation as resolved.
Show resolved Hide resolved
) {
return getFormattedValue(
formatOrOptions,
Expand All @@ -183,7 +183,7 @@ export default function createFormatter({
end: Date | number,
/** 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
formatOrOptions?: keyof IntlFormats['dateTime'] | DateTimeFormatOptions
) {
return getFormattedValue(
formatOrOptions,
Expand All @@ -200,7 +200,7 @@ export default function createFormatter({

function number(
value: number | bigint,
formatOrOptions?: string | NumberFormatOptions
formatOrOptions?: keyof IntlFormats['number'] | NumberFormatOptions
) {
return getFormattedValue(
formatOrOptions,
Expand Down Expand Up @@ -284,7 +284,7 @@ export default function createFormatter({
type FormattableListValue = string | ReactElement;
function list<Value extends FormattableListValue>(
value: Iterable<Value>,
formatOrOptions?: string | Intl.ListFormatOptions
formatOrOptions?: IntlFormats['list'] | Intl.ListFormatOptions
dBianchii marked this conversation as resolved.
Show resolved Hide resolved
): Value extends string ? string : Iterable<ReactElement> {
const serializedValue: Array<string> = [];
const richValues = new Map<string, Value>();
Expand Down
6 changes: 6 additions & 0 deletions packages/use-intl/src/react/useFormatter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('dateTime', () => {
it('can use a global date format', () => {
function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.dateTime(mockDate, 'onlyYear')}</>;
}

Expand All @@ -82,6 +83,7 @@ describe('dateTime', () => {
it('can use a global time format', () => {
function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.dateTime(mockDate, 'onlyHours')}</>;
}

Expand Down Expand Up @@ -191,6 +193,7 @@ describe('dateTime', () => {

function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.dateTime(mockDate, 'onlyYear')}</>;
}

Expand Down Expand Up @@ -218,6 +221,7 @@ describe('dateTime', () => {

function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.dateTime(mockDate, 'medium')}</>;
}

Expand Down Expand Up @@ -315,6 +319,7 @@ describe('number', () => {
it('can use a global format', () => {
function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.number(10000, 'noGrouping')}</>;
}

Expand Down Expand Up @@ -370,6 +375,7 @@ describe('number', () => {

function Component() {
const format = useFormatter();
// @ts-expect-error
return <>{format.number(mockNumber, 'missing')}</>;
}

Expand Down
10 changes: 9 additions & 1 deletion packages/use-intl/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
// This type is intended to be overridden
// by the consumer for optional type safety
// by the consumer for optional type safety of messages
declare interface IntlMessages extends Record<string, any> {}

// This type is intended to be overridden
// by the consumer for optional type safety of formats
declare interface IntlFormats {
dateTime: {};
number: {};
list: {};
dBianchii marked this conversation as resolved.
Show resolved Hide resolved
}

// Temporarly copied here until the "es2020.intl" lib is published.

declare namespace Intl {
Expand Down
Loading
Loading