remix-i18next
Advanced tools
Comparing version 6.1.1 to 6.2.0
@@ -28,1 +28,2 @@ /** | ||
} | ||
//# sourceMappingURL=client.js.map |
@@ -1,2 +0,3 @@ | ||
import { parseAcceptLanguage } from "intl-parse-accept-language"; | ||
import { formatLanguageString } from "./format-language-string.js"; | ||
import { parse, pick } from "./parser.js"; | ||
export function getClientLocales(requestOrHeaders) { | ||
@@ -8,14 +9,6 @@ let headers = getHeaders(requestOrHeaders); | ||
return undefined; | ||
let locales = parseAcceptLanguage(acceptLanguage, { | ||
validate: Intl.DateTimeFormat.supportedLocalesOf, | ||
ignoreWildcard: true, | ||
}); | ||
// if there are no locales found, return undefined | ||
if (locales.length === 0) | ||
return undefined; | ||
// if there is only one locale, return it | ||
if (locales.length === 1) | ||
return locales[0]; | ||
// if there are multiple locales, return the array | ||
return locales; | ||
let locale = pick(Intl.DateTimeFormat.supportedLocalesOf(parse(acceptLanguage) | ||
.filter((lang) => lang.code !== "*") | ||
.map(formatLanguageString)), acceptLanguage); | ||
return locale ?? undefined; | ||
} | ||
@@ -28,6 +21,6 @@ /** | ||
function getHeaders(requestOrHeaders) { | ||
if (requestOrHeaders instanceof Request) { | ||
if (requestOrHeaders instanceof Request) | ||
return requestOrHeaders.headers; | ||
} | ||
return requestOrHeaders; | ||
} | ||
//# sourceMappingURL=get-client-locales.js.map |
@@ -12,1 +12,2 @@ /** | ||
} | ||
//# sourceMappingURL=get-headers.js.map |
@@ -1,17 +0,2 @@ | ||
import * as React from "react"; | ||
export interface PreloadTranslationsProps { | ||
loadPath: string; | ||
} | ||
/** | ||
* Preload the translations files for the current language and the namespaces | ||
* required by the routes. | ||
* | ||
* It receives a single `loadPath` prop with the path to the translation files. | ||
* | ||
* @example | ||
* <PreloadTranslations loadPath="/locales/{{lng}}/{{ns}}.json" /> | ||
* | ||
*/ | ||
export declare function PreloadTranslations({ loadPath }: PreloadTranslationsProps): React.JSX.Element; | ||
/** | ||
* Get the locale returned by the root route loader under the `locale` key. | ||
@@ -18,0 +3,0 @@ * @example |
@@ -5,26 +5,2 @@ import { useMatches } from "@remix-run/react"; | ||
/** | ||
* Preload the translations files for the current language and the namespaces | ||
* required by the routes. | ||
* | ||
* It receives a single `loadPath` prop with the path to the translation files. | ||
* | ||
* @example | ||
* <PreloadTranslations loadPath="/locales/{{lng}}/{{ns}}.json" /> | ||
* | ||
*/ | ||
export function PreloadTranslations({ loadPath }) { | ||
let { i18n } = useTranslation(); | ||
let namespaces = [ | ||
...new Set(useMatches() | ||
.filter((route) => route.handle?.i18n !== undefined) | ||
.flatMap((route) => route.handle.i18n)), | ||
]; | ||
let lang = i18n.language; | ||
return (React.createElement(React.Fragment, null, namespaces.map((namespace) => { | ||
return (React.createElement("link", { key: namespace, rel: "preload", as: "fetch", href: loadPath | ||
.replace("{{lng}}", lang) | ||
.replace("{{ns}}", namespace) })); | ||
}))); | ||
} | ||
/** | ||
* Get the locale returned by the root route loader under the `locale` key. | ||
@@ -39,3 +15,5 @@ * @example | ||
export function useLocale(localeKey = "locale") { | ||
let [rootMatch] = useMatches(); | ||
let matches = useMatches(); | ||
// biome-ignore lint/style/noNonNullAssertion: There's always a root match | ||
let rootMatch = matches.at(0); | ||
let { [localeKey]: locale } = rootMatch.data ?? {}; | ||
@@ -56,4 +34,6 @@ if (!locale) | ||
React.useEffect(() => { | ||
i18n.changeLanguage(locale); | ||
if (i18n.language !== locale) | ||
i18n.changeLanguage(locale); | ||
}, [locale, i18n]); | ||
} | ||
//# sourceMappingURL=react.js.map |
import type { Cookie, EntryContext, SessionStorage } from "@remix-run/server-runtime"; | ||
import { Module, BackendModule, InitOptions, NewableModule, TFunction, Namespace } from "i18next"; | ||
import { type BackendModule, type InitOptions, type Module, type Namespace, type NewableModule, type TFunction } from "i18next"; | ||
export interface LanguageDetectorOption { | ||
@@ -103,6 +103,10 @@ /** | ||
* @param namespaces The namespaces to use for the T function. (Default: `translation`). | ||
* @param options The i18next init options | ||
* @param options The i18next init options and the key prefix to prepend to translation keys. | ||
*/ | ||
getFixedT<N extends Namespace>(locale: string, namespaces?: N, options?: Omit<InitOptions, "react">): Promise<TFunction<N>>; | ||
getFixedT<N extends Namespace>(request: Request, namespaces?: N, options?: Omit<InitOptions, "react">): Promise<TFunction<N>>; | ||
getFixedT<N extends Namespace, KPrefix extends string>(locale: string, namespaces?: N, options?: Omit<InitOptions, "react"> & { | ||
keyPrefix?: KPrefix; | ||
}): Promise<TFunction<N, KPrefix>>; | ||
getFixedT<N extends Namespace, KPrefix extends string>(request: Request, namespaces?: N, options?: Omit<InitOptions, "react"> & { | ||
keyPrefix?: KPrefix; | ||
}): Promise<TFunction<N, KPrefix>>; | ||
private createInstance; | ||
@@ -109,0 +113,0 @@ } |
@@ -1,4 +0,4 @@ | ||
import { pick } from "accept-language-parser"; | ||
import { createInstance, } from "i18next"; | ||
import { getClientLocales } from "./lib/get-client-locales.js"; | ||
import { pick } from "./lib/parser.js"; | ||
const DEFAULT_NS = "translation"; | ||
@@ -77,3 +77,3 @@ export class RemixI18Next { | ||
await instance.loadNamespaces(parsedNamespaces); | ||
return instance.getFixedT(locale, parsedNamespaces); | ||
return instance.getFixedT(locale, parsedNamespaces, options?.keyPrefix); | ||
} | ||
@@ -182,1 +182,2 @@ async createInstance(options = {}) { | ||
} | ||
//# sourceMappingURL=server.js.map |
190
package.json
{ | ||
"name": "remix-i18next", | ||
"version": "6.1.1", | ||
"description": "The easiest way to translate your Remix apps", | ||
"license": "MIT", | ||
"homepage": "https://github.com/sergiodxa/remix-i18next#readme", | ||
"engines": { | ||
"node": ">=18.0.0" | ||
}, | ||
"type": "module", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
"./client": "./build/client.js", | ||
"./server": "./build/server.js", | ||
"./react": "./build/react.js" | ||
}, | ||
"sideEffects": false, | ||
"scripts": { | ||
"prepare": "npm run build", | ||
"build": "tsc --project tsconfig.json --outDir ./build", | ||
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.tsx\" \"test/**/*.ts\" \"test/**/*.tsx\" \"*.md\" \"package.json\"", | ||
"typecheck": "tsc --project tsconfig.json --noEmit", | ||
"lint": "eslint --ext .ts,.tsx src/", | ||
"test": "vitest --run", | ||
"test:watch": "vitest", | ||
"test:coverage": "vitest --coverage", | ||
"test:exports": "bun scripts/check-pkg-exports.ts" | ||
}, | ||
"author": { | ||
"name": "Sergio Xalambrí", | ||
"url": "https://sergiodxa.com", | ||
"email": "hello@sergiodxa.com" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/sergiodxa/remix-i18next.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/sergiodxa/remix-i18next/issues" | ||
}, | ||
"funding": "https://github.com/sponsors/sergiodxa", | ||
"keywords": [ | ||
"remix", | ||
"i18n", | ||
"i18next", | ||
"ssr", | ||
"csr" | ||
], | ||
"dependencies": { | ||
"accept-language-parser": "^1.5.0", | ||
"intl-parse-accept-language": "^1.0.0" | ||
}, | ||
"peerDependencies": { | ||
"@remix-run/cloudflare": "^2.0.0", | ||
"@remix-run/deno": "^2.0.0", | ||
"@remix-run/node": "^2.0.0", | ||
"@remix-run/react": "^2.0.0", | ||
"i18next": "^23.1.0", | ||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", | ||
"react-i18next": "^13.0.0 || ^14.0.0 || ^15.0.0" | ||
}, | ||
"peerDependenciesMeta": { | ||
"@remix-run/cloudflare": { | ||
"optional": true | ||
}, | ||
"@remix-run/deno": { | ||
"optional": true | ||
}, | ||
"@remix-run/node": { | ||
"optional": true | ||
} | ||
}, | ||
"devDependencies": { | ||
"@arethetypeswrong/cli": "^0.14.1", | ||
"@remix-run/cloudflare": "^2.7.2", | ||
"@remix-run/deno": "^2.7.2", | ||
"@remix-run/dev": "^2.7.2", | ||
"@remix-run/node": "^2.7.2", | ||
"@remix-run/react": "^2.7.2", | ||
"@remix-run/server-runtime": "^2.7.2", | ||
"@types/accept-language-parser": "^1.5.6", | ||
"@types/bun": "^1.0.7", | ||
"@types/node": "^20.11.20", | ||
"@types/prop-types": "^15.7.11", | ||
"@types/react": "^18.2.58", | ||
"@typescript-eslint/eslint-plugin": "^7.0.2", | ||
"@typescript-eslint/parser": "^7.0.2", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-import-resolver-typescript": "^3.6.1", | ||
"eslint-plugin-import": "^2.29.1", | ||
"eslint-plugin-jest-dom": "^5.1.0", | ||
"eslint-plugin-jsx-a11y": "^6.8.0", | ||
"eslint-plugin-prettier": "^5.1.3", | ||
"eslint-plugin-promise": "^6.1.1", | ||
"eslint-plugin-react": "^7.33.2", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-testing-library": "^6.2.0", | ||
"eslint-plugin-unicorn": "^51.0.1", | ||
"i18next": "^23.10.0", | ||
"prettier": "^3.2.5", | ||
"react": "^18.2.0", | ||
"react-i18next": "^14.0.5", | ||
"ts-node": "^10.9.2", | ||
"typescript": "^5.3.3", | ||
"vitest": "^1.3.1" | ||
} | ||
"name": "remix-i18next", | ||
"version": "6.2.0", | ||
"author": { | ||
"name": "Sergio Xalambrí", | ||
"url": "https://sergiodxa.com", | ||
"email": "hello@sergiodxa.com" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/sergiodxa/remix-i18next.git" | ||
}, | ||
"devDependencies": { | ||
"@arethetypeswrong/cli": "^0.15.3", | ||
"@biomejs/biome": "^1.8.3", | ||
"@remix-run/cloudflare": "^2.0.0", | ||
"@remix-run/deno": "^2.0.0", | ||
"@remix-run/dev": "^2.11.0", | ||
"@remix-run/node": "^2.0.0", | ||
"@remix-run/react": "^2.0.0", | ||
"@remix-run/server-runtime": "^2.11.0", | ||
"@total-typescript/tsconfig": "^1.0.4", | ||
"@types/accept-language-parser": "^1.5.6", | ||
"@types/bun": "^1.1.6", | ||
"@types/react": "^18.3.3", | ||
"consola": "^3.2.3", | ||
"i18next": "^23.1.0", | ||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", | ||
"react-i18next": "^13.0.0 || ^14.0.0 || ^15.0.0", | ||
"typedoc": "^0.26.5", | ||
"typedoc-plugin-mdn-links": "^3.2.6", | ||
"typescript": "^5.5.4" | ||
}, | ||
"peerDependencies": { | ||
"@remix-run/cloudflare": "^2.0.0", | ||
"@remix-run/deno": "^2.0.0", | ||
"@remix-run/node": "^2.0.0", | ||
"@remix-run/react": "^2.0.0", | ||
"i18next": "^23.1.0", | ||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", | ||
"react-i18next": "^13.0.0 || ^14.0.0 || ^15.0.0" | ||
}, | ||
"exports": { | ||
"./package.json": "./package.json", | ||
"./client": "./build/client.js", | ||
"./server": "./build/server.js", | ||
"./react": "./build/react.js" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/sergiodxa/remix-i18next/issues" | ||
}, | ||
"description": "The easiest way to translate your Remix apps", | ||
"engines": { | ||
"node": ">=20.0.0" | ||
}, | ||
"funding": "https://github.com/sponsors/sergiodxa", | ||
"homepage": "https://github.com/sergiodxa/remix-i18next#readme", | ||
"keywords": [ | ||
"remix", | ||
"i18n", | ||
"i18next", | ||
"ssr", | ||
"csr" | ||
], | ||
"license": "MIT", | ||
"peerDependenciesMeta": { | ||
"@remix-run/cloudflare": { | ||
"optional": true | ||
}, | ||
"@remix-run/deno": { | ||
"optional": true | ||
}, | ||
"@remix-run/node": { | ||
"optional": true | ||
} | ||
}, | ||
"scripts": { | ||
"build": "tsc", | ||
"typecheck": "tsc --noEmit", | ||
"quality": "biome check .", | ||
"quality:fix": "biome check . --write --unsafe", | ||
"exports": "bun run ./scripts/exports.ts" | ||
}, | ||
"sideEffects": false, | ||
"type": "module" | ||
} |
@@ -377,1 +377,18 @@ # remix-i18next | ||
This options will be overwritten by the options provided to `getFixedT`. | ||
#### Using the `keyPrefix` option with `getFixedT` | ||
The `getFixedT` function now supports a `keyPrefix` option, allowing you to prepend a prefix to your translation keys. This is particularly useful when you want to namespace your translations without having to specify the full key path every time. | ||
Here's how you can use it: | ||
```ts | ||
export async function loader({ request }: LoaderArgs) { | ||
// Assuming "greetings" namespace and "welcome" keyPrefix | ||
let t = await i18n.getFixedT(request, "greetings", { keyPrefix: "welcome" }); | ||
let message = t("user"); // This will look for the "welcome.user" key in your "greetings" namespace | ||
return json({ message }); | ||
} | ||
``` | ||
This feature simplifies working with deeply nested translation keys and enhances the organization of your translation files. |
Sorry, the diff of this file is not supported yet
7
19
29
628
394
333218
- Removedaccept-language-parser@^1.5.0
- Removedintl-parse-accept-language@^1.0.0
- Removedaccept-language-parser@1.5.0(transitive)
- Removedintl-parse-accept-language@1.0.0(transitive)