diff --git a/.changeset/forty-waves-add.md b/.changeset/forty-waves-add.md new file mode 100644 index 000000000..41b4eebf1 --- /dev/null +++ b/.changeset/forty-waves-add.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Normalizes translations across all pages, updates the next-intl configuration, and simplifies translation handling in the project. diff --git a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx index 782f42daa..35f0666fb 100644 --- a/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/brand/[slug]/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; -import { NextIntlClientProvider } from 'next-intl'; -import { getMessages, getTranslations, unstable_setRequestLocale } from 'next-intl/server'; +import { getTranslations, unstable_setRequestLocale } from 'next-intl/server'; import { ProductCard } from '~/components/product-card'; import { Pagination } from '~/components/ui/pagination'; @@ -43,8 +42,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function Brand({ params: { slug, locale }, searchParams }: Props) { unstable_setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: 'Brand' }); - const messages = await getMessages({ locale }); + const t = await getTranslations('Brand'); const brandId = Number(slug); @@ -63,70 +61,61 @@ export default async function Brand({ params: { slug, locale }, searchParams }: return (
- -
-

{brand.name}

- -
- - - -
- -
- {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })} -
+
+

{brand.name}

+ +
+ + + +
+ +
+ {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })}
+
+ +
+ + +
+

+ {t('products')} +

+ +
+ {products.map((product, index) => ( + + ))} +
-
- - -
-

- {t('products')} -

