Close the menu cleanly when changing locale

Dismiss the user menu on language pick, and update the
URL together with an optimistic identity write so the
mismatch callout does not flash mid-switch.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-07-21 16:34:19 +02:00
parent 53b14b3984
commit 03252b4883
3 changed files with 20 additions and 4 deletions

View File

@@ -58,7 +58,6 @@ const topBarUserMenuFragment = graphql`
fragment TopBarUserMenu_identity on Identity {
fullName
email
locale
}
`;
@@ -136,7 +135,12 @@ export function TopBarUserMenu({ identityKey }: TopBarUserMenuProps) {
}}
>
{URL_LOCALES.map(code => (
<DropdownRadioItem key={code} value={code} disabled={isChangingLocale}>
<DropdownRadioItem
key={code}
value={code}
closeOnClick
disabled={isChangingLocale}
>
{URL_LOCALE_LABELS[code]}
</DropdownRadioItem>
))}

View File

@@ -44,11 +44,18 @@ export function useChangeLocale() {
locale: UrlLocale,
options: ChangeLocaleOptions = {},
) => {
// Persist and navigate without sequencing them: awaiting the mutation
// before navigation left a frame where Identity.locale already matched
// the new choice but the URL still had the old prefix, flashing the
// mismatch callout. updateLocale writes the store optimistically, and
// flushSync applies the URL change in the same paint.
if (options.persist) {
await updateLocale(locale);
void updateLocale(locale);
}
if (locale !== currentLocale) {
void navigate(replaceLocaleInPathname(pathname, locale) + search);
void navigate(replaceLocaleInPathname(pathname, locale) + search, {
flushSync: true,
});
}
}, [currentLocale, navigate, pathname, search, updateLocale]);

View File

@@ -53,6 +53,11 @@ export function useUpdateLocale() {
await commit(
{
variables: { input: { locale } },
// Keep the Relay store in sync with the URL during locale switches so
// the mismatch callout never paints a one-frame desync.
optimisticUpdater: (store) => {
store.getRoot().getLinkedRecord("viewer")?.setValue(locale, "locale");
},
},
feedback,
);