框架使用的是umi 搭建的所以用的umi国际化配置(我的都是TS)
npm install react-i18next i18next --save
// 或者
yarn add react-i18next i18next //推荐
getLocale 获取
setLocale 设置
第一步在app.tsx 同级目录新建locales文件,在locales文件下新建zh-CH.ts,en-US.ts,i18.ts
zh-CH.ts
export default {
'zh-CN': '中文',
'en-US': 'English',
language: '语言',
mix: '混合菜单布局',
side: '侧边菜单布局',
top: '顶部菜单布局',
};
en-US.ts
export default {
'zh-CN': 'Chinese',
'en-US': 'English',
language: 'Language',
mix: '混合菜单布局',
side: '侧边菜单布局',
top: '顶部菜单布局',
};
i18.ts
//i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import zh_CNCommon from './zh-CN';
import en_CNCommon from './en-US';
import { getLanguage } from '@/components/Language/index';
const resources = {
en: {
translation: zh_CNCommon,
},
zh: {
translation: en_CNCommon,
},
};
i18n.use(initReactI18next).init({
resources,
// 默认语言 zh/en 中文/英文
lng: getLanguage() || 'CN', //当前语音 默认CN
interpolation: {
escapeValue: false,
},
});
export default i18n;
app.tsx //引入文件
import '@/locales/i18n';
以上为配置,想要实现切换还需要getLanguage()事件
在components下新建Language文件,Language中新建index.tsx,Language.stories.tsx,useLanguageService.ts,
useLanguageService.ts //代码
import { setLocale } from 'umi';
import { useMount } from 'ahooks';
import { IProps } from '.';
export default function useLanguageService(props: IProps) {
const { systemLanguages } = props;
const browserLanguage = (navigator.language || navigator.browserLanguage)
?.toLowerCase()
.split('-')[0];
/**
* 优先使用浏览器语言
*/
useMount(() => {
const systemBrowserLanguage = systemLanguages.find(
(item) => item.lang?.toLowerCase().indexOf(browserLanguage) >= 0,
);
if (systemLanguages && systemBrowserLanguage) {
setLocale(systemBrowserLanguage.lang, false);
}
});
return {};
}
Language.stories.tsx
import React from 'react';
import { Meta } from '@storybook/react';
import Language from './index';
export default {
title: 'MSO/Language',
component: Language,
parameters: {
previewTabs: {
canvas: {
hidden: true,
},
},
viewMode: 'docs',
},
} as Meta;
export const Defalut = (args) => (
<div style={{ width: '100px' }}>
<Language {...args} />
</div>
);
index.tsx,
import TextIcon from '@/components/TextIcon';
import Icon from '@ant-design/icons';
import { Dropdown, Menu } from 'antd';
import 'antd/dist/antd.css';
import { DropDownProps } from 'antd/lib/dropdown/index';
import * as React from 'react';
import styled from 'styled-components';
import { getLocale, setLocale } from 'umi';
import locale from '@/assets/images/locale.png';
import useLanguageService from './useLanguageService';
export enum LauguageEnum {
English = 'en-US',
Chinese = 'zh-CN',
}
export enum LanguageIconEnum {
English = 'US',
Chinese = 'CN',
}
export type LanguageData = {
lang: LauguageEnum | string;
/** icon为该语种的缩写, 长度最长为两个字符 */
icon: LanguageIconEnum | string;
};
export type IFormatMessage = (
key: string,
attr?: Record<string, any>,
) => string;
export type IProps = {
/**多语言翻译函数, 必传 */
formatMessage: IFormatMessage;
/** 多语言数组
* 不传默认显示中英两种语种
*/
systemLanguages?: LanguageData[];
} & Omit<DropDownProps, 'overlay'>;
export const DropdownWrapper = styled(Dropdown)`
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
`;
export const MenuItemWrapper = styled(Menu.Item)<{ isSelected: boolean }>`
min-width: 124px;
color: ${(props) =>
props.isSelected ? props.theme['com-language-highlight-color'] : ''};
background-color: ${(props) =>
props.isSelected ? props.theme['com-language-highlight-bg-color'] : ''};
display: flex;
align-items: center;
img {
height: 12px;
margin-right: 8px;
}
`;
const LanguageIcon = () => (
<img
style={{ width: '20px', height: '20px', marginRight: '3px' }}
src={locale}
alt=""
/>
);
const onSetLocale = (val, bol) => {
setLocale(val, bol);
getLanguage();
};
export const getLanguage = () => {
return getLocale().split('-')[1];
};
export const MedalsoftLanguage = (props: IProps) => {
const { formatMessage } = props;
const {} = useLanguageService(props);
return props.systemLanguages ? (
<DropdownWrapper
{...props}
trigger={['click']}
overlay={
<Menu>
{props.systemLanguages?.map((languageData: LanguageData) => (
<MenuItemWrapper
isSelected={languageData.lang === getLocale()}
onClick={() => onSetLocale(languageData.lang, false)}
key={languageData.lang}
>
<TextIcon
text={languageData.icon?.slice(0, 2)}
isSelected={languageData.lang === getLocale()}
/>
<span>{formatMessage(languageData.lang)}</span>
</MenuItemWrapper>
))}
</Menu>
}
>
<div>
<Icon component={LanguageIcon}></Icon>
<span>{getLocale().split('-')[1]}</span>
</div>
</DropdownWrapper>
) : null;
};
const defaultProps: IProps = {
formatMessage: (i) => i,
placement: 'bottomLeft',
systemLanguages: [
{ lang: LauguageEnum.Chinese, icon: LanguageIconEnum.Chinese },
{ lang: LauguageEnum.English, icon: LanguageIconEnum.English },
],
};
MedalsoftLanguage.defaultProps = defaultProps;
export default { MedalsoftLanguage, getLanguage };
//MedalsoftLanguage 显示在页面上DOM
//getLanguage 当前语言
应用
import { useIntl } from 'umi';
const intl = useIntl();
const t = (id) => intl.formatMessage({ id });// 为什么不要直接使用 formatMessage 这个语法糖?
// 虽然 formatMessage 使用起来会非常方便,但是它脱离了 react 的生命周期,最严重的问题就是切换语言时无法触发 dom 重新渲染。为了解决这个问题,我们切换语言时会刷新一下浏览器,用户体验很差,所以推荐大家使用 useIntl 或者 injectIntl,可以实现同样的功能。
import React from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next';
import { useIntl } from 'umi'; //国际化
import {
Button,
Table,
Space,
Form,
Row,
Col,
DatePicker,
Select,
Input,
} from 'antd';
import { list } from './dataList';
import './style.less';
import useService from './items';
import {
ContainerDiv,
WrapperDiv,
SearchDiv,
TableWrapDiv,
TableTopDiv,
TableTitleDiv,
BreadcrumbDiv,
ButtonDiv,
} from '@/assets/style/bdreport';
import { Breadcrumb } from 'antd';
export default (props: any) => {
const columns: any = [
{
title: '项目名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
},
{
title: '创建人',
dataIndex: 'created',
key: 'created',
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'time',
key: 'time',
ellipsis: true,
},
{
title: '状态',
dataIndex: 'type',
key: 'type',
render: (text) => (
<span>
{/* 0 已发布,1 待审核,2 已退回*/}
{text == '0' ? '已发布' : text == '1' ? '待审核' : '已退回'}
</span>
),
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
align: 'center',
width: 250,
render: () => (
<Space size="middle">
<a className="see border_bottom">通过</a>
<a className="close border_bottom">退回</a>
<a className="see border_bottom">查看</a>
<a className="close border_bottom">关闭</a>
<a className="codeWord border_bottom">口令集</a>
</Space>
),
},
];
// 设置奇偶行颜色
const setRowClassName = (record, index) => {
let rowColor = index % 2 === 0 ? '' : 'even'; //判断单双行,赋予不同样式
return rowColor;
};
const layout: any = {
requiredMark: true,
labelCol: { flex: '80px' },
};
const { form, formSearch, onChange, onOk } = useService(props);
const intl = useIntl();
const t = (id) => intl.formatMessage({ id });
return (
<ContainerDiv>
<BreadcrumbDiv separator=">">
<Breadcrumb.Item>所有项目</Breadcrumb.Item>
</BreadcrumbDiv>
<WrapperDiv>
<div>{t('language')}</div>
<SearchDiv>
<Form form={form} {...layout}>
<Row gutter={24}>
{/* <Col span={22}>
<Row gutter={24}> */}
<Col xs={24} sm={24} md={24} lg={8} xl={8}>
<Form.Item label="创建时间">
<DatePicker
onChange={onChange}
onOk={onOk}
showTime
placeholder="请选择创建时间"
/>
</Form.Item>
</Col>
<Col xs={24} sm={24} md={24} lg={8} xl={8}>
<Form.Item label="项目名称">
<Select placeholder="请输入项目名称"></Select>
</Form.Item>
</Col>
<Col xs={24} sm={24} md={24} lg={8} xl={8}>
<Form.Item label="状态">
<Select placeholder="请选择状态"></Select>
</Form.Item>
</Col>
<Col xs={24} sm={24} md={24} lg={8} xl={8}>
<Form.Item label="关键字">
<Input placeholder="请输入关键字" />
</Form.Item>
</Col>
{/* </Row>
</Col> */}
<Col
xs={24}
sm={24}
md={24}
lg={16}
xl={16}
style={{
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'flex-end',
}}
>
<Button
type="primary"
htmlType="submit"
style={{ marginBottom: 24 }}
onClick={formSearch}
>
搜索
</Button>
{/* <Button style={{ marginBottom: 24 }} className="reset">
重置
</Button> */}
</Col>
</Row>
</Form>
</SearchDiv>
<TableWrapDiv>
<TableTopDiv>
<TableTitleDiv>
<span style={{ verticalAlign: 'middle', paddingRight: 12 }}>
项目列表
</span>
</TableTitleDiv>
<ButtonDiv>
<Button icon={<PlusOutlined />}>新建</Button>
</ButtonDiv>
</TableTopDiv>
<div>
<Table
rowKey={(record) => `${record.id}${Math.random()}`}
columns={columns}
dataSource={list}
rowClassName={setRowClassName}
></Table>
</div>
</TableWrapDiv>
</WrapperDiv>
</ContainerDiv>
);
};