Browse Source

完善RForm,增加i18n国际化渲染

main
dark 2 weeks ago
parent
commit
e1a30e25ec
  1. 19
      src/components/r-form/index.tsx
  2. 24
      src/components/r-form/utils/index.tsx
  3. 89
      src/i18n.ts
  4. 6
      src/locales/lang/zh-CN.ts
  5. 3
      src/types/r-form/model.d.ts
  6. 2
      src/utils/index.ts

19
src/components/r-form/index.tsx

@ -14,6 +14,7 @@ import { useApiContext } from '@/context.ts'
import { useDeepCompareEffect } from 'react-use' import { useDeepCompareEffect } from 'react-use'
import { RFormTypes } from '@/types/r-form/model' import { RFormTypes } from '@/types/r-form/model'
import { ProCoreActionType } from '@ant-design/pro-utils/es/typing' import { ProCoreActionType } from '@ant-design/pro-utils/es/typing'
import { getI18nTitle } from '@/i18n.ts'
export interface RFormProps { export interface RFormProps {
@ -66,7 +67,7 @@ const RForm = (
useDeepCompareEffect(() => { useDeepCompareEffect(() => {
let res = transformAntdTableProColumns(curdModal?.columns || [], propColumns)
let res = transformAntdTableProColumns(curdModal?.columns || [], propColumns, curdModal?.config?.i18n)
if (resolveColumns) { if (resolveColumns) {
res = resolveColumns(res) res = resolveColumns(res)
} }
@ -101,7 +102,7 @@ const RForm = (
formItemProps: { hidden: true } formItemProps: { hidden: true }
} ].concat(res as any).concat([ } ].concat(res as any).concat([
{ {
title: '操作',
title: getI18nTitle(curdModal?.config?.i18n, { dataIndex: 'option', title: '操作' },),
dataIndex: 'option', dataIndex: 'option',
valueType: 'option', valueType: 'option',
fixed: 'right', fixed: 'right',
@ -114,7 +115,7 @@ const RForm = (
} as any } as any
]) ])
setColumns(_columns) setColumns(_columns)
}, [ curdModal?.columns, propColumns, renderColumnOptions, resolveColumns, deleteModel, form, isDeleting, setOpen, ])
}, [ curdModal?.columns, curdModal?.config?.i18n, propColumns, renderColumnOptions, resolveColumns, deleteModel, form, isDeleting, setOpen, ])
useEffect(() => { useEffect(() => {
if (apiCtx.isApi && apiCtx.api) { if (apiCtx.isApi && apiCtx.api) {
@ -170,7 +171,7 @@ const RForm = (
}) })
setOpen(true) setOpen(true)
}} }}
type={'primary'}>{'添加'}</Button>
type={'primary'}>{getI18nTitle('actions.add','添加')}</Button>
</> </>
const _renderActions = () => { const _renderActions = () => {
@ -209,7 +210,7 @@ const RForm = (
placeholder: '输入关键字搜索', placeholder: '输入关键字搜索',
},*/ },*/
actions: [ actions: [
<Tooltip key={'filter'} title={'高级查询'}>
<Tooltip key={'filter'} title={getI18nTitle('actions.advanceSearch','高级查询')}>
<Badge count={getValueCount(search)}> <Badge count={getValueCount(search)}>
<Button <Button
onClick={() => { onClick={() => {
@ -277,7 +278,7 @@ const RForm = (
form={form} form={form}
layout={'vertical'} layout={'vertical'}
scrollToFirstError={true} scrollToFirstError={true}
title={model?.id !== 0 ? '编辑' : '添加'}
title={model?.id !== 0 ? getI18nTitle('actions.edit','编辑') : getI18nTitle('actions.add','添加')}
{...formProps as any} {...formProps as any}
open={open} open={open}
onOpenChange={(open) => { onOpenChange={(open) => {
@ -291,7 +292,7 @@ const RForm = (
columns={columns as ProFormColumnsType[]}/> columns={columns as ProFormColumnsType[]}/>
<BetaSchemaForm <BetaSchemaForm
{...curdModal?.form} {...curdModal?.form}
title={'高级查询'}
title={getI18nTitle('actions.advanceSearch','高级查询')}
grid={true} grid={true}
shouldUpdate={false} shouldUpdate={false}
width={500} width={500}
@ -313,8 +314,8 @@ const RForm = (
}} }}
submitter={{ submitter={{
searchConfig: { searchConfig: {
resetText: '清空',
submitText: '查询',
resetText: getI18nTitle('actions.clear', '清空'),
submitText: getI18nTitle('actions.search', '查询'),
}, },
onReset: () => { onReset: () => {
filterForm.resetFields() filterForm.resetFields()

24
src/components/r-form/utils/index.tsx

@ -6,6 +6,7 @@ import request from '@/request'
import { convertToBool } from '@/utils' import { convertToBool } from '@/utils'
import { has, get } from 'lodash' import { has, get } from 'lodash'
import { mapTree } from '@/utils/tree.ts' import { mapTree } from '@/utils/tree.ts'
import { getI18nTitle } from '@/i18n.ts'
const getValueType = (column: ProColumns) => { const getValueType = (column: ProColumns) => {
@ -40,7 +41,7 @@ const getComponent = (column: ProColumns) => {
} }
export const transformAntdTableProColumns = (columns: ProColumns[], overwriteColumns?: ProColumns[]) => {
export const transformAntdTableProColumns = (columns: ProColumns[], overwriteColumns?: ProColumns[], i18n?: string) => {
const overwriteKeys = [] as string[] const overwriteKeys = [] as string[]
@ -56,27 +57,40 @@ export const transformAntdTableProColumns = (columns: ProColumns[], overwriteCol
return { return {
...item, ...item,
title: getI18nTitle(i18n!, item),
request: item.request ? async (params) => { request: item.request ? async (params) => {
const { url: _url, method, params: p, fieldNames, resultPath } = item.request as unknown as RFormTypes.IRequest
const {
transform = true,
url: _url,
method,
params: p,
fieldNames,
resultPath
} = item.request as unknown as RFormTypes.IRequest
const { value, label, disabled: disabledKey, children = 'children' } = fieldNames || {} const { value, label, disabled: disabledKey, children = 'children' } = fieldNames || {}
const url = (_url.startsWith('/') || _url.startsWith('http')) ? _url : `/${_url}` const url = (_url.startsWith('/') || _url.startsWith('http')) ? _url : `/${_url}`
return request[method?.toLowerCase() || 'get'](url, { return request[method?.toLowerCase() || 'get'](url, {
...params, ...params,
...p, ...p,
}).then(res => { }).then(res => {
try { try {
const data = resultPath && has(res.data, resultPath) ? get(res.data, resultPath) : res.data const data = resultPath && has(res.data, resultPath) ? get(res.data, resultPath) : res.data
if (!transform) {
return data
}
return mapTree(data || [], (i: any) => { return mapTree(data || [], (i: any) => {
const disabled = disabledKey && has(i, disabledKey) ? get(i, disabledKey) : ('status' in i ? !convertToBool(i.status) : false) const disabled = disabledKey && has(i, disabledKey) ? get(i, disabledKey) : ('status' in i ? !convertToBool(i.status) : false)
const title = i.i18n ? getI18nTitle(i.i18n, i.label || i[label || 'name']) : i.label || i[label || 'name']
return { return {
title: i.label || i[label || 'name'],
label: i.label || i[label || 'name'],
title,
label: title,
value: i.value ?? i[value || 'id'], value: i.value ?? i[value || 'id'],
disabled, disabled,
data: i data: i
} }
}, { children }) }, { children })
} catch (e) { } catch (e) {

89
src/i18n.ts

@ -3,49 +3,72 @@ import i18n, { InitOptions, t } from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector' import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next, useTranslation, } from 'react-i18next' import { initReactI18next, useTranslation, } from 'react-i18next'
import { zh, en } from './locales' import { zh, en } from './locales'
import { ProColumns } from '@ant-design/pro-components'
const detectionOptions = { const detectionOptions = {
// 探测器的选项
order: [ 'querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag' ],
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
caches: [ 'localStorage', 'cookie' ],
excludeCacheFor: [ 'cimode' ], // 语言探测模式中排除缓存的语言
// 探测器的选项
order: [ 'querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag' ],
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
caches: [ 'localStorage', 'cookie' ],
excludeCacheFor: [ 'cimode' ], // 语言探测模式中排除缓存的语言
} }
export const initI18n = (options?: InitOptions) => { export const initI18n = (options?: InitOptions) => {
i18n.on('initialized', () => {
const currentLanguage = i18n.language
changeLanguage(currentLanguage)
})
return i18n
.use(initReactI18next)
.use(LanguageDetector)
.init({
resources: {
en: {
translation: en.default,
},
zh: {
translation: zh.default,
},
},
fallbackLng: 'zh',
debug: false,
detection: detectionOptions,
interpolation: {
escapeValue: false,
},
...options,
})
i18n.on('initialized', () => {
const currentLanguage = i18n.language
changeLanguage(currentLanguage)
})
return i18n
.use(initReactI18next)
.use(LanguageDetector)
.init({
resources: {
en: {
translation: en.default,
},
zh: {
translation: zh.default,
},
},
fallbackLng: 'zh',
debug: false,
detection: detectionOptions,
interpolation: {
escapeValue: false,
},
...options,
})
}
export function getI18nTitle(key: string, defTitle: string): string;
export function getI18nTitle(key: string, column: ProColumns): string;
export function getI18nTitle(key: string, option: any): string {
if (option.dataIndex) {
let k = `${key}.columns.${option.dataIndex}`
if (option.i18n) {
k = option.i18n
}
//如果没有key也没有option.i18n, 说明没有i18n前缀, 直接返回
if (!option.i18n && !key) {
return option.title || option.label
}
return t(k, (option.title || option.label) as string)
}
if (!key) {
return option as unknown as string
}
return t(`${key}`, option as unknown as string)
} }
export { export {
useTranslation, t
useTranslation, t
} }
export default i18n export default i18n

6
src/locales/lang/zh-CN.ts

@ -77,6 +77,12 @@ export default {
close: '关闭', close: '关闭',
copy: '复制', copy: '复制',
clickCopy: '点击复制', clickCopy: '点击复制',
resetPass: '重置密码',
save: '保存',
submit: '提交',
refresh: '刷新',
search: '查询',
advanceSearch: '高级查询',
}, },
message: { message: {
infoTitle: '提示', infoTitle: '提示',

3
src/types/r-form/model.d.ts

@ -27,6 +27,9 @@ export namespace RFormTypes {
params?: any; params?: any;
resultPath?: string; resultPath?: string;
//是否需要转换成下拉框的数据或者树形数据格式, 默认为true
transform: boolean;
fieldNames?: { fieldNames?: {
label: string; label: string;
value: string; value: string;

2
src/utils/index.ts

@ -216,3 +216,5 @@ export const genProTableColumnWidthProps = (width: string | number) => {
} }
} }
Loading…
Cancel
Save