Skip to content

Commit

Permalink
feat: load resource by namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
hemengke1997 committed Sep 18, 2024
1 parent c8689d5 commit a5c2c9f
Show file tree
Hide file tree
Showing 172 changed files with 18,298 additions and 7,008 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ playground-temp
.DS_Store
.tsup
.eslintcache
TODO.md
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
{
"i18n-ally.localesPaths": ["playground/spa-with-namespace/src/locales"],
"i18n-ally.keystyle": "nested",
"i18n-ally.enabledParsers": ["json", "json5", "yaml", "ts"],
"i18n-ally.enabledFrameworks": ["react", "i18next", "react-i18next"],
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.sourceLanguage": "en",
"eslint.experimental.useFlatConfig": true
"i18n-ally.sourceLanguage": "en"
}
106 changes: 54 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,83 +55,85 @@ pnpm add vite-plugin-i18n-ally -D
### vite.config.ts

```ts
import path from 'node:path';
import { defineConfig } from 'vite';
import { i18nAlly } from 'vite-plugin-i18n-ally';
import path from 'node:path'
import { defineConfig } from 'vite'
import { i18nAlly } from 'vite-plugin-i18n-ally'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [i18nAlly()],
});
})
```

## Client Options

| Option | Type | Description |
| ---------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| language | `string`\| `undefined` | The current language |
| onInited | `Function` | Callback after initialization |
| onResourceLoaded | `Function` | Callback after resource loaded |
| fallbackLng | `string` | Fallback language |
| cache | `object` | Cache configuration. You can cache the language on `html`/`querystring`/`cookie`/`sessionStorage`/`localStorage` |
| Option | Type | Description |
| ---------------- | ---------- | --------------------------------------------------------------------- |
| language | `string` | The current language |
| namespaces | `string[]` | Initial namespaces |
| onInited | `Function` | Callback after initialization |
| onResourceLoaded | `Function` | Callback after resource loaded |
| fallbackLng | `string` | Fallback language |
| detection | `Array` | Language detection and cache, like `i18next-browser-languagedetector` |

## Use with i18next

### main.tsx

```tsx
import i18next from 'i18next';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initReactI18next } from 'react-i18next';
import { i18nAlly } from 'vite-plugin-i18n-ally/client';
import App from './App';

const root = ReactDOM.createRoot(document.querySelector('#root') as HTMLElement);

const lookupTarget = 'lang';
const fallbackLng = 'en';

i18next.use(initReactI18next).init({
resources: {}, // !!! important: No resources are added at initialization, otherwise what's lazy loading :)
nsSeparator: '.',
keySeparator: '.',
fallbackLng,
});

const { beforeLanguageChange } = i18nAlly({
language: i18next.language,
import React from 'react'
import { initReactI18next } from 'react-i18next'
import i18next from 'i18next'
import ReactDOM from 'react-dom/client'
import { i18nAlly } from 'vite-plugin-i18n-ally/client'
import App from './App'

const root = ReactDOM.createRoot(document.querySelector('#root') as HTMLElement)

const { asyncLoadResource } = i18nAlly({
onInit() {
i18next.use(initReactI18next).init({
resources: {}, // !!! important: No resources are added at initialization, otherwise what's lazy loading :)
nsSeparator: '.',
keySeparator: '.',
fallbackLng: 'en',
})
},
onInited() {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
)
},
onResourceLoaded: (resource, currentLang) => {
// Once the resource is loaded, add it to i18next
Object.keys(resource).forEach((ns) => {
i18next.addResourceBundle(currentLang, ns, resource[ns]);
});
},
fallbackLng,
/**
* Cache configuration
* You can cache the current language to `html`/`querystring`/`cookie`/`sessionStorage`/`localStorage`
* If this does not meet your needs, you can use the Detector plugin provided by the i18n library to replace this functionality.
*/
cache: {
querystring: lookupTarget, // If you want to cache on querystring
cookie: 'lang-cookie', // If you want to cache on cookie
Object.keys(resources).forEach((ns) => {
i18next.addResourceBundle(language, ns, resources[ns])
})
},
});

const i18nextChangeLanguage = i18next.changeLanguage;
fallbackLng: 'en',
detection: [
{
detect: 'querystring',
lookup: 'lang',
},
{
detect: 'cookie',
lookup: 'cookie-name',
},
{
detect: 'htmlTag',
},
],
})

const i18nextChangeLanguage = i18next.changeLanguage
i18next.changeLanguage = async (lang: string, ...args) => {
// Load resources before language change
await beforeLanguageChange(lang);
return i18nextChangeLanguage(lang, ...args);
};
await asyncLoadResource(lang)
return i18nextChangeLanguage(lang, ...args)
}
```

