Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 80 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ npm i --save @kne/react-intl

技术亮点在于提供了多种创建方式,createIntlProvider 用于创建完整的国际化上下文,createWithIntlProvider 可以为单个组件注入国际化能力,createIntl 则适用于非组件环境的国际化场景。消息加载器支持单个和批量加载,命名空间机制确保不同模块的翻译内容互不干扰。

***远程加载语言包***

远程加载语言包功能支持通过 API 动态获取翻译内容,当本地缺少某语言的翻译时自动触发远程请求。提供智能缓存机制,避免重复请求相同的语言包,适用于按需加载、动态扩展语言支持、分包优化等场景。开发者可通过配置全局上下文的 localeMessage 接口,灵活集成后端翻译服务,实现运营人员动态管理翻译内容,无需重新部署应用。

### 示例

Expand All @@ -40,8 +43,8 @@ npm i --save @kne/react-intl

#### 示例代码

- 基础国际化
- 使用createIntlProvider创建国际化Provider,支持语言切换
- 基础语言切换
- 实现中英文切换功能,通过下拉选择器实时更新页面语言
- _ReactIntl(@kne/current-lib_react-intl)[import * as _ReactIntl from "@kne/react-intl"],antd(antd)

```jsx
Expand Down Expand Up @@ -85,6 +88,81 @@ render(<BaseExample />);

```

- 远程加载语言
- 支持API远程动态加载语言包,扩展多语言支持至日语和德语
- _ReactIntl(@kne/current-lib_react-intl)[import * as _ReactIntl from "@kne/react-intl"],antd(antd),remoteLoader(@kne/remote-loader)

```jsx
const { createIntlProvider, FormattedMessage } = _ReactIntl;
const { Select, Flex } = antd;
const { useState } = React;
const { createWithRemoteLoader } = remoteLoader;

const IntlProvider = createIntlProvider({
defaultLocale: 'zh-CN',
namespace: 'test',
messages: {
'zh-CN': {
hello: '你好,世界!',
remove: '删除'
},
'en-US': {
hello: 'Hello, world!',
remove: 'remove'
}
}
});

const BaseExample = createWithRemoteLoader({
modules: ['components-core:Global@PureGlobal']
})(({ remoteModules }) => {
const [PureGlobal] = remoteModules;
const [locale, setLocale] = useState('zh-CN');
return (
<PureGlobal
preset={{
apis: {
localeMessage: {
loader: ({ data }) => {
console.log('params', data);
const lang = {
'ja-JP': {
hello: 'こんにちは、世界!'
},
'de-DE': {
hello: 'Hallo, Welt!'
}
};

return Promise.resolve(lang[data.locale]);
}
}
}
}}>
<IntlProvider locale={locale}>
<Flex gap={10}>
<Select
placeholder="请选择语言"
value={locale}
onChange={setLocale}
options={[
{ value: 'zh-CN', label: '中文' },
{ value: 'en-US', label: 'English' },
{ value: 'ja-JP', label: '日本語' },
{ value: 'de-DE', label: 'Deutsch' }
]}
/>
<FormattedMessage id="hello" />
</Flex>
</IntlProvider>
</PureGlobal>
);
});

render(<BaseExample />);

```


### API

Expand Down
24 changes: 22 additions & 2 deletions doc/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"isFull": false,
"list": [
{
"title": "基础国际化",
"description": "使用createIntlProvider创建国际化Provider,支持语言切换",
"title": "基础语言切换",
"description": "实现中英文切换功能,通过下拉选择器实时更新页面语言",
"code": "./base.js",
"scope": [
{
Expand All @@ -16,6 +16,26 @@
"packageName": "antd"
}
]
},
{
"title": "远程加载语言",
"description": "支持API远程动态加载语言包,扩展多语言支持至日语和德语",
"code": "./remote-load-lang.js",
"scope": [
{
"name": "_ReactIntl",
"packageName": "@kne/current-lib_react-intl",
"importStatement": "import * as _ReactIntl from \"@kne/react-intl\""
},
{
"name": "antd",
"packageName": "antd"
},
{
"name": "remoteLoader",
"packageName": "@kne/remote-loader"
}
]
}
]
}
67 changes: 67 additions & 0 deletions doc/remote-load-lang.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const { createIntlProvider, FormattedMessage } = _ReactIntl;
const { Select, Flex } = antd;
const { useState } = React;
const { createWithRemoteLoader } = remoteLoader;

