Skip to content

Commit

Permalink
feat: Return type-safe IntlMessages from useMessages & `getMessag…
Browse files Browse the repository at this point in the history
…es` (#1489)

If consumers use type-safe `IntlMessages`, these will now be used for
`useMessages` and `getMessages`.

Fixes #1452
  • Loading branch information
amannn authored Oct 30, 2024
1 parent b4e4d1d commit d83abc2
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
jobs:
build:
name: Build, lint, and test
runs-on: ubuntu-latest
runs-on: macos-15
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {notFound} from 'next/navigation';
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
import {ReactNode} from 'react';
import {routing} from '@/i18n/routing';

Expand All @@ -13,12 +15,20 @@ export default async function LocaleLayout({children, params}: Props) {
notFound();
}

// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();

return (
<html lang={params.locale}>
<head>
<title>next-intl</title>
</head>
<body>{children}</body>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import {useMessages} from 'next-intl';
import {getMessages} from 'next-intl/server';

export async function GetMessages() {
const messages = await getMessages();

// Valid
messages.Index;
messages.Index.title;

// Invalid
// @ts-expect-error
messages.Unknown;
// @ts-expect-error
messages.Index.unknown;
}

export function UseMessages() {
const messages = useMessages();

// Valid
messages.Index;
messages.Index.title;

// Invalid
// @ts-expect-error
messages.Unknown;
// @ts-expect-error
messages.Index.unknown;
}
8 changes: 3 additions & 5 deletions packages/next-intl/src/server/react-server/getMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {cache} from 'react';
import type {AbstractIntlMessages} from 'use-intl';
import type {useMessages as useMessagesType} from 'use-intl';
import getConfig from './getConfig.tsx';

export function getMessagesFromConfig(
config: Awaited<ReturnType<typeof getConfig>>
): AbstractIntlMessages {
): ReturnType<typeof useMessagesType> {
if (!config.messages) {
throw new Error(
'No messages found. Have you configured them correctly? See https://next-intl-docs.vercel.app/docs/configuration#messages'
Expand All @@ -19,8 +19,6 @@ async function getMessagesCachedImpl(locale?: string) {
}
const getMessagesCached = cache(getMessagesCachedImpl);

export default async function getMessages(opts?: {
locale?: string;
}): Promise<AbstractIntlMessages> {
export default async function getMessages(opts?: {locale?: string}) {
return getMessagesCached(opts?.locale);
}
2 changes: 1 addition & 1 deletion packages/next-intl/src/server/react-server/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ describe('getMessages', () => {
const messages = await getMessages();

// @ts-expect-error
messages.about();
messages();

// Valid
return messages.about;
Expand Down
5 changes: 3 additions & 2 deletions packages/use-intl/src/core/AbstractIntlMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** A generic type that describes the shape of messages.
/**
* A generic type that describes the shape of messages.
*
* Optionally `IntlMessages` can be provided to get type safety for message
* Optionally, `IntlMessages` can be provided to get type safety for message
* namespaces and keys. See https://next-intl-docs.vercel.app/docs/usage/typescript
*/
type AbstractIntlMessages = {
Expand Down
3 changes: 1 addition & 2 deletions packages/use-intl/src/react/useMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {AbstractIntlMessages} from '../core.tsx';
import useIntlContext from './useIntlContext.tsx';

export default function useMessages(): AbstractIntlMessages {
export default function useMessages(): IntlMessages {
const context = useIntlContext();

if (!context.messages) {
Expand Down

0 comments on commit d83abc2

Please sign in to comment.