## Full Example
Expand Down
113 changes: 57 additions & 56 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,87 +53,88 @@ pnpm add vite-plugin-i18n-ally -D
### vite.config.ts

```ts
import path from 'node:path';
import { defineConfig } from 'vite';
import { i18nAlly } from 'vite-plugin-i18n-ally';
import path from 'node:path'
import { defineConfig } from 'vite'
import { i18nAlly } from 'vite-plugin-i18n-ally'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [i18nAlly()],
});
})
```

## 客户端配置项

| 参数 | 类型 | 描述 |
| ---------------- | ----------------------- | ------------------------------------------------------------------------------------------------- |
| language | `string` \| `undefined` | 当前语言 |
| onInited | `Function` | 初始化完成后的回调 |
| onResourceLoaded | `Function` | 资源加载完成后的回调,参数为资源和当前语言 |
| fallbackLng | `string` | 回退语言 |
| cache | `object` | 缓存配置。你可以把当前语言缓存到 `html`/`querystring`/`cookie`/`sessionStorage`/`localStorage`|
| 参数 | 类型 | 描述 |
| ---------------- | ---------- | ------------------------------------------------------- |
| language | `string` | 当前语言 |
| namespaces | `string[]` | 当前路由所需的namespaces |
| onInited | `Function` | 初始化完成后的回调 |
| onResourceLoaded | `Function` | 资源加载完成后的回调,参数为资源和当前语言 |
| fallbackLng | `string` | 回退语言 |
| detection | `Array` | 语言探测和缓存,类似 `i18next-browser-languagedetector` |

## 与i18next配合使用

### main.tsx

```tsx
import i18next from 'i18next';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { initReactI18next } from 'react-i18next';
import { i18nAlly } from 'vite-plugin-i18n-ally/client'; // 注意是 client
import App from './App';

const root = ReactDOM.createRoot(document.querySelector('#root') as HTMLElement);

const lookupTarget = 'lang';
const fallbackLng = 'en';

await i18next.use(initReactI18next).init({
resources: {}, // !!! 初始化时不添加资源,不然何来懒加载:)
nsSeparator: '.',
keySeparator: '.',
fallbackLng,
});

const { beforeLanguageChange } = i18nAlly({
language: i18next.language,
import React from 'react'
import { initReactI18next } from 'react-i18next'
import i18next from 'i18next'
import ReactDOM from 'react-dom/client'
import { i18nAlly } from 'vite-plugin-i18n-ally/client' // 注意是 client
import App from './App'

const root = ReactDOM.createRoot(document.querySelector('#root') as HTMLElement)

const { asyncLoadResource } = i18nAlly({
onInit() {
i18next.use(initReactI18next).init({
resources: {}, // !!! 初始化时不添加资源,不然何来懒加载:)
nsSeparator: '.',
keySeparator: '.',
fallbackLng: 'en',
})
},
onInited() {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
)
},
onResourceLoaded: (resource, currentLang) => {
// 资源加载完成后,添加到i18next
// 如果你使用namespace
Object.keys(resource).forEach((ns) => {
i18next.addResourceBundle(currentLang, ns, resource[ns]);
});
// 如果你不使用namespace
// i18next.addResourceBundle(currentLang, 'translation', resource)
onResourceLoaded: (resources, { language }) => {
Object.keys(resources).forEach((ns) => {
i18next.addResourceBundle(language, ns, resources[ns])
})
},
fallbackLng,
fallbackLng: 'en',
/**
* 缓存配置
* vite-plugin-i18n-ally 实现了一套简单易用的缓存机制
* 你可以把当前语言缓存到 `html`/`querystring`/`cookie`/`sessionStorage`/`localStorage` 上
* 如果不满足你的需求,可以使用i18n库提供的Detector插件来替代此功能
* 探测配置
* vite-plugin-i18n-ally 实现了一套简单易用的探测缓存机制
*/
cache: {
querystring: lookupTarget, // 如果你想缓存到url querystring上
cookie: 'lang-cookie', // 如果你想缓存到cookie
},
});

const i18nextChangeLanguage = i18next.changeLanguage;
detection: [
{
detect: 'querystring',
lookup: 'lang',
},
{
detect: 'cookie',
lookup: 'cookie-name',
},
{
detect: 'htmlTag',
},
],
})

const i18nextChangeLanguage = i18next.changeLanguage
i18next.changeLanguage = async (lang: string, ...args) => {
// 语言改变之前,先加载资源
await beforeLanguageChange(lang);
return i18nextChangeLanguage(lang, ...args);
};
await asyncLoadResource(lang)
return i18nextChangeLanguage(lang, ...args)
}
```

