diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d3f2d73f4..86d2cf7b7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 }} diff --git a/examples/example-app-router-migration/src/app/[locale]/layout.tsx b/examples/example-app-router-migration/src/app/[locale]/layout.tsx index 5d3c87400..6864db0de 100644 --- a/examples/example-app-router-migration/src/app/[locale]/layout.tsx +++ b/examples/example-app-router-migration/src/app/[locale]/layout.tsx @@ -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'; @@ -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 ( next-intl - {children} + + + {children} + + ); } diff --git a/examples/example-app-router-playground/src/components/MessagesTest.tsx b/examples/example-app-router-playground/src/components/MessagesTest.tsx new file mode 100644 index 000000000..88f725260 --- /dev/null +++ b/examples/example-app-router-playground/src/components/MessagesTest.tsx @@ -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; +} diff --git a/packages/next-intl/src/server/react-server/getMessages.tsx b/packages/next-intl/src/server/react-server/getMessages.tsx index 4129b1b93..39ac4ca0d 100644 --- a/packages/next-intl/src/server/react-server/getMessages.tsx +++ b/packages/next-intl/src/server/react-server/getMessages.tsx @@ -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> -): AbstractIntlMessages { +): ReturnType { if (!config.messages) { throw new Error( 'No messages found. Have you configured them correctly? See https://next-intl-docs.vercel.app/docs/configuration#messages' @@ -19,8 +19,6 @@ async function getMessagesCachedImpl(locale?: string) { } const getMessagesCached = cache(getMessagesCachedImpl); -export default async function getMessages(opts?: { - locale?: string; -}): Promise { +export default async function getMessages(opts?: {locale?: string}) { return getMessagesCached(opts?.locale); } diff --git a/packages/next-intl/src/server/react-server/index.test.tsx b/packages/next-intl/src/server/react-server/index.test.tsx index 2f0d92f67..8f6054387 100644 --- a/packages/next-intl/src/server/react-server/index.test.tsx +++ b/packages/next-intl/src/server/react-server/index.test.tsx @@ -150,7 +150,7 @@ describe('getMessages', () => { const messages = await getMessages(); // @ts-expect-error - messages.about(); + messages(); // Valid return messages.about; diff --git a/packages/use-intl/src/core/AbstractIntlMessages.tsx b/packages/use-intl/src/core/AbstractIntlMessages.tsx index 42f02a333..3a62dec89 100644 --- a/packages/use-intl/src/core/AbstractIntlMessages.tsx +++ b/packages/use-intl/src/core/AbstractIntlMessages.tsx @@ -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 = { diff --git a/packages/use-intl/src/react/useMessages.tsx b/packages/use-intl/src/react/useMessages.tsx index 31a4bf48a..e921c4a0e 100644 --- a/packages/use-intl/src/react/useMessages.tsx +++ b/packages/use-intl/src/react/useMessages.tsx @@ -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) {