Skip to content

Commit

Permalink
add noPrefix config option
Browse files Browse the repository at this point in the history
  • Loading branch information
dcporter44 committed Mar 23, 2024
1 parent 72a46bf commit 8a5f01c
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 5.4.0

- Add config option `noPrefix` for hiding the locale prefix in the pathname.
- `useCurrentLocale` now checks the document cookie for the current locale prior to checking the pathname.

## 5.3.0

- Change default of `serverSetCookie` to `"always"`.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ You now have internationalized routing!
| `prefixDefault` | `false` | boolean | |
| `localeDetector` | (See below) | function \| false | |
| `localeCookie` | `'NEXT_LOCALE'` | string | |
| `noPrefix` | `false` | boolean | |
| `serverSetCookie` | `'always'` | "always" \| "if-empty" \| "never" | |
| `basePath` | `''` | string | |

Expand All @@ -76,7 +77,9 @@ By default, the `defaultLocale`'s path is not prefixed with the locale. For exam

**German**: `/de/products`

To include your default language in the path, set the `prefixDefault` config option to `true`.
To also include your default locale in the path, set the `prefixDefault` config option to `true`.

To hide all locales from the path, set the `noPrefix` config option to `true`.

## Locale Detection

Expand Down Expand Up @@ -119,6 +122,8 @@ The `serverSetCookie` option automatically changes a visitor's preferred locale

`'never'`: The middleware will not automatically set the cookie.

If you are using `noPrefix`, the `serverSetCookie` option does not do anything since there is no locale in the pathname to read from. All language changing must be done by setting the cookie manually.

## Using `basePath` (optional)

This is only needed if you are using the `basePath` option in `next.config.js`. You will need to also include it as the `basePath` option in your `i18nConfig`.
Expand Down
23 changes: 23 additions & 0 deletions __tests__/i18nRouter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,5 +341,28 @@ basePaths.forEach(basePath => {

expect(mockRedirect).toHaveBeenCalledTimes(0);
});

it('should not redirect when noPrefix is true', () => {
const mockRedirect = jest.fn().mockReturnValue(new NextResponse());
NextResponse.redirect = mockRedirect;

const mockRewrite = jest.fn().mockReturnValue(new NextResponse());
NextResponse.rewrite = mockRewrite;

const request = mockRequest('/faq', ['en'], 'jp');

i18nRouter(request, {
locales: ['en', 'de', 'jp'],
defaultLocale: 'en',
basePath,
noPrefix: true
});

expect(mockRedirect).toHaveBeenCalledTimes(0);
expect(mockRewrite).toHaveBeenCalledTimes(1);
expect(mockRewrite.mock.calls[0][0]).toEqual(
new URL(`${basePath}/jp/faq`, 'https://example.com/faq')
);
});
});
});
28 changes: 28 additions & 0 deletions __tests__/useCurrentLocale.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,33 @@ basePaths.forEach(basePath => {

expect(useCurrentLocale(config)).toEqual(undefined);
});

it('should return cookie locale when noPrefix is true and cookie set', () => {
pathname = `/products/2`;

const config = {
defaultLocale: 'en',
locales: ['en', 'de'],
noPrefix: true,
basePath
};

expect(
useCurrentLocale(config, 'random_cookie=sdf; NEXT_LOCALE=de')
).toEqual('de');
});

it('should return defaultLocale when noPrefix is true and no cookie set', () => {
pathname = `/products/2`;

const config = {
defaultLocale: 'en',
locales: ['en', 'de'],
noPrefix: true,
basePath
};

expect(useCurrentLocale(config, 'random_cookie=sdf')).toEqual('en');
});
});
});
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-i18n-router",
"version": "5.3.1",
"version": "5.4.0",
"description": "Next.js App Router internationalized routing and locale detection.",
"repository": "https://github.com/i18nexus/next-i18n-router",
"keywords": [
Expand Down
37 changes: 36 additions & 1 deletion src/client/useCurrentLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,44 @@
import { Config } from '../types';
import { usePathname } from 'next/navigation';

const useCurrentLocale = (i18nConfig: Config): string | undefined => {
const getCookie = (name: string, documentCookie: string) => {
let cookies = documentCookie;
let cookieArray = cookies.split('; ');

for (let i = 0; i < cookieArray.length; i++) {
let cookiePair = cookieArray[i].split('=');
if (cookiePair[0] === name) {
return cookiePair[1];
}
}
return null;
};

const useCurrentLocale = (
i18nConfig: Config,
documentCookie?: string
): string | undefined => {
const { basePath = '', locales } = i18nConfig;

if (!documentCookie && typeof window !== 'undefined') {
documentCookie = document.cookie;
}

if (documentCookie) {
const cookieLocale = getCookie(
i18nConfig.localeCookie || 'NEXT_LOCALE',
documentCookie
);

if (cookieLocale && locales.includes(cookieLocale)) {
return cookieLocale;
}
}

if (i18nConfig.noPrefix) {
return i18nConfig.defaultLocale;
}

const currentPathname = usePathname();

const locale = locales.find(locale => {
Expand Down
32 changes: 27 additions & 5 deletions src/i18nRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ function i18nRouter(request: NextRequest, config: Config): NextResponse {
localeDetector = defaultLocaleDetector,
prefixDefault = false,
basePath = '',
serverSetCookie = 'always'
serverSetCookie = 'always',
noPrefix = false
} = config;

validateConfig(config);
Expand All @@ -35,10 +36,6 @@ function i18nRouter(request: NextRequest, config: Config): NextResponse {

let response = NextResponse.next(responseOptions);

const pathLocale = locales.find(
locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);

let cookieLocale;
// check cookie for locale
if (localeCookie) {
Expand All @@ -49,6 +46,31 @@ function i18nRouter(request: NextRequest, config: Config): NextResponse {
}
}

if (noPrefix) {
let locale = cookieLocale || defaultLocale;

let newPath = `${locale}${pathname}`;

newPath = `${basePath}${basePathTrailingSlash ? '' : '/'}${newPath}`;

if (request.nextUrl.search) {
newPath += request.nextUrl.search;
}

response = NextResponse.rewrite(
new URL(newPath, request.url),
responseOptions
);

response.headers.set('x-next-i18n-router-locale', locale);

return response;
}

const pathLocale = locales.find(
locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);

if (!pathLocale) {
let locale = cookieLocale;

Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Config {
localeCookie?: string;
localeDetector?: ((request: NextRequest, config: Config) => string) | false;
prefixDefault?: boolean;
noPrefix?: boolean;
basePath?: string;
serverSetCookie?: 'if-empty' | 'always' | 'never';
}

0 comments on commit 8a5f01c

Please sign in to comment.