const IntlProvider = createIntlProvider({
defaultLocale: 'zh-CN',
namespace: 'test',
messages: {
'zh-CN': {
hello: '你好,世界!',
remove: '删除'
},
'en-US': {
hello: 'Hello, world!',
remove: 'remove'
}
}
});

const BaseExample = createWithRemoteLoader({
modules: ['components-core:Global@PureGlobal']
})(({ remoteModules }) => {
const [PureGlobal] = remoteModules;
const [locale, setLocale] = useState('zh-CN');
return (
<PureGlobal
preset={{
apis: {
localeMessage: {
loader: ({ data }) => {
console.log('params', data);
const lang = {
'ja-JP': {
hello: 'こんにちは、世界!'
},
'de-DE': {
hello: 'Hallo, Welt!'
}
};

return Promise.resolve(lang[data.locale]);
}
}
}
}}>
<IntlProvider locale={locale}>
<Flex gap={10}>
<Select
placeholder="请选择语言"
value={locale}
onChange={setLocale}
options={[
{ value: 'zh-CN', label: '中文' },
{ value: 'en-US', label: 'English' },
{ value: 'ja-JP', label: '日本語' },
{ value: 'de-DE', label: 'Deutsch' }
]}
/>
<FormattedMessage id="hello" />
</Flex>
</IntlProvider>
</PureGlobal>
);
});

render(<BaseExample />);
4 changes: 4 additions & 0 deletions doc/summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
适用于需要快速实现国际化功能的 React 应用,特别适合中大型项目的多语言支持,包括电商网站、SaaS 平台、企业后台管理系统等场景。支持组件级和全局级的语言配置,可以根据不同模块独立管理翻译内容。

技术亮点在于提供了多种创建方式,createIntlProvider 用于创建完整的国际化上下文,createWithIntlProvider 可以为单个组件注入国际化能力,createIntl 则适用于非组件环境的国际化场景。消息加载器支持单个和批量加载,命名空间机制确保不同模块的翻译内容互不干扰。

***远程加载语言包***

远程加载语言包功能支持通过 API 动态获取翻译内容,当本地缺少某语言的翻译时自动触发远程请求。提供智能缓存机制,避免重复请求相同的语言包,适用于按需加载、动态扩展语言支持、分包优化等场景。开发者可通过配置全局上下文的 localeMessage 接口,灵活集成后端翻译服务,实现运营人员动态管理翻译内容,无需重新部署应用。
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kne/react-intl",
"version": "0.1.10",
"version": "0.1.11-alpha.0",
"description": "快捷地创建国际化中需要使用到的组件",
"syntax": {
"esmodules": true
Expand Down Expand Up @@ -88,6 +88,7 @@
},
"dependencies": {
"@kne/global-context": ">=1",
"@kne/react-fetch": ">=1",
"react-intl": "^6.8.9"
}
}
53 changes: 53 additions & 0 deletions src/createWithFetchLang.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Fetch from '@kne/react-fetch';
import { useGlobalValue, usePreset } from '@kne/global-context';
import localeLoader, { messagesLoader, message } from './loader';
import { IntlProvider } from 'react-intl';
import React, { forwardRef } from 'react';

const argsParse = (...args) => {
if (typeof args[0] === 'object' && typeof args[0].defaultLocale === 'string') {
return Object.assign({}, args[0]);
}

return { defaultLocale: args[0], defaultMessage: args[1], namespace: args[2] };
};