## 完整示例
Expand Down
2 changes: 1 addition & 1 deletion client.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './dist/client/index.js'
export * from './dist/client'
40 changes: 20 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@
"build": "rm -rf dist && tsup",
"build:pages": "npm run build && cd playground/spa-with-namespace && npm run build",
"test": "run-s test:unit test:serve test:build",
"test:unit": "cross-env DEBUG=vite-plugin-i18n* vitest run",
"test:serve": "cross-env DEBUG=vite-plugin-i18n* vitest run -c vitest.config.e2e.ts",
"test:unit": "vitest run",
"test:serve": "vitest run -c vitest.config.e2e.ts",
"test:build": "cross-env VITE_TEST_BUILD=1 vitest run -c vitest.config.e2e.ts",
"prepare": "simple-git-hooks",
"lint": "eslint . --fix --cache",
"commitlint": "commitlint -e",
"up": "taze -I -w -r",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
"bump": "bumpp package.json -c --no-push -t --all -x \"npm run changelog\""
Expand All @@ -56,49 +57,48 @@
},
"dependencies": {
"clone-deep": "^4.0.1",
"debug": "^4.3.5",
"debug": "^4.3.7",
"fast-glob": "^3.3.2",
"find-up": "^7.0.0",
"importx": "^0.3.11",
"importx": "^0.4.4",
"js-yaml": "^4.1.0",
"json5": "^2.2.3",
"language-tags": "^1.0.9",
"string.prototype.trimend": "^1.0.8",
"uniq": "^1.0.1",
"watcher": "^2.3.1"
"uniq": "^1.0.1"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@minko-fe/commitlint-config": "^2.1.0",
"@minko-fe/eslint-config": "^3.2.0",
"@minko-fe/tsconfig": "^2.1.0",
"@swc/core": "^1.6.13",
"@commitlint/cli": "^19.5.0",
"@minko-fe/commitlint-config": "^2.1.2",
"@minko-fe/eslint-config": "^4.0.2",
"@minko-fe/tsconfig": "^2.1.1",
"@swc/core": "^1.7.26",
"@types/clone-deep": "^4.0.4",
"@types/debug": "^4.1.12",
"@types/js-yaml": "^4.0.9",
"@types/language-tags": "^1.0.4",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"bumpp": "^9.4.1",
"@types/node": "^22.5.5",
"@types/react": "^18.3.7",
"bumpp": "^9.5.2",
"conventional-changelog-cli": "^5.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint": "^9.10.0",
"i18next": "23.5.1",
"jsdom": "^22.1.0",
"npm-run-all": "^4.1.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "13.2.2",
"simple-git-hooks": "^2.11.1",
"taze": "^0.15.1",
"tsup": "^8.1.0",
"typescript": "^5.5.3",
"taze": "^0.16.9",
"tsup": "^8.3.0",
"typescript": "^5.6.2",
"vite-plugin-i18n-ally": "workspace:*",
"vitest": "0.34.5",
"vitest": "^2.1.1",
"vitest-e2e": "^0.0.10"
},
"simple-git-hooks": {
"commit-msg": "npx commitlint -e",
"commit-msg": "npm run commitlint",
"pre-commit": "npm run lint"
},
"commitlint": {
Expand Down
2 changes: 1 addition & 1 deletion playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"dependencies": {},
"devDependencies": {
"node-fetch": "^3.3.2",
"sirv": "^2.0.3",
"sirv": "^2.0.4",
"tree-kill": "^1.2.2"
}
}
Loading

0 comments on commit a5c2c9f

Please sign in to comment.