remix-i18next
Advanced tools
Comparing version 4.1.1 to 4.2.0
@@ -1,2 +0,2 @@ | ||
export declare type Locales = string | string[] | undefined; | ||
export type Locales = string | string[] | undefined; | ||
/** | ||
@@ -3,0 +3,0 @@ * Get the client's locales from the Accept-Language header. |
@@ -21,4 +21,7 @@ /// <reference types="react" /> | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
* @example | ||
* let locale = useLocale("language") | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
*/ | ||
export declare function useLocale(): string; | ||
export declare function useLocale(localeKey?: string): string; | ||
/** | ||
@@ -25,0 +28,0 @@ * Detect when the locale returned by the root route loader changes and call |
@@ -20,3 +20,3 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; | ||
.filter((route) => { var _a; return ((_a = route.handle) === null || _a === void 0 ? void 0 : _a.i18n) !== undefined; }) | ||
.flatMap((route) => route.handle.i18n)), | ||
.flatMap((route) => { var _a; return (_a = route.handle) === null || _a === void 0 ? void 0 : _a.i18n; })), | ||
]; | ||
@@ -35,7 +35,10 @@ let lang = i18n.language; | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
* @example | ||
* let locale = useLocale("language") | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
*/ | ||
export function useLocale() { | ||
export function useLocale(localeKey = "locale") { | ||
var _a; | ||
let [rootMatch] = useMatches(); | ||
let { locale } = (_a = rootMatch.data) !== null && _a !== void 0 ? _a : {}; | ||
let { [localeKey]: locale } = (_a = rootMatch.data) !== null && _a !== void 0 ? _a : {}; | ||
if (!locale) | ||
@@ -42,0 +45,0 @@ throw new Error("Missing locale returned by the root loader."); |
@@ -1,2 +0,2 @@ | ||
export declare type Locales = string | string[] | undefined; | ||
export type Locales = string | string[] | undefined; | ||
/** | ||
@@ -3,0 +3,0 @@ * Get the client's locales from the Accept-Language header. |
@@ -21,4 +21,7 @@ /// <reference types="react" /> | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
* @example | ||
* let locale = useLocale("language") | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
*/ | ||
export declare function useLocale(): string; | ||
export declare function useLocale(localeKey?: string): string; | ||
/** | ||
@@ -25,0 +28,0 @@ * Detect when the locale returned by the root route loader changes and call |
@@ -23,3 +23,3 @@ "use strict"; | ||
.filter((route) => { var _a; return ((_a = route.handle) === null || _a === void 0 ? void 0 : _a.i18n) !== undefined; }) | ||
.flatMap((route) => route.handle.i18n)), | ||
.flatMap((route) => { var _a; return (_a = route.handle) === null || _a === void 0 ? void 0 : _a.i18n; })), | ||
]; | ||
@@ -39,7 +39,10 @@ let lang = i18n.language; | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
* @example | ||
* let locale = useLocale("language") | ||
* let formattedDate = date.toLocaleDateString(locale); | ||
*/ | ||
function useLocale() { | ||
function useLocale(localeKey = "locale") { | ||
var _a; | ||
let [rootMatch] = (0, react_1.useMatches)(); | ||
let { locale } = (_a = rootMatch.data) !== null && _a !== void 0 ? _a : {}; | ||
let { [localeKey]: locale } = (_a = rootMatch.data) !== null && _a !== void 0 ? _a : {}; | ||
if (!locale) | ||
@@ -46,0 +49,0 @@ throw new Error("Missing locale returned by the root loader."); |
{ | ||
"name": "remix-i18next", | ||
"version": "4.1.1", | ||
"version": "4.2.0", | ||
"description": "The easiest way to translate your Remix apps", | ||
@@ -43,5 +43,5 @@ "license": "MIT", | ||
"@remix-run/server-runtime": "^1.0.0", | ||
"i18next": "^21.3.3", | ||
"i18next": "^21.3.3 || ^22.0.3", | ||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", | ||
"react-i18next": "^11.13.0" | ||
"react-i18next": "^11.13.0 || ^12.0.0" | ||
}, | ||
@@ -51,34 +51,33 @@ "dependencies": { | ||
"intl-parse-accept-language": "^1.0.0", | ||
"lru-cache": "^7.10.0", | ||
"lru-cache": "^7.14.1", | ||
"use-consistent-value": "^1.0.0" | ||
}, | ||
"devDependencies": { | ||
"@remix-run/dev": "^1.4.3", | ||
"@remix-run/node": "^1.4.3", | ||
"@remix-run/react": "^1.4.3", | ||
"@remix-run/server-runtime": "^1.4.3", | ||
"@remix-run/dev": "^1.7.6", | ||
"@remix-run/node": "^1.7.6", | ||
"@remix-run/react": "^1.7.6", | ||
"@remix-run/server-runtime": "^1.7.6", | ||
"@types/accept-language-parser": "^1.5.3", | ||
"@types/lru-cache": "^7.6.1", | ||
"@types/node": "^17.0.32", | ||
"@types/node": "^18.11.9", | ||
"@types/prop-types": "^15.7.5", | ||
"@types/react": "^18.0.9", | ||
"@typescript-eslint/eslint-plugin": "^5.23.0", | ||
"@typescript-eslint/parser": "^5.23.0", | ||
"eslint": "^8.15.0", | ||
"@types/react": "^18.0.25", | ||
"@typescript-eslint/eslint-plugin": "^5.44.0", | ||
"@typescript-eslint/parser": "^5.44.0", | ||
"eslint": "^8.28.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-cypress": "^2.12.1", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-jest-dom": "^4.0.1", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"eslint-plugin-testing-library": "^5.5.0", | ||
"eslint-plugin-unicorn": "^42.0.0", | ||
"i18next": "^21.8.1", | ||
"prettier": "^2.6.2", | ||
"react": "^18.1.0", | ||
"react-i18next": "^11.16.9", | ||
"ts-node": "^10.7.0", | ||
"typescript": "^4.6.4", | ||
"vitest": "^0.12.4" | ||
"eslint-plugin-jest-dom": "^4.0.3", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"eslint-plugin-promise": "^6.1.1", | ||
"eslint-plugin-testing-library": "^5.9.1", | ||
"eslint-plugin-unicorn": "^45.0.0", | ||
"i18next": "^22.0.6", | ||
"prettier": "^2.8.0", | ||
"react": "^18.2.0", | ||
"react-i18next": "^12.0.0", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.9.3", | ||
"vitest": "^0.25.3" | ||
} | ||
} |
157
README.md
@@ -30,21 +30,59 @@ # remix-i18next | ||
Then create a `i18n.server.ts` file somewhere in your app and add the following code: | ||
First let's create some translation files | ||
`public/locales/en/common.json`: | ||
```json | ||
{ | ||
"greeting": "Hello" | ||
} | ||
``` | ||
`public/locales/es/common.json`: | ||
```json | ||
{ | ||
"greeting": "Hola" | ||
} | ||
``` | ||
Next, set your [i18next configuration](https://www.i18next.com/overview/configuration-options). | ||
These two files can go somewhere in your app folder. | ||
For this example, we will create `app/i18n.ts`: | ||
```ts | ||
import Backend from "i18next-fs-backend"; | ||
import { resolve } from "node:path"; | ||
import { RemixI18Next } from "remix-i18next"; | ||
export default { | ||
// This is the list of languages your application supports | ||
supportedLngs: ['en', 'es'], | ||
// This is the language you want to use in case | ||
// if the user language is not in the supportedLngs | ||
fallbackLng: 'en', | ||
// The default namespace of i18next is "translation", but you can customize it here | ||
defaultNS: 'common', | ||
// Disabling suspense is recommended | ||
react: {useSuspense: false}, | ||
}; | ||
``` | ||
export let i18n = new RemixI18Next({ | ||
And then create a file named `i18next.server.ts` with the following code: | ||
```ts | ||
import Backend from 'i18next-fs-backend'; | ||
import { resolve } from 'node:path'; | ||
import { RemixI18Next } from 'remix-i18next'; | ||
import i18n from '~/i18n'; // your i18n configuration file | ||
let i18next = new RemixI18Next({ | ||
detection: { | ||
// This is the list of languages your application supports | ||
supportedLanguages: ["es", "en"], | ||
// This is the language you want to use in case the user language is not | ||
// listed above | ||
fallbackLanguage: "en", | ||
supportedLanguages: i18n.supportedLngs, | ||
fallbackLanguage: i18n.fallbackLng, | ||
}, | ||
// This is the configuration for i18next used when translating messages server | ||
// side only | ||
// This is the configuration for i18next used | ||
// when translating messages server-side only | ||
i18next: { | ||
backend: { loadPath: resolve("./public/locales/{{lng}}/{{ns}}.json") }, | ||
...i18n, | ||
backend: { | ||
loadPath: resolve('./public/locales/{{lng}}/{{ns}}.json'), | ||
}, | ||
}, | ||
@@ -56,2 +94,4 @@ // The backend you want to use to load the translations | ||
}); | ||
export default i18next; | ||
``` | ||
@@ -64,9 +104,10 @@ | ||
```tsx | ||
import { RemixBrowser } from "@remix-run/react"; | ||
import i18next from "i18next"; | ||
import LanguageDetector from "i18next-browser-languagedetector"; | ||
import Backend from "i18next-http-backend"; | ||
import { hydrate } from "react-dom"; | ||
import { I18nextProvider, initReactI18next } from "react-i18next"; | ||
import { getInitialNamespaces } from "remix-i18next"; | ||
import { RemixBrowser } from '@remix-run/react'; | ||
import i18next from 'i18next'; | ||
import LanguageDetector from 'i18next-browser-languagedetector'; | ||
import Backend from 'i18next-http-backend'; | ||
import { hydrate } from 'react-dom'; | ||
import { I18nextProvider, initReactI18next } from 'react-i18next'; | ||
import { getInitialNamespaces } from 'remix-i18next'; | ||
import i18n from './i18n'; // your i18n configuration file | ||
@@ -78,12 +119,8 @@ i18next | ||
.init({ | ||
// This is normal i18next config, except a few things | ||
supportedLngs: ["es", "en"], | ||
defaultNS: "common", | ||
fallbackLng: "en", | ||
// Disabling suspense is recommended | ||
react: { useSuspense: false }, | ||
...i18n, // spread the configuration | ||
// This function detects the namespaces your routes rendered while SSR use | ||
// and pass them here to load the translations | ||
ns: getInitialNamespaces(), | ||
backend: { loadPath: "/locales/{{lng}}/{{ns}}.json" }, | ||
backend: { | ||
loadPath: '/locales/{{lng}}/{{ns}}.json', | ||
}, | ||
detection: { | ||
@@ -124,3 +161,4 @@ // Here only enable htmlTag detection, we'll detect the language only | ||
import { I18nextProvider, initReactI18next } from "react-i18next"; | ||
import { i18n } from "./services/i18n.server"; | ||
import i18next from "./i18next.server"; | ||
import i18n from './i18n'; // your i18n configuration file | ||
@@ -138,5 +176,5 @@ export default async function handleRequest( | ||
// Then we could detect locale from the request | ||
let lng = await i18n.getLocale(request); | ||
let lng = await i18next.getLocale(request); | ||
// And here we detect what namespaces the routes about to render want to use | ||
let ns = i18n.getRouteNamespaces(context); | ||
let ns = i18next.getRouteNamespaces(context); | ||
@@ -147,10 +185,5 @@ await instance | ||
.init({ | ||
// And configure i18next as usual | ||
supportedLngs: ["es", "en"], | ||
defaultNS: "common", | ||
fallbackLng: "en", | ||
// Disable suspense again here | ||
react: { useSuspense: false }, | ||
...i18n, // spread the configuration | ||
lng, // The locale we detected above | ||
ns, // The namespaces the routes about to render want to use | ||
ns, // The namespaces the routes about to render wants to use | ||
backend: { | ||
@@ -180,3 +213,3 @@ loadPath: resolve("./public/locales/{{lng}}/{{ns}}.json"), | ||
Now, in your `root` file create a loader if you don't have one with the following code and also run the `useSetupTranslations` hook on the Root component. | ||
Now, in your `app/root.tsx` or `app/root.jsx` file create a loader if you don't have one with the following code. | ||
@@ -191,6 +224,8 @@ ```tsx | ||
ScrollRestoration, | ||
useLoaderData, | ||
Outlet, | ||
} from "@remix-run/react"; | ||
import { i18n } from "~/i18n.server.ts"; | ||
import { useChangeLanguage } from "remix-i18next"; | ||
import { useTranslation } from "react-i18next"; | ||
import i18next from "~/i18next.server"; | ||
@@ -200,3 +235,3 @@ type LoaderData = { locale: string }; | ||
export let loader: LoaderFunction = async ({ request }) => { | ||
let locale = await i18n.getLocale(request); | ||
let locale = await i18next.getLocale(request); | ||
return json<LoaderData>({ locale }); | ||
@@ -206,5 +241,7 @@ }; | ||
export let handle = { | ||
// In the handle export, we could add a i18n key with namespaces our route | ||
// In the handle export, we can add a i18n key with namespaces our route | ||
// will need to load. This key can be a single string or an array of strings. | ||
i18n: ["translations", "root"], | ||
// TIP: In most cases, you should set this to your defaultNS from your i18n config | ||
// or if you did not set one, set it to the i18next default namespace "translation" | ||
i18n: "common", | ||
}; | ||
@@ -231,3 +268,3 @@ | ||
<body> | ||
{children} | ||
<Outlet /> | ||
<ScrollRestoration /> | ||
@@ -242,8 +279,36 @@ <Scripts /> | ||
Finally, in any route you want to translate you can do this: | ||
Finally, in any route you want to translate, you can use the `t()` function, as per the [i18next documentation](https://www.i18next.com/overview/api#t) and use translations from the default namespace. | ||
```tsx | ||
import { json, LoaderFunction } from "@remix-run/node"; | ||
import { useTranslation } from "react-i18next"; | ||
export default function Component() { | ||
let { t } = useTranslation(); | ||
return <h1>{t("greeting")}</h1>; | ||
} | ||
``` | ||
If you wish to split up your translation files, you create new translation files | ||
like: | ||
`public/locales/en/home.json` | ||
```json | ||
{ | ||
"title": "remix-i18n is awesome" | ||
} | ||
``` | ||
`public/locales/es/home.json` | ||
```json | ||
{ | ||
"title": "remix-i18n es increíble" | ||
} | ||
``` | ||
And use them in your routes: | ||
```tsx | ||
import { useTranslation } from "react-i18next"; | ||
// This tells remix to load the "home" namespace | ||
export let handle = { | ||
@@ -250,0 +315,0 @@ i18n: "home", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
49725
26
941
353
+ Addedi18next@22.5.1(transitive)
+ Addedreact-i18next@12.3.1(transitive)
- Removedi18next@21.10.0(transitive)
- Removedreact-i18next@11.18.6(transitive)
Updatedlru-cache@^7.14.1