From 8c4ef3e0d155261c1c6f2bde4f88e693fe5b800c Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Fri, 23 Jun 2023 08:37:11 +0200 Subject: [PATCH] refactor: Switch to a string argument for the `locale` that is passed to the non-component APIs --- .../src/app/[locale]/layout.tsx | 13 +++--- .../src/app/[locale]/layout.tsx | 9 ++-- .../src/react-server/useFormatter.tsx | 2 +- .../next-intl/src/react-server/useNow.tsx | 2 +- .../src/react-server/useTimeZone.tsx | 2 +- .../src/react-server/useTranslations.tsx | 2 +- .../next-intl/src/server/getFormatter.tsx | 37 +++++++++++++---- packages/next-intl/src/server/getNow.tsx | 37 +++++++++++++---- packages/next-intl/src/server/getTimeZone.tsx | 37 +++++++++++++---- .../next-intl/src/server/getTranslator.tsx | 41 +++++++++++++++---- 10 files changed, 137 insertions(+), 45 deletions(-) diff --git a/examples/example-next-13-advanced/src/app/[locale]/layout.tsx b/examples/example-next-13-advanced/src/app/[locale]/layout.tsx index 45507d939..bac9e11aa 100644 --- a/examples/example-next-13-advanced/src/app/[locale]/layout.tsx +++ b/examples/example-next-13-advanced/src/app/[locale]/layout.tsx @@ -15,15 +15,12 @@ type Props = { }; export async function generateMetadata({ - params + params: {locale} }: Omit): Promise { - const t = await getTranslator({ - namespace: 'LocaleLayout', - locale: params.locale - }); - const formatter = await getFormatter({locale: params.locale}); - const now = await getNow({locale: params.locale}); - const timeZone = await getTimeZone({locale: params.locale}); + const t = await getTranslator(locale, 'LocaleLayout'); + const formatter = await getFormatter(locale); + const now = await getNow(locale); + const timeZone = await getTimeZone(locale); return { title: t('title'), diff --git a/examples/example-next-13/src/app/[locale]/layout.tsx b/examples/example-next-13/src/app/[locale]/layout.tsx index 014b2520e..9ad57533e 100644 --- a/examples/example-next-13/src/app/[locale]/layout.tsx +++ b/examples/example-next-13/src/app/[locale]/layout.tsx @@ -13,11 +13,10 @@ type Props = { params: {locale: string}; }; -export async function generateMetadata({params}: Omit) { - const t = await getTranslator({ - locale: params.locale, - namespace: 'LocaleLayout' - }); +export async function generateMetadata({ + params: {locale} +}: Omit) { + const t = await getTranslator(locale, 'LocaleLayout'); return { title: t('title') diff --git a/packages/next-intl/src/react-server/useFormatter.tsx b/packages/next-intl/src/react-server/useFormatter.tsx index 4001d0e64..30230ef58 100644 --- a/packages/next-intl/src/react-server/useFormatter.tsx +++ b/packages/next-intl/src/react-server/useFormatter.tsx @@ -8,5 +8,5 @@ export default function useFormatter( ...[]: Parameters ): ReturnType { const locale = useLocale(); - return useHook('useFormatter', getFormatter({locale})); + return useHook('useFormatter', getFormatter(locale)); } diff --git a/packages/next-intl/src/react-server/useNow.tsx b/packages/next-intl/src/react-server/useNow.tsx index 289b73c4f..4359126cf 100644 --- a/packages/next-intl/src/react-server/useNow.tsx +++ b/packages/next-intl/src/react-server/useNow.tsx @@ -13,5 +13,5 @@ export default function useNow( } const locale = useLocale(); - return useHook('useNow', getNow({locale})); + return useHook('useNow', getNow(locale)); } diff --git a/packages/next-intl/src/react-server/useTimeZone.tsx b/packages/next-intl/src/react-server/useTimeZone.tsx index 4b5e4508a..a9907a4cd 100644 --- a/packages/next-intl/src/react-server/useTimeZone.tsx +++ b/packages/next-intl/src/react-server/useTimeZone.tsx @@ -8,5 +8,5 @@ export default function useTimeZone( ...[]: Parameters ): ReturnType { const locale = useLocale(); - return useHook('useTimeZone', getTimeZone({locale})); + return useHook('useTimeZone', getTimeZone(locale)); } diff --git a/packages/next-intl/src/react-server/useTranslations.tsx b/packages/next-intl/src/react-server/useTranslations.tsx index b3bea0824..b95893231 100644 --- a/packages/next-intl/src/react-server/useTranslations.tsx +++ b/packages/next-intl/src/react-server/useTranslations.tsx @@ -7,7 +7,7 @@ export default function useTranslations( ...[namespace]: Parameters ): ReturnType { const locale = useLocale(); - const result = useHook('useTranslations', getTranslator({namespace, locale})); + const result = useHook('useTranslations', getTranslator(locale, namespace)); // The types are slightly off here and indicate that rich text formatting // doesn't integrate with React - this is not the case. diff --git a/packages/next-intl/src/server/getFormatter.tsx b/packages/next-intl/src/server/getFormatter.tsx index 0341bb749..df251c434 100644 --- a/packages/next-intl/src/server/getFormatter.tsx +++ b/packages/next-intl/src/server/getFormatter.tsx @@ -3,7 +3,8 @@ import {createFormatter} from 'use-intl/dist/src/core'; import getConfig from './getConfig'; import getLocaleFromHeader from './getLocaleFromHeader'; -let hasWarned = false; +let hasWarnedForMissingLocale = false; +let hasWarnedForObjectArgument = false; /** * Returns a formatter based on the given locale. @@ -11,10 +12,32 @@ let hasWarned = false; * The formatter automatically receives the request config, but * you can override it by passing in additional options. */ -const getFormatter = cache(async (opts?: {locale: string}) => { - if (!opts?.locale && !hasWarned) { - hasWarned = true; - console.warn(` +const getFormatter = cache(async (locale?: string | {locale: string}) => { + if (typeof locale === 'object') { + locale = locale.locale; + if (!hasWarnedForObjectArgument) { + hasWarnedForObjectArgument = true; + console.warn( + ` +DEPRECATION WARNING: Calling \`getFormatter\` with an object argument is deprecated, please update your call site accordingly. + +// Previously +getFormatter({locale: 'en'}); + +// Now +getFormatter('en'); + +See also https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components +` + ); + } + } + + if (!locale) { + locale = getLocaleFromHeader(); + if (!hasWarnedForMissingLocale) { + hasWarnedForMissingLocale = true; + console.warn(` Calling \`getFormatter\` without a locale is deprecated, please update the call: // app/[locale]/layout.tsx @@ -26,11 +49,11 @@ export async function generateMetadata({params}) { Learn more: https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components `); + } } - const locale = opts?.locale || getLocaleFromHeader(); const config = await getConfig(locale); - return createFormatter({...config, ...opts}); + return createFormatter(config); }); export default getFormatter; diff --git a/packages/next-intl/src/server/getNow.tsx b/packages/next-intl/src/server/getNow.tsx index 1c97dc7f8..56f15cf81 100644 --- a/packages/next-intl/src/server/getNow.tsx +++ b/packages/next-intl/src/server/getNow.tsx @@ -2,13 +2,36 @@ import {cache} from 'react'; import getConfig from './getConfig'; import getLocaleFromHeader from './getLocaleFromHeader'; -let hasWarned = false; +let hasWarnedForMissingLocale = false; +let hasWarnedForObjectArgument = false; -const getNow = cache(async (opts?: {locale: string}) => { - if (!opts?.locale && !hasWarned) { - hasWarned = true; - console.warn(` -Calling \`getNow\` without a locale is deprecated. Please update the call: +const getNow = cache(async (locale?: string | {locale: string}) => { + if (typeof locale === 'object') { + locale = locale.locale; + if (!hasWarnedForObjectArgument) { + hasWarnedForObjectArgument = true; + console.warn( + ` +DEPRECATION WARNING: Calling \`getNow\` with an object argument is deprecated, please update your call site accordingly. + +// Previously +getNow({locale: 'en'}); + +// Now +getNow('en'); + +See also https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components +` + ); + } + } + + if (!locale) { + locale = getLocaleFromHeader(); + if (!hasWarnedForMissingLocale) { + hasWarnedForMissingLocale = true; + console.warn(` +Calling \`getNow\` without a locale is deprecated, please update the call: // app/[locale]/layout.tsx export async function generateMetadata({params}) { @@ -19,9 +42,9 @@ export async function generateMetadata({params}) { Learn more: https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components `); + } } - const locale = opts?.locale || getLocaleFromHeader(); const config = await getConfig(locale); return config.now; }); diff --git a/packages/next-intl/src/server/getTimeZone.tsx b/packages/next-intl/src/server/getTimeZone.tsx index 43bff5bb0..29fa80d66 100644 --- a/packages/next-intl/src/server/getTimeZone.tsx +++ b/packages/next-intl/src/server/getTimeZone.tsx @@ -2,13 +2,36 @@ import {cache} from 'react'; import getConfig from './getConfig'; import getLocaleFromHeader from './getLocaleFromHeader'; -let hasWarned = false; +let hasWarnedForMissingLocale = false; +let hasWarnedForObjectArgument = false; -const getTimeZone = cache(async (opts?: {locale: string}) => { - if (!opts?.locale && !hasWarned) { - hasWarned = true; - console.warn(` -Calling \`getTimeZone\` without a locale is deprecated. Please update the call: +const getTimeZone = cache(async (locale?: string | {locale: string}) => { + if (typeof locale === 'object') { + locale = locale.locale; + if (!hasWarnedForObjectArgument) { + hasWarnedForObjectArgument = true; + console.warn( + ` +DEPRECATION WARNING: Calling \`getTimeZone\` with an object argument is deprecated, please update your call site accordingly. + +// Previously +getTimeZone({locale: 'en'}); + +// Now +getTimeZone('en'); + +See also https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components +` + ); + } + } + + if (!locale) { + locale = getLocaleFromHeader(); + if (!hasWarnedForMissingLocale) { + hasWarnedForMissingLocale = true; + console.warn(` +Calling \`getTimeZone\` without a locale is deprecated, please update the call: // app/[locale]/layout.tsx export async function generateMetadata({params}) { @@ -19,9 +42,9 @@ export async function generateMetadata({params}) { Learn more: https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components `); + } } - const locale = opts?.locale || getLocaleFromHeader(); const config = await getConfig(locale); return config.timeZone; }); diff --git a/packages/next-intl/src/server/getTranslator.tsx b/packages/next-intl/src/server/getTranslator.tsx index a1a69cb92..4dbb1ec44 100644 --- a/packages/next-intl/src/server/getTranslator.tsx +++ b/packages/next-intl/src/server/getTranslator.tsx @@ -13,15 +13,22 @@ import NestedKeyOf from 'use-intl/dist/src/core/utils/NestedKeyOf'; import NestedValueOf from 'use-intl/dist/src/core/utils/NestedValueOf'; import getConfig from './getConfig'; +let hasWarned = false; + async function getTranslatorImpl< NestedKey extends NamespaceKeys< IntlMessages, NestedKeyOf > = never ->(opts: { - namespace?: NestedKey; - locale: string; -}): // Explicitly defining the return type is necessary as TypeScript would get it wrong +>( + locale: + | string + | { + namespace?: NestedKey; + locale: string; + }, + namespace?: NestedKey +): // Explicitly defining the return type is necessary as TypeScript would get it wrong Promise<{ // Default invocation < @@ -81,11 +88,32 @@ Promise<{ key: TargetKey ): any; }> { - const config = await getConfig(opts.locale); + if (typeof locale === 'object') { + namespace = locale.namespace; + locale = locale.locale; + if (!hasWarned) { + console.warn( + ` +DEPRECATION WARNING: Calling \`getTranslator\` with an object argument is deprecated, please update your call site accordingly. + +// Previously +getTranslator({locale: 'en', namespace: 'About'}); + +// Now +getTranslator('en', 'About'); + +See also https://next-intl-docs.vercel.app/docs/next-13/server-components#using-internationalization-outside-of-components +` + ); + hasWarned = true; + } + } + + const config = await getConfig(locale); const messagesOrError = getMessagesOrError({ messages: config.messages as any, - namespace: opts.namespace, + namespace, onError: config.onError }); @@ -95,7 +123,6 @@ Promise<{ // @ts-ignore return createBaseTranslator({ ...config, - ...opts, messagesOrError }); }