我在我们的代码库中定义了这个enum
。
enum EventDesc {
EVENT1 = 'event 1',
EVENT2 = 'event 2',
EVENT3 = 'event 3'
}
EVENT1
,EVENT2
,EVENT3
是在后端定义的事件类型。 event 1
,event 2
,event 3
是在UI上呈现的事件描述,由于某种原因,它们未在后端定义。我使用enum
在此处进行映射并获取相应的事件描述。
但是,现在我们支持使用react-i18next
进行国际化,这意味着必须将描述翻译成多种语言。换句话说,仅使用英语就不能像这样对它们进行硬编码。
我们当前注入翻译文本的方法是,我们为我们关心的每种语言定义了一个json文件,并且将它们与react-i18next
一起使用
import {useTranslation} from 'react-i18next';
export const Page = () => {
const {i: i18n } = useTranslation()
return (
<div>{i18n("siteTitle")}</div>
)
}
因此,在获取事件描述之前,只需查找enum
中的键,例如EventDesc[eventType]
。现在显然,它不适用于react-i18next
。我想知道是否有一种方法可以使用泛型来参数化枚举的值,以便我们可以执行类似EventDesc<'en'>[eventType]
或EventDesc<'jp'>[eventType]
的操作。但是后来我意识到,即使这样做,它也可能不起作用,因为使用enum
时,我们总是在编译时定义事件描述,而react-i18next
只会在json
文件中提取翻译文本。运行时。
是否有比使用enum
存储事件描述数据更好的选择?
答案 0 :(得分:0)
使用这种方法,您可以强制维护翻译-矩阵中缺少的翻译显示为针对GlobalDictionary实例的编译器错误。
全局字典可以保存在单个const中,但是我已经展示了如何分隔翻译-例如将它们保存在单独的文件中。
在VSCode中,将该文件另存为.ts,然后尝试添加事件或语言,并按照编译器错误进行操作,直到翻译再次完成。
namespace Internationalization {
type Event = 'event 1' | 'event 2' | 'event 3';
type Language = 'en' | 'jp' | 'fr'
type Translation<L extends Language> = {
[K in Event]: string
}
type GlobalDictionary = {
[L in Language]: Translation<L>
}
const frenchDictionary: Translation<'fr'> = {
"event 1": 'hoh',
"event 2": 'hi',
"event 3": 'hoh',
}
const babel: GlobalDictionary = {
en: {
"event 1": 'yo',
"event 2": 'hi',
"event 3": 'ug',
},
jp: {
"event 1": 'um',
"event 2": 'er',
"event 3": 'ah',
},
fr: frenchDictionary
}
}
答案 1 :(得分:0)
在我看来,尝试参数化枚举不是在 Angular 或 React 中工作的方式。
大多数情况下,我们希望将枚举显示为 html 中的 select DOM 元素,但预计单词会被翻译。
这是一种仅以英文显示性别枚举作为选择元素的方法,根本没有翻译。
What user sees
import logo from './logo.svg';
import './App.css';
import React from 'react';
function getLengthEnum(ENUMERATION:any):number{
let l_items : any[] = Object.values(ENUMERATION).filter((item) => !isNaN(Number(item)));
return l_items.length;
}
enum Gender{
'None',
'Male',
'Female'
}
export interface MyAplicacionState {
i_genderSelected : number
}
class MyAplicacion extends React.Component<{},MyAplicacionState> {
private li_indexesGenders : number[];
constructor() {
super({});
let i_numGenders : number = getLengthEnum(Gender);
this.li_indexesGenders = Array.from(Array(i_numGenders).keys());//[...Array(i_numGenders).keys()];
this.handleChangeGender = this.handleChangeGender.bind(this);
this.state = {
i_genderSelected : 0
};
}
handleChangeGender(event:any) : void {
this.setState({i_genderSelected: event.target.value});
}
render(){
const listOptionsGender = this.li_indexesGenders.map((i_index:number) =>
<option value={i_index}>{Gender[i_index]}</option>
);
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<select value={this.state.i_genderSelected} onChange={this.handleChangeGender}>
{listOptionsGender}
</select>
</header>
</div>
);
}
}
export default MyAplicacion;
这是一种使用 react-i18next 将性别枚举显示为选择元素的方法。
What user sees
import logo from './logo.svg';
import './App.css';
import React from 'react';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const resTrans = {
de: {
translation: {
'None': 'Keine',
'Male': 'Männlich',
'Female': 'Weiblich'
}
},
fr: {
translation: {
'None': 'Aucun',
'Male': 'Homme',
'Female': 'Femme'
}
}
};
i18n.use(initReactI18next).init({
resources: resTrans,
lng: 'de',
fallbackLng: 'de',
interpolation: {
escapeValue: false
}
});
function getLengthEnum(ENUMERATION:any):number{
let l_items : any[] = Object.values(ENUMERATION).filter((item) => !isNaN(Number(item)));
return l_items.length;
}
enum Gender{
'None',
'Male',
'Female'
}
export interface MyAplicacionState {
i_genderSelected : number,
i_langSelected : number,
ls_gendersTranslated : string[]
}
class MyAplicacion extends React.Component<{},MyAplicacionState> {
private li_indexesGenders : number[];
constructor() {
super({});
let i_numGenders : number = getLengthEnum(Gender);
this.li_indexesGenders = Array.from(Array(i_numGenders).keys());//[...Array(i_numGenders).keys()];
this.handleChangeGender = this.handleChangeGender.bind(this);
this.handleChangeLang = this.handleChangeLang.bind(this);
this.getListGendersTranslated = this.getListGendersTranslated.bind(this);
this.state = {
i_genderSelected : 0,
i_langSelected : 0,
ls_gendersTranslated : this.getListGendersTranslated()
};
}
handleChangeGender(event:any) : void {
this.setState({i_genderSelected: event.target.value});
}
handleChangeLang(event:any) : void {
let i_indexLang : number = parseInt(event.target.value);
let s_lang : string = 'de';
if(i_indexLang===1)s_lang = 'fr';
i18n.changeLanguage(s_lang);
this.setState({i_langSelected: i_indexLang, ls_gendersTranslated : this.getListGendersTranslated()});
}
//from enum list to string list
getListGendersTranslated() : string[]{
let ls_gendersTranslated1 : string[] = [];
this.li_indexesGenders.forEach((i_index : number)=>{
ls_gendersTranslated1.push(i18n.t(Gender[i_index]));
});
return ls_gendersTranslated1;
}
render(){
const listOptionsGender = this.li_indexesGenders.map((i_index:number) =>
<option value={i_index}>{this.state.ls_gendersTranslated[i_index]}</option>
);
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<select value={this.state.i_genderSelected} onChange={this.handleChangeGender}>
{listOptionsGender}
</select>
<select value={this.state.i_langSelected} onChange={this.handleChangeLang}>
<option value={0}>Deutsche</option>
<option value={1}>Française</option>
</select>
</header>
</div>
);
}
}
export default MyAplicacion;
ls_gendersTranslated
是所选语言的性别(字符串)列表。
ls_gendersTranslated
位于 state 内部,因此只要所选语言发生变化,它就会发生变化。
使用 li_indexesGenders
和 getListGendersTranslated
您可以将枚举显示为选择。
resTrans
、getLengthEnum
和 Gender
枚举应该在其他 ts 和 json 文件中。
对不起,这个奇怪的符号。