next-language-selector 0.1.8 β 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -3
- package/dist/index.cjs +7 -4
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +7 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,108 @@
|
|
|
1
1
|
# next-language-selector
|
|
2
2
|
|
|
3
3
|
A lightweight, configurable language selector for Next.js (App Router & Pages Router).
|
|
4
|
-
Efficiently manages the `NEXT_LOCALE` cookie and works seamlessly with any i18n solution.
|
|
4
|
+
Efficiently manages the `NEXT_LOCALE` cookie and works seamlessly with `next-intl` or any other i18n solution.
|
|
5
5
|
|
|
6
6
|
## Key Features
|
|
7
|
+
|
|
7
8
|
- π **Next.js Native**: Built specifically for the Next.js ecosystem.
|
|
8
9
|
- πͺΆ **Zero Dependencies**: Keeps your bundle size minimal.
|
|
9
|
-
- π¨ **Fully Customizable**: Use built-in styles or your own UI (Shadcn, Radix, etc.).
|
|
10
|
+
- π¨ **Fully Customizable**: Use built-in styles or your own UI (Shadcn UI, Radix, etc.) via render props.
|
|
11
|
+
- πͺ **Cookie-based**: Automatically syncs with the `NEXT_LOCALE` cookie.
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
16
|
pnpm add next-language-selector
|
|
15
17
|
# or
|
|
16
|
-
npm install next-language-selector
|
|
18
|
+
npm install next-language-selector
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Basic Usage
|
|
22
|
+
|
|
23
|
+
Just drop the component into your Footer or Navbar. It handles cookie updates and local state out of the box.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { LanguageSelector } from "next-language-selector";
|
|
27
|
+
|
|
28
|
+
const locales = [
|
|
29
|
+
{ name: "English", code: "en", flag: "πΊπΈ" },
|
|
30
|
+
{ name: "Deutsch", code: "de", flag: "π©πͺ" },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export default function Footer() {
|
|
34
|
+
return (
|
|
35
|
+
<footer>
|
|
36
|
+
<LanguageSelector
|
|
37
|
+
locales={locales}
|
|
38
|
+
defaultLocale="en"
|
|
39
|
+
activeColor="#3b82f6" // optional
|
|
40
|
+
isDropdown={false} // Renders as a list of buttons
|
|
41
|
+
/>
|
|
42
|
+
</footer>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Custom UI (e.g., Shadcn UI / Headless)
|
|
48
|
+
|
|
49
|
+
Use the `renderCustom` prop to take full control over the rendering while keeping the cookie management logic.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<LanguageSelector
|
|
53
|
+
locales={locales}
|
|
54
|
+
defaultLocale="en"
|
|
55
|
+
renderCustom={({ locales, currentLocale, onChange }) => (
|
|
56
|
+
<div className="flex gap-4">
|
|
57
|
+
{locales.map((lang) => (
|
|
58
|
+
<button
|
|
59
|
+
key={lang.code}
|
|
60
|
+
onClick={() => onChange(lang.code)}
|
|
61
|
+
className={
|
|
62
|
+
currentLocale === lang.code
|
|
63
|
+
? "text-blue-600 font-bold"
|
|
64
|
+
: "text-gray-500"
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
{lang.flag} {lang.name}
|
|
68
|
+
</button>
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
/>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Setup with next-intl (Middleware)
|
|
76
|
+
|
|
77
|
+
To make sure Next.js detects the language from the cookie set by this component, update your `middleware.ts` or `proxy.ts`:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import createMiddleware from "next-intl/middleware";
|
|
81
|
+
import { routing } from "./i18n/routing";
|
|
82
|
+
|
|
83
|
+
export default createMiddleware({
|
|
84
|
+
...routing,
|
|
85
|
+
localeCookie: {
|
|
86
|
+
name: "NEXT_LOCALE",
|
|
87
|
+
path: "/",
|
|
88
|
+
maxAge: 31536000, // 1 year
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Props
|
|
94
|
+
|
|
95
|
+
| Prop | Type | Default | Description |
|
|
96
|
+
| :-------------- | :--------------- | :------------ | :---------------------------------------------------------- |
|
|
97
|
+
| `locales` | `LocaleConfig[]` | **Required** | Array of `{ name, code, flag }` objects |
|
|
98
|
+
| `defaultLocale` | `string` | **Required** | Initial language code |
|
|
99
|
+
| `isDropdown` | `boolean` | `false` | Toggle between `<select>` and a list of buttons |
|
|
100
|
+
| `autoReload` | `boolean` | `true` | Trigger reload on cookie change |
|
|
101
|
+
| `cookieName` | `string` | `NEXT_LOCALE` | Name of the cookie to store the selected language |
|
|
102
|
+
| `activeColor` | `string` | `red` | Underline color for the active language (non-dropdown mode) |
|
|
103
|
+
| `className` | `string` | - | CSS class for the wrapper element |
|
|
104
|
+
| `renderCustom` | `Function` | - | Render prop for custom UI logic |
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -29,10 +29,12 @@ module.exports = __toCommonJS(index_exports);
|
|
|
29
29
|
var import_react = require("react");
|
|
30
30
|
|
|
31
31
|
// src/utils.ts
|
|
32
|
-
var setLocaleCookie = (locale, cookieName = "NEXT_LOCALE") => {
|
|
32
|
+
var setLocaleCookie = (locale, cookieName = "NEXT_LOCALE", autoReload = true) => {
|
|
33
33
|
if (typeof document === "undefined") return;
|
|
34
34
|
document.cookie = `${cookieName}=${locale}; max-age=31536000; path=/`;
|
|
35
|
-
|
|
35
|
+
if (autoReload) {
|
|
36
|
+
window.location.reload();
|
|
37
|
+
}
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
// src/selector.tsx
|
|
@@ -42,7 +44,8 @@ function LanguageSelector(props) {
|
|
|
42
44
|
locales,
|
|
43
45
|
defaultLocale,
|
|
44
46
|
cookieName = "NEXT_LOCALE",
|
|
45
|
-
isDropdown =
|
|
47
|
+
isDropdown = false,
|
|
48
|
+
autoReload = true,
|
|
46
49
|
renderCustom,
|
|
47
50
|
className,
|
|
48
51
|
activeColor = "red"
|
|
@@ -54,7 +57,7 @@ function LanguageSelector(props) {
|
|
|
54
57
|
}, [cookieName]);
|
|
55
58
|
const handleSelect = (code) => {
|
|
56
59
|
setCurrent(code);
|
|
57
|
-
setLocaleCookie(code, cookieName);
|
|
60
|
+
setLocaleCookie(code, cookieName, autoReload);
|
|
58
61
|
};
|
|
59
62
|
if (renderCustom) {
|
|
60
63
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: renderCustom({
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
-
declare const setLocaleCookie: (locale: string, cookieName?: string) => void;
|
|
3
|
+
declare const setLocaleCookie: (locale: string, cookieName?: string, autoReload?: boolean) => void;
|
|
4
4
|
|
|
5
5
|
interface LocaleConfig {
|
|
6
6
|
name: string;
|
|
@@ -14,6 +14,7 @@ interface LanguageSelectorProps {
|
|
|
14
14
|
cookieName?: string;
|
|
15
15
|
activeColor?: string;
|
|
16
16
|
className?: string;
|
|
17
|
+
autoReload?: boolean;
|
|
17
18
|
renderCustom?: (props: {
|
|
18
19
|
locales: LocaleConfig[];
|
|
19
20
|
currentLocale: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
-
declare const setLocaleCookie: (locale: string, cookieName?: string) => void;
|
|
3
|
+
declare const setLocaleCookie: (locale: string, cookieName?: string, autoReload?: boolean) => void;
|
|
4
4
|
|
|
5
5
|
interface LocaleConfig {
|
|
6
6
|
name: string;
|
|
@@ -14,6 +14,7 @@ interface LanguageSelectorProps {
|
|
|
14
14
|
cookieName?: string;
|
|
15
15
|
activeColor?: string;
|
|
16
16
|
className?: string;
|
|
17
|
+
autoReload?: boolean;
|
|
17
18
|
renderCustom?: (props: {
|
|
18
19
|
locales: LocaleConfig[];
|
|
19
20
|
currentLocale: string;
|
package/dist/index.mjs
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
|
|
4
4
|
// src/utils.ts
|
|
5
|
-
var setLocaleCookie = (locale, cookieName = "NEXT_LOCALE") => {
|
|
5
|
+
var setLocaleCookie = (locale, cookieName = "NEXT_LOCALE", autoReload = true) => {
|
|
6
6
|
if (typeof document === "undefined") return;
|
|
7
7
|
document.cookie = `${cookieName}=${locale}; max-age=31536000; path=/`;
|
|
8
|
-
|
|
8
|
+
if (autoReload) {
|
|
9
|
+
window.location.reload();
|
|
10
|
+
}
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
// src/selector.tsx
|
|
@@ -15,7 +17,8 @@ function LanguageSelector(props) {
|
|
|
15
17
|
locales,
|
|
16
18
|
defaultLocale,
|
|
17
19
|
cookieName = "NEXT_LOCALE",
|
|
18
|
-
isDropdown =
|
|
20
|
+
isDropdown = false,
|
|
21
|
+
autoReload = true,
|
|
19
22
|
renderCustom,
|
|
20
23
|
className,
|
|
21
24
|
activeColor = "red"
|
|
@@ -27,7 +30,7 @@ function LanguageSelector(props) {
|
|
|
27
30
|
}, [cookieName]);
|
|
28
31
|
const handleSelect = (code) => {
|
|
29
32
|
setCurrent(code);
|
|
30
|
-
setLocaleCookie(code, cookieName);
|
|
33
|
+
setLocaleCookie(code, cookieName, autoReload);
|
|
31
34
|
};
|
|
32
35
|
if (renderCustom) {
|
|
33
36
|
return /* @__PURE__ */ jsx(Fragment, { children: renderCustom({
|