我正在为I18N编写自己的组件。它称为翻译,并连接到我的翻译的Redux Store。
我知道那里有I18N库,但我想避免HOC,因为这很难为应用程序编写测试。
这就是它(我正在使用Typescript(:
import * as React from 'react'
import { connect } from 'react-redux'
import IStoreState from '../../store/IStoreState'
import { LocalizationData } from '../../apiTypes/localizationData'
import { Translation } from '../../apiTypes/translation'
interface IProps {
localizationData: LocalizationData | null
context: string
options?: Translation
fallback?: string
}
class Translate extends React.Component<IProps, {}> {
public render() {
const { localizationData, context, options, fallback } = this.props
return <span>{localizationData && this.translate(context, options, fallback)}</span>
}
public translate = (context: string, options?: Translation, fallback?: string): string => {
const { localizationData } = this.props
if (localizationData) {
let res: string = localizationData.translations![context]
if (options && res && res) {
// replace optional strings
for (const key in options) {
if (options.hasOwnProperty(key)) {
res = res.replace(`%${key}`, options[key] + '')
}
}
}
// fallback to fallback string OR last segment of translation key
if (!res) {
res = fallback || context.substr(context.lastIndexOf('.') + 1)
}
return res
}
return ''
}
}
function mapStateToProps(state: IStoreState) {
return {
localizationData: state.localizationData,
}
}
export default connect(mapStateToProps)(Translate)
它是这样使用的:
import './components/Translate'
public render() {
return (
<div>
<Translate context="page.title" />
</div>
);
}
这可以正常工作,但我也希望能够将其用作函数,以便能够做以下操作:
public render() {
return (
<div>
<img alt={t('image.title')}/>
</div>
);
}
我该怎么做?
我看到的两个选项:
- 将
<Translate />
更改为函数无状态组件。然后,返回字符串而不是跨度。
FSC翻译:
import translate from '../../services/translate';
const Translate = props => {
const { localizationData, context, options, fallback } = props;
return localizationData && translate(context, options, fallback)
};
function mapStateToProps(state: IStoreState) {
return {
localizationData: state.localizationData,
}
}
export default connect(mapStateToProps)(Translate)
这将使您的用法更改为:
import './components/Translate'
public render() {
return (
<div>
<span><Translate context="page.title" /></span>
</div>
);
}
,但它还允许您将组件称为返回字符串的函数:
public render() {
return (
<div>
<img alt={Translate({ context: 'image.title' })}/>
</div>
);
}
- 甚至更好,将
translate
功能从组件中抽象出来,然后将其存储在可以在任何地方使用的单独文件中。
然后 <Translate />
变为:
import * as React from 'react'
import { connect } from 'react-redux'
import IStoreState from '../../store/IStoreState'
import { LocalizationData } from '../../apiTypes/localizationData'
import { Translation } from '../../apiTypes/translation'
import translate from '../../services/translate';
interface IProps {
localizationData: LocalizationData | null
context: string
options?: Translation
fallback?: string
}
class Translate extends React.Component<IProps, {}> {
public render() {
const { localizationData, context, options, fallback } = this.props
return <span>{localizationData && translate(context, options, fallback, localizationData)}</span>
}
function mapStateToProps(state: IStoreState) {
return {
localizationData: state.localizationData,
}
}
export default connect(mapStateToProps)(Translate)
translate.js
const translate = (context: string, options?: Translation, fallback?: string, localizationData: object): string => {
if (localizationData) {
let res: string = localizationData.translations![context]
if (options && res && res) {
// replace optional strings
for (const key in options) {
if (options.hasOwnProperty(key)) {
res = res.replace(`%${key}`, options[key] + '')
}
}
}
// fallback to fallback string OR last segment of translation key
if (!res) {
res = fallback || context.substr(context.lastIndexOf('.') + 1)
}
return res
}
return ''
}
export default translate;