Skip to content

Commit 0a8b379

Browse files
authored
feat(configprovider): support configProvider (#591)
* feat(configprovider): support configProvider * test(configprovider): fixed unit test
1 parent a157f87 commit 0a8b379

File tree

16 files changed

+614
-46
lines changed

16 files changed

+614
-46
lines changed

src/catalogue/components/catalogue.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Dropdown, DropdownProps, Form, Input, Tabs } from 'antd';
33
import { BlockHeader, EllipsisText } from 'dt-react-component';
44
import { IBlockHeaderProps } from 'dt-react-component/blockHeader';
55

6+
import useLocale from '../../locale/useLocale';
67
import { ITreeNode } from '../useTreeData';
78
import { CatalogIcon, CloseIcon, DragIcon, EllipsisIcon, SearchIcon } from './icon';
89
import CatalogueTree, { ICatalogueTree } from './tree';
@@ -49,12 +50,13 @@ function isTabMode<U extends Record<string, any> = {}, T extends readOnlyTab = a
4950
const Catalogue = <U extends Record<string, any> = {}, T extends readOnlyTab = any>(
5051
props: CatalogueProps<U, T>
5152
) => {
53+
const locale = useLocale('Catalogue');
5254
const {
5355
title,
5456
addonBefore = <CatalogIcon style={{ fontSize: 20 }} />,
5557
tooltip = false,
5658
showSearch = false,
57-
placeholder = '搜索目录名称',
59+
placeholder = locale.searchPlaceholder,
5860
addonAfter,
5961
edit = true,
6062
treeData,
@@ -78,7 +80,7 @@ const Catalogue = <U extends Record<string, any> = {}, T extends readOnlyTab = a
7880
<Form.Item name="catalog_input" initialValue={item?.title as string}>
7981
<Input
8082
size="small"
81-
placeholder={`请输入${title}名称`}
83+
placeholder={locale.inputPlaceholder}
8284
maxLength={100}
8385
autoFocus
8486
onFocus={() => form.setFields([{ name: 'catalog_input', errors: [] }])}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from 'react';
2+
import { render } from '@testing-library/react';
3+
import '@testing-library/jest-dom/extend-expect';
4+
5+
import enUS from '../../locale/en-US';
6+
import { LocaleContext } from '../../locale/useLocale';
7+
import zhCN from '../../locale/zh-CN';
8+
import ConfigProvider from '..';
9+
10+
describe('ConfigProvider', () => {
11+
it('renders children correctly', () => {
12+
const { getByText } = render(
13+
<ConfigProvider locale={zhCN}>
14+
<div>Test Content</div>
15+
</ConfigProvider>
16+
);
17+
expect(getByText('Test Content')).toBeInTheDocument();
18+
});
19+
20+
it('provides locale context correctly', () => {
21+
const TestComponent = () => {
22+
const { locale } = React.useContext(LocaleContext);
23+
return <div data-testid="locale-value">{locale.locale}</div>;
24+
};
25+
26+
const { getByTestId } = render(
27+
<ConfigProvider locale={zhCN}>
28+
<TestComponent />
29+
</ConfigProvider>
30+
);
31+
32+
expect(getByTestId('locale-value').textContent).toBe(zhCN.locale);
33+
});
34+
35+
it('updates context when locale changes', () => {
36+
const TestComponent = () => {
37+
const { locale } = React.useContext(LocaleContext);
38+
return <div data-testid="locale-value">{locale.locale}</div>;
39+
};
40+
41+
const { getByTestId, rerender } = render(
42+
<ConfigProvider locale={zhCN}>
43+
<TestComponent />
44+
</ConfigProvider>
45+
);
46+
47+
expect(getByTestId('locale-value').textContent).toBe(zhCN.locale);
48+
49+
// 重新渲染,使用英文语言包
50+
rerender(
51+
<ConfigProvider locale={enUS}>
52+
<TestComponent />
53+
</ConfigProvider>
54+
);
55+
56+
expect(getByTestId('locale-value').textContent).toBe(enUS.locale);
57+
});
58+
});

src/configProvider/demos/basic.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { useState } from 'react';
2+
import { Radio, Space } from 'antd';
3+
import { BlockHeader, ConfigProvider, Copy, enUS, Input, zhCN } from 'dt-react-component';
4+
5+
export default function Basic() {
6+
const [locale, setLocale] = useState(zhCN);
7+
8+
return (
9+
<Space direction="vertical" size="large">
10+
<Radio.Group
11+
value={locale.locale}
12+
onChange={(e) => setLocale(e.target.value === 'zh-CN' ? zhCN : enUS)}
13+
>
14+
<Radio.Button value="zh-CN">中文</Radio.Button>
15+
<Radio.Button value="en-US">English</Radio.Button>
16+
</Radio.Group>
17+
18+
<ConfigProvider locale={locale}>
19+
<Space direction="vertical" size="middle">
20+
<div>
21+
<h3>Copy 组件</h3>
22+
<Copy text="这是要复制的文本" />
23+
</div>
24+
<div>
25+
<h3>BlockHeader 组件</h3>
26+
<BlockHeader title="标题" defaultExpand>
27+
<p>内容区域</p>
28+
</BlockHeader>
29+
</div>
30+
<div>
31+
<h3>Input.Match 组件</h3>
32+
<Input.Match />
33+
</div>
34+
</Space>
35+
</ConfigProvider>
36+
</Space>
37+
);
38+
}

src/configProvider/demos/custom.tsx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React, { useState } from 'react';
2+
import { Radio, Space } from 'antd';
3+
import { BlockHeader, ConfigProvider, Copy, enUS, useLocale, zhCN } from 'dt-react-component';
4+
5+
// 自定义组件,使用useLocale获取当前语言环境
6+
const LocaleConsumer = () => {
7+
const copyLocale = useLocale('Copy');
8+
const blockHeaderLocale = useLocale('BlockHeader');
9+
10+
return (
11+
<div>
12+
<h4>当前语言环境</h4>
13+
<div style={{ background: '#f5f5f5', padding: '10px', borderRadius: '4px' }}>
14+
<p>
15+
<strong>Copy组件:</strong>
16+
</p>
17+
<ul>
18+
<li>copy: {copyLocale.copy}</li>
19+
<li>copied: {copyLocale.copied}</li>
20+
</ul>
21+
22+
<p>
23+
<strong>BlockHeader组件:</strong>
24+
</p>
25+
<ul>
26+
<li>expand: {blockHeaderLocale.expand}</li>
27+
<li>collapse: {blockHeaderLocale.collapse}</li>
28+
</ul>
29+
</div>
30+
</div>
31+
);
32+
};
33+
34+
export default function Custom() {
35+
// 创建自定义语言包
36+
const [customLocale, setCustomLocale] = useState({
37+
...zhCN,
38+
locale: 'custom-zh',
39+
Copy: {
40+
copy: '点击复制',
41+
copied: '已复制到剪贴板',
42+
},
43+
BlockHeader: {
44+
expand: '展开全部',
45+
collapse: '收起全部',
46+
},
47+
});
48+
49+
const [localeType, setLocaleType] = useState('custom');
50+
51+
const handleLocaleChange = (type: string) => {
52+
setLocaleType(type);
53+
if (type === 'zh-CN') {
54+
setCustomLocale(zhCN);
55+
} else if (type === 'en-US') {
56+
setCustomLocale(enUS);
57+
} else {
58+
// 恢复自定义语言包
59+
setCustomLocale({
60+
...zhCN,
61+
locale: 'custom-zh',
62+
Copy: {
63+
copy: '点击复制',
64+
copied: '已复制到剪贴板',
65+
},
66+
BlockHeader: {
67+
expand: '展开全部',
68+
collapse: '收起全部',
69+
},
70+
});
71+
}
72+
};
73+
74+
return (
75+
<Space direction="vertical" size="large" style={{ width: '100%' }}>
76+
<Radio.Group value={localeType} onChange={(e) => handleLocaleChange(e.target.value)}>
77+
<Radio.Button value="custom">自定义语言</Radio.Button>
78+
<Radio.Button value="zh-CN">默认中文</Radio.Button>
79+
<Radio.Button value="en-US">默认英文</Radio.Button>
80+
</Radio.Group>
81+
82+
<ConfigProvider locale={customLocale}>
83+
<Space direction="vertical" style={{ width: '100%' }}>
84+
<div>
85+
<h3>使用自定义语言包</h3>
86+
<Copy text="这是要复制的文本" />
87+
</div>
88+
89+
<div>
90+
<h3>BlockHeader 示例</h3>
91+
<BlockHeader title="标题" defaultExpand>
92+
<p>内容区域</p>
93+
</BlockHeader>
94+
</div>
95+
96+
<LocaleConsumer />
97+
</Space>
98+
</ConfigProvider>
99+
</Space>
100+
);
101+
}

src/configProvider/demos/nested.tsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import React, { useState } from 'react';
2+
import { Divider, Radio, Space } from 'antd';
3+
import { ConfigProvider, Copy, enUS, useLocale, zhCN } from 'dt-react-component';
4+
5+
// 自定义组件,使用useLocale获取当前语言环境
6+
const LocaleDisplay = () => {
7+
const copyLocale = useLocale('Copy');
8+
return (
9+
<div>
10+
<p>当前Copy组件的文案:</p>
11+
<ul>
12+
<li>copy: {copyLocale.copy}</li>
13+
<li>copied: {copyLocale.copied}</li>
14+
</ul>
15+
</div>
16+
);
17+
};
18+
19+
export default function Nested() {
20+
const [outerLocale, setOuterLocale] = useState(zhCN);
21+
const [innerLocale, setInnerLocale] = useState(enUS);
22+
23+
return (
24+
<Space direction="vertical" size="large" style={{ width: '100%' }}>
25+
<div>
26+
<h3>外层ConfigProvider</h3>
27+
<Radio.Group
28+
value={outerLocale.locale}
29+
onChange={(e) => setOuterLocale(e.target.value === 'zh-CN' ? zhCN : enUS)}
30+
>
31+
<Radio.Button value="zh-CN">中文</Radio.Button>
32+
<Radio.Button value="en-US">English</Radio.Button>
33+
</Radio.Group>
34+
</div>
35+
36+
<ConfigProvider locale={outerLocale}>
37+
<Space
38+
direction="vertical"
39+
style={{ width: '100%', border: '1px solid #eee', padding: '16px' }}
40+
>
41+
<div>
42+
<h4>外层ConfigProvider的组件</h4>
43+
<Copy text="这是要复制的文本" />
44+
<LocaleDisplay />
45+
</div>
46+
47+
<Divider>嵌套的ConfigProvider</Divider>
48+
49+
<div>
50+
<h4>内层ConfigProvider</h4>
51+
<Radio.Group
52+
value={innerLocale.locale}
53+
onChange={(e) =>
54+
setInnerLocale(e.target.value === 'zh-CN' ? zhCN : enUS)
55+
}
56+
>
57+
<Radio.Button value="zh-CN">中文</Radio.Button>
58+
<Radio.Button value="en-US">English</Radio.Button>
59+
</Radio.Group>
60+
61+
<ConfigProvider locale={innerLocale}>
62+
<div
63+
style={{
64+
marginTop: '16px',
65+
border: '1px dashed #ccc',
66+
padding: '16px',
67+
}}
68+
>
69+
<h4>内层ConfigProvider的组件</h4>
70+
<Copy text="这是要复制的文本" />
71+
<LocaleDisplay />
72+
</div>
73+
</ConfigProvider>
74+
</div>
75+
</Space>
76+
</ConfigProvider>
77+
78+
<div>
79+
<h3>无ConfigProvider的组件</h3>
80+
<p>当组件不在ConfigProvider内时,将使用默认的中文语言包</p>
81+
<Copy text="这是要复制的文本" />
82+
<LocaleDisplay />
83+
</div>
84+
</Space>
85+
);
86+
}

src/configProvider/index.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
title: ConfigProvider 全局化配置
3+
group: 组件
4+
toc: content
5+
demo:
6+
cols: 1
7+
---
8+
9+
# ConfigProvider 全局化配置
10+
11+
## 何时使用
12+
13+
ConfigProvider 用于全局配置组件库的默认属性,目前主要用于配置国际化文案。
14+
15+
## 代码演示
16+
17+
<code src="./demos/basic.tsx" title="基本使用" description="ConfigProvider 的基本用法,通过切换语言环境,可以看到组件的文案会随之变化。"></code>
18+
19+
<code src="./demos/nested.tsx" title="嵌套使用" description="ConfigProvider 支持嵌套使用,内层的 ConfigProvider 会覆盖外层的配置。"></code>
20+
21+
<code src="./demos/custom.tsx" title="自定义语言包" description="可以通过扩展默认语言包来创建自定义的语言配置。"></code>
22+
23+
## API
24+
25+
### ConfigProvider
26+
27+
| 参数 | 说明 | 类型 | 默认值 |
28+
| -------- | ---------- | ----------------- | ------ |
29+
| locale | 语言包配置 | [Locale](#locale) | - |
30+
| children | 子组件 | ReactNode | - |
31+
32+
### Locale
33+
34+
```typescript
35+
interface Locale {
36+
locale: string;
37+
BlockHeader: { expand: string; collapse: string };
38+
Catalogue: { searchPlaceholder: string; inputPlaceholder: string };
39+
Chat: {
40+
stopped: string;
41+
stop: string;
42+
regenerate: string;
43+
};
44+
Copy: { copied: string; copy: string };
45+
Dropdown: { selectAll: string; resetText: string; okText: string };
46+
ErrorBoundary: {
47+
please: string;
48+
get: string;
49+
refresh: string;
50+
title: string;
51+
};
52+
// ... 其他组件的文案配置
53+
}
54+
```
55+
56+
## 注意事项
57+
58+
- 组件库默认使用中文(zh-CN)语言包。
59+
- 当组件不在 ConfigProvider 内时,将使用默认的中文语言包。
60+
- 可以通过 `useLocale` hook 在组件内部获取当前的语言环境。
61+
- 自定义语言包时,可以只覆盖需要修改的部分,其他部分会使用默认语言包。

src/errorBoundary/loadError.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react';
33
import useLocale from '../locale/useLocale';
44

55
const LoadError: React.FC = function () {
6-
const locale = useLocale('LoadError');
6+
const locale = useLocale('ErrorBoundary');
77
return (
88
<div className="dtc-error" data-testid="test-error">
99
<div>

0 commit comments

Comments
 (0)