Skip to content

Commit eb2d4e1

Browse files
committed
fix: locale switcher correctly works w/ localized Makeswift paths
1 parent 1821b03 commit eb2d4e1

3 files changed

Lines changed: 85 additions & 9 deletions

File tree

.changeset/twenty-ants-sip.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-makeswift": patch
3+
---
4+
5+
Fix locale switcher on localized Makeswift pages with different paths
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use server';
2+
3+
import { getSiteVersion } from '@makeswift/runtime/next/server';
4+
5+
import { defaultLocale } from '~/i18n/locales';
6+
import { client as makeswiftClient } from '~/lib/makeswift/client';
7+
8+
const getPageInfo = async ({
9+
pathname,
10+
locale,
11+
}: {
12+
pathname: string;
13+
locale: string | undefined;
14+
}) =>
15+
makeswiftClient
16+
.getPages({
17+
locale: locale === defaultLocale ? undefined : locale,
18+
pathPrefix: pathname,
19+
siteVersion: await getSiteVersion(),
20+
})
21+
.filter((page) => page.path === pathname)
22+
.toArray()
23+
.then((pages) => (pages.length === 0 ? null : pages[0]));
24+
25+
const getPathname = (variants: Array<{ locale: string; path: string }>, locale: string) =>
26+
variants.find((v) => v.locale === locale)?.path;
27+
28+
export async function getLocalizedPathname({
29+
pathname,
30+
activeLocale,
31+
targetLocale,
32+
}: {
33+
pathname: string;
34+
activeLocale: string | undefined;
35+
targetLocale: string;
36+
}) {
37+
// fallback to page info for default locale if there is no page info for active locale
38+
const fallbackPageInfo =
39+
activeLocale === defaultLocale
40+
? Promise.resolve(null)
41+
: getPageInfo({ pathname, locale: undefined });
42+
43+
const localizedPageInfo = await getPageInfo({ pathname, locale: activeLocale });
44+
const pageInfo = localizedPageInfo ?? (await fallbackPageInfo);
45+
46+
if (pageInfo == null) {
47+
return pathname;
48+
}
49+
50+
return (
51+
getPathname(pageInfo.localizedVariants, targetLocale) ??
52+
getPathname(pageInfo.localizedVariants, defaultLocale) ??
53+
pathname
54+
);
55+
}

core/vibes/soul/primitives/navigation/index.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { Link } from '~/components/link';
3030
import { usePathname, useRouter } from '~/i18n/routing';
3131
import { useSearch } from '~/lib/search';
3232

33+
import { getLocalizedPathname } from './_actions/localized-pathname';
34+
3335
interface Link {
3436
label: string;
3537
href: string;
@@ -862,22 +864,36 @@ function SearchResults({
862864
);
863865
}
864866

865-
const useSwitchLocale = () => {
867+
const useSwitchLocale = ({ activeLocale }: { activeLocale: Locale | undefined }) => {
866868
const pathname = usePathname();
867869
const router = useRouter();
868870
const params = useParams();
869871
const searchParams = useSearchParams();
870872

871873
return useCallback(
872-
(locale: string) =>
874+
async (locale: string) => {
875+
const localizedPathname = await getLocalizedPathname({
876+
pathname,
877+
activeLocale: activeLocale?.id,
878+
targetLocale: locale,
879+
});
880+
881+
// the Next.js App Router guarantees a `startTransition` call on `router.push`,
882+
// so we don’t need to wrap it in an explicit nested call as set out in
883+
// https://react.dev/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition
873884
router.push(
874-
// @ts-expect-error -- TypeScript will validate that only known `params`
875-
// are used in combination with a given `pathname`. Since the two will
876-
// always match for the current route, we can skip runtime checks.
877-
{ pathname, params, query: Object.fromEntries(searchParams.entries()) },
885+
{
886+
pathname: localizedPathname,
887+
// @ts-expect-error -- TypeScript will validate that only known `params`
888+
// are used in combination with a given `pathname`. Since the two will
889+
// always match for the current route, we can skip runtime checks.
890+
params,
891+
query: Object.fromEntries(searchParams.entries()),
892+
},
878893
{ locale },
879-
),
880-
[pathname, params, router, searchParams],
894+
);
895+
},
896+
[pathname, activeLocale?.id, params, router, searchParams],
881897
);
882898
};
883899

@@ -892,7 +908,7 @@ function LocaleSwitcher({
892908
}) {
893909
const activeLocale = locales.find((locale) => locale.id === activeLocaleId);
894910
const [isPending, startTransition] = useTransition();
895-
const switchLocale = useSwitchLocale();
911+
const switchLocale = useSwitchLocale({ activeLocale });
896912

897913
return (
898914
<div className={className}>

0 commit comments

Comments
 (0)