const createWithFetchLang = (...args) => {
const { defaultLocale, defaultMessage, namespace, messages } = argsParse(...args);
defaultMessage && localeLoader(defaultLocale, defaultMessage, namespace);
messages && messagesLoader(messages, namespace);
return WrappedComponents =>
forwardRef(({ locale: propsLocale, ...props }, ref) => {
const { apis } = usePreset();
const contextLocal = useGlobalValue('locale');
const locale = propsLocale || contextLocal || defaultLocale || 'zh-CN';
const currentNamespace = namespace || 'global';
const messages = message[locale]?.[currentNamespace];
const defaultLocalMessage = message[defaultLocale || 'zh-CN']?.[currentNamespace];
if (apis?.localeMessage && !(messages && Object.keys(messages).length > 0) && defaultLocalMessage && Object.keys(defaultLocalMessage).length > 0) {
return (
<Fetch
{...Object.assign({}, apis.localeMessage, { data: { locale, namespace: currentNamespace, defaultLang: defaultLocalMessage } })}
cache="intl-fetch-lang "
render={({ data }) => {
messagesLoader({ [locale]: data }, currentNamespace);
const messages = message[locale]?.[currentNamespace];
return (
<IntlProvider messages={messages} locale={locale}>
<WrappedComponents {...props} ref={ref} />
</IntlProvider>
);
}}
/>
);
}

return (
<IntlProvider messages={messages} locale={locale}>
<WrappedComponents {...props} ref={ref} />
</IntlProvider>
);
});
};

export default createWithFetchLang;
33 changes: 6 additions & 27 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { forwardRef } from 'react';
import localeLoader, { message, messagesLoader } from './loader';
import { IntlProvider, createIntl as createIntlBase, useIntl } from 'react-intl';
import { useGlobalValue } from '@kne/global-context';
import createWithFetchLang from './createWithFetchLang';

const withIntlProvider = WrappedComponents =>
forwardRef(({ locale: propsLocale, namespace, ...props }, ref) => {
Expand All @@ -23,39 +24,17 @@ const argsParse = (...args) => {
};

export const createIntlProvider = (...args) => {
const { defaultLocale, defaultMessage, namespace, messages } = argsParse(...args);
defaultMessage && localeLoader(defaultLocale, defaultMessage, namespace);
messages && messagesLoader(messages, namespace);
const withIntlProvider = createWithFetchLang(...args);
const InnerComponent = ({ children }) => {
const intl = useIntl();
return children(intl);
};
return ({ locale: propsLocale, children }) => {
const contextLocal = useGlobalValue('locale');
const locale = propsLocale || contextLocal || defaultLocale || 'zh-CN';
return (
<IntlProvider messages={message[locale]?.[namespace || 'global']} locale={locale}>
{typeof children === 'function' ? <InnerComponent>{children}</InnerComponent> : children}
</IntlProvider>
);
};
return withIntlProvider(({ locale: propsLocale, children }) => {
return typeof children === 'function' ? <InnerComponent>{children}</InnerComponent> : children;
});
};

export const createWithIntlProvider = (...args) => {
const { defaultLocale, defaultMessage, namespace, messages } = argsParse(...args);
defaultMessage && localeLoader(defaultLocale, defaultMessage, namespace);
messages && messagesLoader(messages, namespace);
return WrappedComponents =>
forwardRef(({ locale: propsLocale, ...props }, ref) => {
const contextLocal = useGlobalValue('locale');
const locale = propsLocale || contextLocal || defaultLocale || 'zh-CN';
return (
<IntlProvider messages={message[locale]?.[namespace || 'global']} locale={locale}>
<WrappedComponents {...props} ref={ref} />
</IntlProvider>
);
});
};
export const createWithIntlProvider = createWithFetchLang;

export * from 'react-intl';

Expand Down