Core & UI: Use cookie to store active locale on always mode

This commit is contained in:
fuma-nama
2024-08-17 21:19:52 +08:00
parent 2f15256a05
commit c542561f37
5 changed files with 56 additions and 22 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'fumadocs-core': minor
'fumadocs-ui': minor
---
Use cookie to store active locale on `always` mode
@@ -158,13 +158,13 @@ You can also customise the i18n middleware from `i18n.ts`.
### Hide Locale Prefix
To hide the locale prefix, for example, use `/` instead of `/en` where `en` is the default locale, use the `hideLocale` option.
To hide the locale prefix, for example, use `/` instead of `/en`, use the `hideLocale` option.
| Mode | Description |
| ---------------- | ------------------------------- |
| `always` | Always hide the prefix |
| `default-locale` | Only hide the default locale |
| `never` | Never hide the prefix (default) |
| Mode | Description |
| ---------------- | -------------------------------------------------- |
| `always` | Always hide the prefix, detect locale from cookies |
| `default-locale` | Only hide the default locale |
| `never` | Never hide the prefix (default) |
> It uses `NextResponse.rewrite` under the hood.
@@ -178,6 +178,13 @@ export const i18n: I18nConfig = {
};
```
#### `always`
It's highly **unrecommended** to use `always`.
On this mode, locale is stored as a cookie, read and set on the middleware.
This may cause undesired cache problems on your hosting platform, and need to pay extra attention on SEO to ensure search engines can index your pages correctly.
<UIOnly>
### Adding Translations
+1
View File
@@ -41,6 +41,7 @@ export default function Layout({
searchNoResult: '沒有結果',
previousPage: '上一頁',
nextPage: '下一頁',
chooseLanguage: '選擇語言',
},
}[lang]
}
+35 -16
View File
@@ -11,6 +11,8 @@ interface MiddlewareOptions extends I18nConfig {
format?: (locale: string, path: string) => string;
}
const COOKIE = 'FD_LOCALE';
function getLocale(
request: NextRequest,
locales: string[],
@@ -41,10 +43,21 @@ export function createI18nMiddleware({
format = defaultFormat,
hideLocale = 'never',
}: MiddlewareOptions): NextMiddleware {
function shouldHideLocale(locale: string): boolean {
return (
hideLocale === 'always' ||
(hideLocale === 'default-locale' && locale === defaultLanguage)
function getUrl(
request: NextRequest,
pathname: string,
locale?: string,
): URL {
if (!locale) {
return new URL(
pathname.startsWith('/') ? pathname : `/${pathname}`,
request.url,
);
}
return new URL(
format(locale, pathname.startsWith('/') ? pathname.slice(1) : pathname),
request.url,
);
}
@@ -57,17 +70,25 @@ export function createI18nMiddleware({
);
if (!pathLocale) {
const locale = getLocale(request, languages, defaultLanguage);
let path = pathname;
while (path.startsWith('/')) {
path = path.slice(1);
if (hideLocale === 'default-locale') {
return NextResponse.rewrite(getUrl(request, pathname, defaultLanguage));
}
const url = new URL(format(locale, path), request.url);
return shouldHideLocale(locale)
? NextResponse.rewrite(url)
: NextResponse.redirect(url);
if (hideLocale === 'always') {
const locale = request.cookies.get(COOKIE)?.value ?? defaultLanguage;
return NextResponse.rewrite(getUrl(request, pathname, locale));
}
const locale = getLocale(request, languages, defaultLanguage);
return NextResponse.redirect(getUrl(request, pathname, locale));
}
if (hideLocale === 'always') {
const path = pathname.slice(`/${pathLocale}`.length);
const res = NextResponse.redirect(getUrl(request, path));
res.cookies.set(COOKIE, pathLocale);
return res;
}
// Remove explicit default locale
@@ -75,9 +96,7 @@ export function createI18nMiddleware({
if (hideLocale === 'default-locale' && pathLocale === defaultLanguage) {
const path = pathname.slice(`/${pathLocale}`.length);
return NextResponse.redirect(
new URL(path.startsWith('/') ? path : `/${path}`, request.url),
);
return NextResponse.redirect(getUrl(request, path));
}
return NextResponse.next();
+1
View File
@@ -54,6 +54,7 @@ export function I18nProvider({
}
router.push(`/${segments.join('/')}`);
router.refresh();
},
[locale, segments, router],
);