- -
- {products.map((product, index) => ( - - ))} -
- - -
-
- +
+
); } diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/sub-categories.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/sub-categories.tsx index b4a95b890..8d38bae6f 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/sub-categories.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/_components/sub-categories.tsx @@ -1,4 +1,4 @@ -import { getTranslations } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; import { FragmentOf, graphql } from '~/client/graphql'; import { Link } from '~/components/link'; @@ -30,8 +30,8 @@ interface Props { categoryTree: CategoryTree; } -export async function SubCategories({ categoryTree }: Props) { - const t = await getTranslations('FacetedGroup.MobileSideNav'); +export function SubCategories({ categoryTree }: Props) { + const t = useTranslations('FacetedGroup.MobileSideNav'); if (!categoryTree[0]?.children?.length) { return null; diff --git a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx index 67b97dd6a..236003ca4 100644 --- a/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/category/[slug]/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; -import { NextIntlClientProvider } from 'next-intl'; -import { getMessages, getTranslations, unstable_setRequestLocale } from 'next-intl/server'; +import { getTranslations, unstable_setRequestLocale } from 'next-intl/server'; import { Breadcrumbs } from '~/components/breadcrumbs'; import { ProductCard } from '~/components/product-card'; @@ -50,8 +49,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function Category({ params: { locale, slug }, searchParams }: Props) { unstable_setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: 'Category' }); - const messages = await getMessages({ locale }); + const t = await getTranslations('Category'); const categoryId = Number(slug); @@ -71,74 +69,65 @@ export default async function Category({ params: { locale, slug }, searchParams return (
- -
-

{category.name}

- -
- - - - - -
- -
- {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })} -
+
+

{category.name}

+ +
+ + + + + +
+ +
+ {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })}
+
+ +
+ + + + +
+

+ {t('products')} +

+ +
+ {products.map((product, index) => ( + + ))} +
-
- - - - -
-

- {t('products')} -

- -
- {products.map((product, index) => ( - - ))} -
- - -
-
- + +
+
); diff --git a/core/app/[locale]/(default)/(faceted)/search/page.tsx b/core/app/[locale]/(default)/(faceted)/search/page.tsx index a1a459982..3fb58ad61 100644 --- a/core/app/[locale]/(default)/(faceted)/search/page.tsx +++ b/core/app/[locale]/(default)/(faceted)/search/page.tsx @@ -1,10 +1,8 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getMessages, getTranslations } from 'next-intl/server'; +import { getTranslations } from 'next-intl/server'; import { ProductCard } from '~/components/product-card'; import { SearchForm } from '~/components/search-form'; import { Pagination } from '~/components/ui/pagination'; -import { LocaleType } from '~/i18n'; import { FacetedSearch } from '../_components/faceted-search'; import { MobileSideNav } from '../_components/mobile-side-nav'; @@ -16,23 +14,19 @@ export const metadata = { }; interface Props { - params: { locale: LocaleType }; searchParams: Record; } -export default async function Search({ params: { locale }, searchParams }: Props) { +export default async function Search({ searchParams }: Props) { const t = await getTranslations('Search'); - const messages = await getMessages({ locale }); const searchTerm = typeof searchParams.term === 'string' ? searchParams.term : undefined; if (!searchTerm) { return ( <>

{t('heading')}

- - - + ); } @@ -45,9 +39,7 @@ export default async function Search({ params: { locale }, searchParams }: Props if (products.length === 0) { return (
- - - +
); } @@ -56,72 +48,63 @@ export default async function Search({ params: { locale }, searchParams }: Props return (
- -
-

- {t('searchResults')}
- "{searchTerm}" -

- -
- - - -
- -
- {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })} -
+
+

+ {t('searchResults')}
+ "{searchTerm}" +

+ +
+ + + +
+ +
+ {t('sortBy', { items: productsCollection.collectionInfo?.totalItems ?? 0 })}
+
-
- -
-

- {t('products')} -

- -
- {products.map((product, index) => ( - - ))} -
+
+ +
+

+ {t('products')} +

+ +
+ {products.map((product, index) => ( + + ))} +
- -
-
- + +
+
); } diff --git a/core/app/[locale]/(default)/account/(tabs)/_components/tab-heading.tsx b/core/app/[locale]/(default)/account/(tabs)/_components/tab-heading.tsx index de1009d02..0d4727108 100644 --- a/core/app/[locale]/(default)/account/(tabs)/_components/tab-heading.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/_components/tab-heading.tsx @@ -1,10 +1,9 @@ -import { getLocale, getTranslations } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; import { TabType } from '../layout'; -export const TabHeading = async ({ heading }: { heading: TabType }) => { - const locale = await getLocale(); - const t = await getTranslations({ locale, namespace: 'Account.Home' }); +export const TabHeading = ({ heading }: { heading: TabType }) => { + const t = useTranslations('Account.Home'); return

{t(heading)}

; }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/add-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/add-address.ts index fabd15b89..9f12e3e5d 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/add-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/add-address.ts @@ -1,6 +1,7 @@ 'use server'; import { revalidatePath } from 'next/cache'; +import { getTranslations } from 'next-intl/server'; import { parseAccountFormData } from '~/app/[locale]/(default)/login/register-customer/_components/register-customer-form/fields/parse-fields'; import { getSessionCustomerId } from '~/auth'; @@ -54,6 +55,8 @@ export const addAddress = async ({ formData: FormData; reCaptchaToken?: string; }) => { + const t = await getTranslations('Account.Addresses.AddAddress'); + const customerId = await getSessionCustomerId(); try { @@ -62,7 +65,7 @@ export const addAddress = async ({ if (!isAddCustomerAddressInput(parsed)) { return { status: 'error', - error: 'Something went wrong with proccessing user input.', + error: t('Errors.inputError'), }; } @@ -81,7 +84,7 @@ export const addAddress = async ({ revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: 'The address has been added.' }; + return { status: 'success', message: t('success') }; } return { @@ -96,6 +99,6 @@ export const addAddress = async ({ }; } - return { status: 'error', message: 'Unknown error.' }; + return { status: 'error', message: t('Errors.error') }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts index 1d8f55c55..125698b2b 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts @@ -1,6 +1,7 @@ 'use server'; import { revalidatePath } from 'next/cache'; +import { getTranslations } from 'next-intl/server'; import { getSessionCustomerId } from '~/auth'; import { client } from '~/client'; @@ -32,6 +33,8 @@ const DeleteCustomerAddressMutation = graphql(` `); export const deleteAddress = async (addressId: number): Promise => { + const t = await getTranslations('Account.Addresses.DeleteAddress'); + const customerId = await getSessionCustomerId(); try { @@ -51,7 +54,7 @@ export const deleteAddress = async (addressId: number): Promise => { revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: 'Address deleted from your account.' }; + return { status: 'success', message: t('success') }; } return { @@ -66,6 +69,6 @@ export const deleteAddress = async (addressId: number): Promise => { }; } - return { status: 'error', message: 'Unknown error.' }; + return { status: 'error', message: t('error') }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/update-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/update-address.ts index bc96f8ebf..8d7f4c8ac 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/update-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/update-address.ts @@ -1,6 +1,7 @@ 'use server'; import { revalidatePath } from 'next/cache'; +import { getTranslations } from 'next-intl/server'; import { parseAccountFormData } from '~/app/[locale]/(default)/login/register-customer/_components/register-customer-form/fields/parse-fields'; import { getSessionCustomerId } from '~/auth'; @@ -59,6 +60,8 @@ export const updateAddress = async ({ formData: FormData; reCaptchaToken?: string; }) => { + const t = await getTranslations('Account.Addresses.UpdateAddress'); + const customerId = await getSessionCustomerId(); try { @@ -67,7 +70,7 @@ export const updateAddress = async ({ if (!isUpdateCustomerAddressInput(parsed)) { return { status: 'error', - error: 'Something went wrong with proccessing user input.', + error: t('Errors.inputError'), }; } @@ -89,7 +92,7 @@ export const updateAddress = async ({ revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: 'The address has been updated.' }; + return { status: 'success', message: t('success') }; } return { @@ -97,7 +100,7 @@ export const updateAddress = async ({ message: result.errors .map((error) => { if (error.__typename === 'AddressDoesNotExistError') { - return 'Address does not exist.'; + return t('Errors.notFound'); } return error.message; @@ -112,6 +115,6 @@ export const updateAddress = async ({ }; } - return { status: 'error', message: 'Unknown error.' }; + return { status: 'error', message: t('Errors.error') }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/addresses-content.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/addresses-content.tsx index 5c1e222cb..f45a30924 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/addresses-content.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/addresses-content.tsx @@ -1,4 +1,4 @@ -import { getLocale, getTranslations } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; import { ExistingResultType } from '~/client/util'; import { Pagination } from '~/components/ui/pagination'; @@ -19,15 +19,15 @@ interface Props { pageInfo: CustomerAddresses['pageInfo']; } -export const AddressesContent = async ({ +export const AddressesContent = ({ addresses, addressesCount, activeAddressId, customerAction, pageInfo, }: Props) => { - const locale = await getLocale(); - const t = await getTranslations({ locale, namespace: 'Account.Addresses' }); + const t = useTranslations('Account.Addresses'); + const { hasNextPage, hasPreviousPage, startCursor, endCursor } = pageInfo; if (customerAction === 'add-new-address') { diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-edit-address.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-edit-address.tsx index 66a88c071..4d9cb6136 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-edit-address.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-edit-address.tsx @@ -1,6 +1,3 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getLocale, getMessages } from 'next-intl/server'; - import { getSessionCustomerId } from '~/auth'; import { client } from '~/client'; import { FormFieldsFragment } from '~/client/fragments/form-fields'; @@ -67,8 +64,6 @@ export async function CustomerEditAddress({ isAddressRemovable: boolean; }) { const customerId = await getSessionCustomerId(); - const locale = await getLocale(); - const messages = await getMessages(); const { data } = await client.fetch({ document: CustomerEditAdressQuery, @@ -84,14 +79,12 @@ export async function CustomerEditAddress({ const addressFields = [...(data.site.settings?.formFields.shippingAddress ?? [])]; return ( - - - + ); } diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-new-address.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-new-address.tsx index cce1c658a..6669ed2a1 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-new-address.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/customer-new-address.tsx @@ -1,6 +1,3 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getLocale, getMessages } from 'next-intl/server'; - import { getSessionCustomerId } from '~/auth'; import { client } from '~/client'; import { FormFieldsFragment } from '~/client/fragments/form-fields'; @@ -61,8 +58,6 @@ const FALLBACK_COUNTRY = { export const CustomerNewAddress = async () => { const customerId = await getSessionCustomerId(); - const locale = await getLocale(); - const messages = await getMessages(); const { data } = await client.fetch({ document: CustomerNewAdressQuery, @@ -85,13 +80,11 @@ export const CustomerNewAddress = async () => { } = countries?.find(({ name: country }) => country === defaultCountry) || {}; return ( - - - + ); }; diff --git a/core/app/[locale]/(default)/account/(tabs)/layout.tsx b/core/app/[locale]/(default)/account/(tabs)/layout.tsx index f15fa27bb..ba0474bce 100644 --- a/core/app/[locale]/(default)/account/(tabs)/layout.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/layout.tsx @@ -1,5 +1,5 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getMessages, getTranslations, unstable_setRequestLocale } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; +import { unstable_setRequestLocale } from 'next-intl/server'; import { PropsWithChildren } from 'react'; import { Link } from '~/components/link'; @@ -16,12 +16,10 @@ interface Props extends PropsWithChildren { params: { locale: LocaleType; tab?: TabType }; } -export default async function AccountTabLayout({ children, params: { locale } }: Props) { +export default function AccountTabLayout({ children, params: { locale } }: Props) { unstable_setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: 'Account.Home' }); - - const messages = await getMessages(); + const t = useTranslations('Account.Home'); const tabsTitles = { addresses: t('addresses'), @@ -29,27 +27,25 @@ export default async function AccountTabLayout({ children, params: { locale } }: }; return ( - - -

{t('heading')}

- - {children} -
-
+ +

{t('heading')}

+ + {children} +
); } diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/submit-customer-change-password-form.ts b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/submit-customer-change-password-form.ts index cf5585c8a..8214fe2f3 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/submit-customer-change-password-form.ts +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/submit-customer-change-password-form.ts @@ -1,5 +1,6 @@ 'use server'; +import { getTranslations } from 'next-intl/server'; import { z } from 'zod'; import { getSessionCustomerId } from '~/auth'; @@ -52,6 +53,8 @@ export const submitCustomerChangePasswordForm = async ( _previousState: unknown, formData: FormData, ) => { + const t = await getTranslations('Account.Settings.ChangePassword'); + const customerId = await getSessionCustomerId(); try { @@ -75,7 +78,7 @@ export const submitCustomerChangePasswordForm = async ( const result = response.data.customer.changePassword; if (result.errors.length === 0) { - return { status: 'success', message: 'Password has been updated successfully.' }; + return { status: 'success', message: t('success') }; } return { @@ -99,6 +102,6 @@ export const submitCustomerChangePasswordForm = async ( }; } - return { status: 'error', message: 'Unknown error.' }; + return { status: 'error', message: t('error') }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts index e705b499b..dab99e841 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts @@ -1,6 +1,7 @@ 'use server'; import { revalidatePath } from 'next/cache'; +import { getTranslations } from 'next-intl/server'; import { parseAccountFormData } from '~/app/[locale]/(default)/login/register-customer/_components/register-customer-form/fields/parse-fields'; import { getSessionCustomerId } from '~/auth'; @@ -63,6 +64,8 @@ interface UpdateCustomerForm { } export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustomerForm) => { + const t = await getTranslations('Account.Settings.UpdateCustomer'); + const customerId = await getSessionCustomerId(); formData.delete('g-recaptcha-response'); @@ -72,7 +75,7 @@ export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustome if (!isUpdateCustomerInput(parsed)) { return { status: 'error', - error: 'Something went wrong with proccessing user input.', + error: t('Errors.inputError'), }; } @@ -96,7 +99,7 @@ export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustome if (!customer) { return { status: 'error', - error: 'Customer does not exist', + error: t('Errors.notFound'), }; } diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_components/change-password-form.tsx b/core/app/[locale]/(default)/account/(tabs)/settings/_components/change-password-form.tsx index 46a3f5a6b..eb218dc5c 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_components/change-password-form.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_components/change-password-form.tsx @@ -18,7 +18,7 @@ import { Input, } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; -import { useRouter } from '~/navigation'; +import { useRouter } from '~/routing'; import { submitCustomerChangePasswordForm } from '../_actions/submit-customer-change-password-form'; diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_components/settings-content.tsx b/core/app/[locale]/(default)/account/(tabs)/settings/_components/settings-content.tsx index 7208bb95d..b963c1b07 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_components/settings-content.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_components/settings-content.tsx @@ -1,6 +1,3 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getLocale, getMessages } from 'next-intl/server'; - import { ExistingResultType } from '~/client/util'; import { getCustomerSettingsQuery } from '../page-data'; @@ -15,16 +12,11 @@ interface Props { type CustomerSettings = ExistingResultType; -export const SettingsContent = async ({ action, customerSettings }: Props) => { - const locale = await getLocale(); - const messages = await getMessages({ locale }); - +export const SettingsContent = ({ action, customerSettings }: Props) => { if (action === 'change_password') { return (
- - - +
); } diff --git a/core/app/[locale]/(default)/account/page.tsx b/core/app/[locale]/(default)/account/page.tsx index 6fed50854..1a615ac02 100644 --- a/core/app/[locale]/(default)/account/page.tsx +++ b/core/app/[locale]/(default)/account/page.tsx @@ -1,9 +1,8 @@ import { BookUser, Settings } from 'lucide-react'; -import { getTranslations } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; import { ReactNode } from 'react'; import { Link } from '~/components/link'; -import { LocaleType } from '~/i18n'; interface AccountItem { children: ReactNode; @@ -27,14 +26,8 @@ const AccountItem = ({ children, title, description, href }: AccountItem) => { ); }; -interface Props { - params: { - locale: LocaleType; - }; -} - -export default async function Account({ params: { locale } }: Props) { - const t = await getTranslations({ locale, namespace: 'Account.Home' }); +export default function Account() { + const t = useTranslations('Account.Home'); return (
diff --git a/core/app/[locale]/(default)/blog/[blogId]/_components/print-button.tsx b/core/app/[locale]/(default)/blog/[blogId]/_components/print-button.tsx index d0214421f..54ad5bf9e 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/_components/print-button.tsx +++ b/core/app/[locale]/(default)/blog/[blogId]/_components/print-button.tsx @@ -1,19 +1,24 @@ 'use client'; import { Printer } from 'lucide-react'; +import { useTranslations } from 'next-intl'; -export const PrintButton = () => ( - -); + return ( + + ); +}; diff --git a/core/app/[locale]/(default)/blog/[blogId]/_components/sharing-links.tsx b/core/app/[locale]/(default)/blog/[blogId]/_components/sharing-links.tsx index fdbc90f20..bc0720b75 100644 --- a/core/app/[locale]/(default)/blog/[blogId]/_components/sharing-links.tsx +++ b/core/app/[locale]/(default)/blog/[blogId]/_components/sharing-links.tsx @@ -1,5 +1,6 @@ import { SiFacebook, SiLinkedin, SiPinterest, SiX } from '@icons-pack/react-simple-icons'; import { Mail } from 'lucide-react'; +import { useTranslations } from 'next-intl'; import { FragmentOf, graphql } from '~/client/graphql'; @@ -33,6 +34,8 @@ interface Props { } export const SharingLinks = ({ data }: Props) => { + const t = useTranslations('Blog.SharingLinks'); + const blogPost = data.content.blog?.post; if (!blogPost) { @@ -46,7 +49,7 @@ export const SharingLinks = ({ data }: Props) => { return ( - +
); } diff --git a/core/app/[locale]/(default)/cart/_components/cart-item.tsx b/core/app/[locale]/(default)/cart/_components/cart-item.tsx index 1809ef41a..0048fd035 100644 --- a/core/app/[locale]/(default)/cart/_components/cart-item.tsx +++ b/core/app/[locale]/(default)/cart/_components/cart-item.tsx @@ -1,5 +1,4 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getFormatter, getLocale, getMessages } from 'next-intl/server'; +import { useFormatter } from 'next-intl'; import { FragmentOf, graphql } from '~/client/graphql'; import { BcImage } from '~/components/bc-image'; @@ -148,10 +147,8 @@ interface Props { currencyCode: string; } -export const CartItem = async ({ currencyCode, product }: Props) => { - const locale = await getLocale(); - const messages = await getMessages({ locale }); - const format = await getFormatter({ locale }); +export const CartItem = ({ currencyCode, product }: Props) => { + const format = useFormatter(); return (
  • @@ -231,9 +228,7 @@ export const CartItem = async ({ currencyCode, product }: Props) => { )}
    - - - +
  • @@ -256,16 +251,12 @@ export const CartItem = async ({ currencyCode, product }: Props) => {

    - - - +
    - - - +
    diff --git a/core/app/[locale]/(default)/cart/_components/checkout-summary.tsx b/core/app/[locale]/(default)/cart/_components/checkout-summary.tsx index c3d85234e..743a0f512 100644 --- a/core/app/[locale]/(default)/cart/_components/checkout-summary.tsx +++ b/core/app/[locale]/(default)/cart/_components/checkout-summary.tsx @@ -1,5 +1,4 @@ -import { NextIntlClientProvider } from 'next-intl'; -import { getFormatter, getLocale, getMessages, getTranslations } from 'next-intl/server'; +import { getFormatter, getTranslations } from 'next-intl/server'; import { FragmentOf, graphql } from '~/client/graphql'; @@ -47,10 +46,8 @@ interface Props { } export const CheckoutSummary = async ({ checkout, geography }: Props) => { - const locale = await getLocale(); - const t = await getTranslations({ locale, namespace: 'Cart.CheckoutSummary' }); - const format = await getFormatter({ locale }); - const messages = await getMessages({ locale }); + const t = await getTranslations('Cart.CheckoutSummary'); + const format = await getFormatter(); const { cart, grandTotal, subtotal, taxTotal } = checkout; @@ -68,9 +65,7 @@ export const CheckoutSummary = async ({ checkout, geography }: Props) => {
    - - - + {cart?.discountedAmount && (
    @@ -85,9 +80,7 @@ export const CheckoutSummary = async ({ checkout, geography }: Props) => {
    )} - - - + {taxTotal && (
    diff --git a/core/app/[locale]/(default)/cart/_components/empty-cart.tsx b/core/app/[locale]/(default)/cart/_components/empty-cart.tsx index c7bd3d92e..7339d2a84 100644 --- a/core/app/[locale]/(default)/cart/_components/empty-cart.tsx +++ b/core/app/[locale]/(default)/cart/_components/empty-cart.tsx @@ -1,11 +1,7 @@ -import { getTranslations } from 'next-intl/server'; +import { useTranslations } from 'next-intl'; -interface Props { - locale: string; -} - -export const EmptyCart = async ({ locale }: Props) => { - const t = await getTranslations({ locale, namespace: 'Cart' }); +export const EmptyCart = () => { + const t = useTranslations('Cart'); return (
    diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index 35f5f57e4..07728d33d 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -1,12 +1,10 @@ import { cookies } from 'next/headers'; -import { NextIntlClientProvider } from 'next-intl'; -import { getMessages, getTranslations } from 'next-intl/server'; +import { getTranslations } from 'next-intl/server'; import { getSessionCustomerId } from '~/auth'; import { client } from '~/client'; import { graphql } from '~/client/graphql'; import { TAGS } from '~/client/tags'; -import { LocaleType } from '~/i18n'; import { CartItem, CartItemFragment } from './_components/cart-item'; import { CartViewed } from './_components/cart-viewed'; @@ -42,21 +40,14 @@ export const metadata = { title: 'Cart', }; -interface Props { - params: { - locale: LocaleType; - }; -} - -export default async function Cart({ params: { locale } }: Props) { +export default async function Cart() { const cartId = cookies().get('cartId')?.value; if (!cartId) { - return ; + return ; } - const messages = await getMessages({ locale }); - const t = await getTranslations({ locale, namespace: 'Cart' }); + const t = await getTranslations('Cart'); const customerId = await getSessionCustomerId(); @@ -77,7 +68,7 @@ export default async function Cart({ params: { locale } }: Props) { const geography = data.geography; if (!cart) { - return ; + return ; } const lineItems = [...cart.lineItems.physicalItems, ...cart.lineItems.digitalItems]; @@ -95,9 +86,7 @@ export default async function Cart({ params: { locale } }: Props) {
    {checkout && } - - - +
    diff --git a/core/app/[locale]/(default)/compare/_components/add-to-cart/index.tsx b/core/app/[locale]/(default)/compare/_components/add-to-cart/index.tsx index 498f6482c..743ed9dff 100644 --- a/core/app/[locale]/(default)/compare/_components/add-to-cart/index.tsx +++ b/core/app/[locale]/(default)/compare/_components/add-to-cart/index.tsx @@ -20,7 +20,7 @@ const Submit = ({ data: product }: { data: FragmentOf }; export const AddToCart = ({ data: product }: { data: FragmentOf }) => { - const t = useTranslations('AddToCart'); + const t = useTranslations('Compare.AddToCart'); return (
    , }); @@ -40,7 +40,7 @@ export const AddToCart = ({ data: product }: { data: FragmentOf (
    - {t.rich('addedProductQuantity', { + {t.rich('success', { cartItems: quantity, cartLink: (chunks) => ( ; } -export default async function Compare({ params: { locale }, searchParams }: Props) { +export default async function Compare({ searchParams }: Props) { + const t = await getTranslations('Compare'); + const format = await getFormatter(); + const customerId = await getSessionCustomerId(); - const t = await getTranslations({ locale, namespace: 'Compare' }); - const messages = await getMessages({ locale }); const parsed = CompareParamsSchema.parse(searchParams); const productIds = parsed.ids?.filter((id) => !Number.isNaN(id)); - const format = await getFormatter(); - const { data } = await client.fetch({ document: ComparePageQuery, variables: { @@ -123,11 +117,9 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return (
    -

    {t('nothingCompare')}

    +

    {t('nothingToCompare')}

    {t('helpingText')}

    - - - +
    ); @@ -136,12 +128,12 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return ( <>

    - {t('comparingQuantity', { quantity: products.length })} + {t('heading', { quantity: products.length })}

    - + @@ -176,7 +168,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop @@ -222,7 +214,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop <> {product.prices.retailPrice?.value !== undefined && ( <> - MSRP:{' '} + {t('Table.Prices.msrp')}:{' '} {format.number(product.prices.retailPrice.value, { style: 'currency', @@ -235,7 +227,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop {product.prices.salePrice?.value !== undefined && product.prices.basePrice?.value !== undefined ? ( <> - Was:{' '} + {t('Table.Prices.was')}:{' '} {format.number(product.prices.basePrice.value, { style: 'currency', @@ -244,7 +236,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop
    <> - Now:{' '} + {t('Table.Prices.now')}:{' '} {format.number(product.prices.price.value, { style: 'currency', currency: product.prices.price.currencyCode, @@ -275,7 +267,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return (
    ); @@ -283,12 +275,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return ( ); })} @@ -297,7 +284,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop @@ -312,7 +299,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop @@ -342,7 +329,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop @@ -362,7 +349,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return ( ); @@ -370,12 +357,7 @@ export default async function Compare({ params: { locale }, searchParams }: Prop return ( ); })} diff --git a/core/app/[locale]/(default)/login/_components/change-password-form.tsx b/core/app/[locale]/(default)/login/_components/change-password-form.tsx index bb95d4db5..c4f6e7b75 100644 --- a/core/app/[locale]/(default)/login/_components/change-password-form.tsx +++ b/core/app/[locale]/(default)/login/_components/change-password-form.tsx @@ -15,7 +15,7 @@ import { Input, } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; -import { useRouter } from '~/navigation'; +import { useRouter } from '~/routing'; import { useAccountStatusContext } from '../../account/(tabs)/_components/account-status-provider'; import { submitChangePasswordForm } from '../_actions/submit-change-password-form'; diff --git a/core/app/[locale]/(default)/login/_components/login-form.tsx b/core/app/[locale]/(default)/login/_components/login-form.tsx index cf54a73d3..e36820b50 100644 --- a/core/app/[locale]/(default)/login/_components/login-form.tsx +++ b/core/app/[locale]/(default)/login/_components/login-form.tsx @@ -22,7 +22,7 @@ import { submitLoginForm } from '../_actions/submit-login-form'; const SubmitButton = () => { const { pending } = useFormStatus(); - const t = useTranslations('Account.Login'); + const t = useTranslations('Login'); return ( } /> ) : ( - + ) diff --git a/core/components/link/index.tsx b/core/components/link/index.tsx index 166219be5..d3e69f629 100644 --- a/core/components/link/index.tsx +++ b/core/components/link/index.tsx @@ -4,7 +4,7 @@ import { ComponentPropsWithRef, ElementRef, forwardRef, useReducer } from 'react import { cn } from '~/lib/utils'; -import { Link as NavLink, useRouter } from '../../navigation'; +import { Link as NavLink, useRouter } from '../../routing'; type NextLinkProps = Omit, 'prefetch'>; diff --git a/core/components/product-card/add-to-cart/form/index.tsx b/core/components/product-card/add-to-cart/form/index.tsx index dbf85df1b..aa6fc38ba 100644 --- a/core/components/product-card/add-to-cart/form/index.tsx +++ b/core/components/product-card/add-to-cart/form/index.tsx @@ -24,7 +24,7 @@ const SubmitButton = ({ data: product }: Props) => { }; export const Form = ({ data: product }: Props) => { - const t = useTranslations('AddToCart'); + const t = useTranslations('Components.ProductCard.AddToCart'); return ( { const quantity = Number(formData.get('quantity')); if (result.error) { - toast.error(t('errorAddingProductToCart'), { + toast.error(t('error'), { icon: , }); @@ -44,7 +44,7 @@ export const Form = ({ data: product }: Props) => { () => (
    - {t.rich('addedProductQuantity', { + {t.rich('success', { cartItems: quantity, cartLink: (chunks) => ( ; } -export const AddToCart = async ({ data: product }: Props) => { - const t = await getTranslations('AddToCart'); +export const AddToCart = ({ data: product }: Props) => { + const t = useTranslations('Components.ProductCard.AddToCart'); const productOptions = removeEdgesAndNodes(product.productOptions); diff --git a/core/components/product-card/index.tsx b/core/components/product-card/index.tsx index 197ea801f..953a4289c 100644 --- a/core/components/product-card/index.tsx +++ b/core/components/product-card/index.tsx @@ -1,4 +1,4 @@ -import { getFormatter } from 'next-intl/server'; +import { useFormatter } from 'next-intl'; import { ResultOf } from '~/client/graphql'; import { ProductCard as ComponentProductCard } from '~/components/ui/product-card'; @@ -15,14 +15,14 @@ interface Props { showCart?: boolean; } -export const ProductCard = async ({ +export const ProductCard = ({ product, imageSize = 'square', imagePriority = false, showCart = true, showCompare = true, }: Props) => { - const format = await getFormatter(); + const format = useFormatter(); const { name, entityId, defaultImage, brand, path, prices } = product; diff --git a/core/components/search-form/index.tsx b/core/components/search-form/index.tsx index 23d303c76..140c0c03a 100644 --- a/core/components/search-form/index.tsx +++ b/core/components/search-form/index.tsx @@ -1,7 +1,6 @@ 'use client'; import { useTranslations } from 'next-intl'; -import { useFormStatus } from 'react-dom'; import { Button } from '~/components/ui/button'; import { Field, FieldControl, Form, FormSubmit, Input } from '~/components/ui/form'; @@ -11,8 +10,7 @@ interface Props { } export const SearchForm = ({ initialTerm = '' }: Props) => { - const { pending } = useFormStatus(); - const t = useTranslations('NotFound'); + const t = useTranslations('Components.SearchForm'); return (
    @@ -31,7 +29,7 @@ export const SearchForm = ({ initialTerm = '' }: Props) => { - diff --git a/core/components/ui/compare-drawer/compare-drawer.tsx b/core/components/ui/compare-drawer/compare-drawer.tsx index 17c783800..7b4d982b5 100644 --- a/core/components/ui/compare-drawer/compare-drawer.tsx +++ b/core/components/ui/compare-drawer/compare-drawer.tsx @@ -4,14 +4,14 @@ import { useTranslations } from 'next-intl'; import { BcImage } from '~/components/bc-image'; import { Link as CustomLink } from '~/components/link'; -import { usePathname } from '~/navigation'; +import { usePathname } from '~/routing'; import { Button } from '../button'; import { type Product, useCompareDrawerContext } from './context'; const CompareLink = ({ products }: { products: Product[] }) => { - const t = useTranslations('Providers.Compare'); + const t = useTranslations('Components.Compare'); return ( ); } ``` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddfeb7b71..6b1088def 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,8 +120,8 @@ importers: specifier: 5.0.0-beta.20 version: 5.0.0-beta.20(next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nodemailer@6.9.14)(react@18.3.1) next-intl: - specifier: ^3.17.6 - version: 3.17.6(next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + specifier: ^3.18.1 + version: 3.18.1(next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -249,7 +249,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.9.0 - version: 2.9.0(eslint@8.57.0)(jest@29.7.0(@types/node@20.16.1))(typescript@5.5.4) + version: 2.9.0(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -322,7 +322,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.9.0 - version: 2.9.0(eslint@8.57.0)(jest@29.7.0(@types/node@20.16.1))(typescript@5.5.4) + version: 2.9.0(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -4248,8 +4248,8 @@ packages: nodemailer: optional: true - next-intl@3.17.6: - resolution: {integrity: sha512-giPh2Us/C7B5P/60qdfHZMj9YPg5yXp6c9msFxv6Ua4zJt1IueNrKivInowN8FAwwSqEyC7TNYXBkXuG6oToTQ==} + next-intl@3.18.1: + resolution: {integrity: sha512-ht8HyroJeiJIte9yhg1f0Nc2rlZmkvSYQ3nhqFVJLzhq7T1Xb8nfjilffrOJc3sA8kEjBOS4bdIrg4YX8REO0Q==} peerDependencies: next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5411,8 +5411,8 @@ packages: '@types/react': optional: true - use-intl@3.17.6: - resolution: {integrity: sha512-07wyVHSFSfI6M6TjhX/buZUFXnFymSz5LCimIMutTnBY11Vc/ym18j3HpZoQoWH+JYRKCCa4Jfm7NNyVKmgVww==} + use-intl@3.18.1: + resolution: {integrity: sha512-BFNhVnszG1AB04DbNvJ+TLLd1oBDGergAKI8t9xaE4vDJYZaVKQH4zmpdArbegzTu5U9XMen6w14d1P1hBwKOQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5814,35 +5814,6 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@bigcommerce/eslint-config@2.9.0(eslint@8.57.0)(jest@29.7.0(@types/node@20.16.1))(typescript@5.5.4)': - dependencies: - '@bigcommerce/eslint-plugin': 1.3.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - '@rushstack/eslint-patch': 1.10.3 - '@stylistic/eslint-plugin': 2.1.0(eslint@8.57.0)(typescript@5.5.4) - '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.5.4) - eslint: 8.57.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-jest: 28.6.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4) - eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.0) - eslint-plugin-jsdoc: 48.2.9(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) - eslint-plugin-react: 7.34.2(eslint@8.57.0) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) - eslint-plugin-switch-case: 1.1.2 - prettier: 2.8.8 - optionalDependencies: - typescript: 5.5.4 - transitivePeerDependencies: - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - jest - - supports-color - '@bigcommerce/eslint-config@2.9.0(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4)': dependencies: '@bigcommerce/eslint-plugin': 1.3.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) @@ -8614,23 +8585,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 4.3.6 - enhanced-resolve: 5.17.1 - eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.5 - is-core-module: 2.15.0 - is-glob: 4.0.3 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.6 @@ -8665,17 +8619,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.5.4) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) - transitivePeerDependencies: - - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 @@ -8708,33 +8651,6 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - hasown: 2.0.2 - is-core-module: 2.15.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.5.4) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.8 @@ -10265,13 +10181,13 @@ snapshots: optionalDependencies: nodemailer: 6.9.14 - next-intl@3.17.6(next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-intl@3.18.1(next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@formatjs/intl-localematcher': 0.5.4 negotiator: 0.6.3 next: 14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - use-intl: 3.17.6(react@18.3.1) + use-intl: 3.18.1(react@18.3.1) next@14.2.6(@playwright/test@1.46.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -11424,7 +11340,7 @@ snapshots: optionalDependencies: '@types/react': 18.3.4 - use-intl@3.17.6(react@18.3.1): + use-intl@3.18.1(react@18.3.1): dependencies: '@formatjs/fast-memoize': 2.2.0 intl-messageformat: 10.5.14
    {t('productComparison')}{t('Table.caption')}
    -

    {t('noImageText')}

    +

    {t('Table.noImage')}

    - - - +
    - {t('description')} + {t('Table.description')}
    - {t('rating')} + {t('Table.rating')}
    - {t('availability')} + {t('Table.availability')}
    - - - +