React/Redux和多语言(国际化)应用程序 – 架构
我正在构建一个应用程序,需要有多种语言和区域设置。
我的问题不是纯粹的技术,而是关于建筑,以及人们实际在生产中使用的模式来解决这个问题。 这里是我的要求(他们真的是“标准”): >用户可以选择语言(平凡) 下面是我可以想到的可能的解决方案: 每个组件单独处理翻译 这意味着每个组件都有例如一组en.json,fr.json等文件以及翻译的字符串。以及帮助函数,帮助读取取决于所选语言的值。 > Pro:更尊重React的理念,每个组件都是“独立” 每个组件通过道具接收翻译 所以他们不知道当前的语言,他们只是把字符串列表作为道具,碰巧匹配当前语言 > Pro:因为那些字符串来自“顶部”,所以它们可以集中在某个地方 你绕过道具有点,可能使用context东西传递当前语言 > Pro:它大部分是透明的,不必通过道具通过当前语言和/或翻译所有的时间 如果你有其他想法,请说! 你怎么做呢?
在尝试了相当多的解决方案后,我想我发现一个工作良好,应该是React 0.14的一个惯用的解决方案(即它不使用mixins,但高阶组件)(编辑:也完全精细React 15当然! )。
所以这里的解决方案,从底部开始(单个组件): 组件 你的组件唯一需要的(按照惯例),是一个字符串道具。 它包含默认翻译,所以你可以使用其他地方的组件,而不需要提供任何翻译(它将使用默认语言,在这个例子中的英语框) import { default as React,PropTypes } from 'react'; import translate from './translate'; class MyComponent extends React.Component { render() { return ( <div> { this.props.strings.someTranslatedText } </div> ); } } MyComponent.propTypes = { strings: PropTypes.object }; MyComponent.defaultProps = { strings: { someTranslatedText: 'Hello World' } }; export default translate('MyComponent')(MyComponent); 高阶组件 在上一个片段中,您可能已经在最后一行注意到了这一点: 在这种情况下,translate是一个高阶组件,它包装你的组件,并提供一些额外的功能(这个结构取代了以前的React版本的混合)。 第一个参数是一个键,用于查找翻译文件中的翻译(我在这里使用了组件的名称,但它可以是任何东西)。第二个(注意函数是curryed,允许ES7装饰器)是组件自身要包装。 这里是translate组件的代码: import { default as React } from 'react'; import en from '../i18n/en'; import fr from '../i18n/fr'; const languages = { en,fr }; export default function translate(key) { return Component => { class TranslationComponent extends React.Component { render() { console.log('current language: ',this.context.currentLanguage); var strings = languages[this.context.currentLanguage][key]; return <Component {...this.props} {...this.state} strings={strings} />; } } TranslationComponent.contextTypes = { currentLanguage: React.PropTypes.string }; return TranslationComponent; }; } 这不是魔术:它只是从上下文中读取当前语言(并且上下文不会在整个代码库中流出,只是在这个包装器中使用),然后从加载的文件中获取相关的字符串对象。这个逻辑在这个例子中是相当朴素的,可以按照你想要的方式做。 重要的是,它从上下文中获取当前语言,并将其转换为字符串,给定所提供的键。 在层次结构的最顶端 在根组件上,您只需要从当前状态设置当前语言。以下示例使用Redux作为Flux类实现,但它可以很容易地使用任何其他框架/模式/库进行转换。 import { default as React,PropTypes } from 'react'; import Menu from '../components/Menu'; import { connect } from 'react-redux'; import { changeLanguage } from '../state/lang'; class App extends React.Component { render() { return ( <div> <Menu onLanguageChange={this.props.changeLanguage}/> <div className=""> {this.props.children} </div> </div> ); } getChildContext() { return { currentLanguage: this.props.currentLanguage }; } } App.propTypes = { children: PropTypes.object.isRequired,}; App.childContextTypes = { currentLanguage: PropTypes.string.isRequired }; function select(state){ return {user: state.auth.user,currentLanguage: state.lang.current}; } function mapDispatchToProps(dispatch){ return { changeLanguage: (lang) => dispatch(changeLanguage(lang)) }; } export default connect(select,mapDispatchToProps)(App); 并完成,翻译文件: 翻译文件 // en.js export default { MyComponent: { someTranslatedText: 'Hello World' },SomeOtherComponent: { foo: 'bar' } }; // fr.js export default { MyComponent: { someTranslatedText: 'Salut le monde' },SomeOtherComponent: { foo: 'bar mais en fran?ais' } }; 你们有什么感想? 我认为是解决所有的问题,我试图避免在我的问题:翻译逻辑不会泄漏所有的源代码,它是相当孤立,允许重复使用组件没有它。 例如,MyComponent不需要被translate()包装,并且可以是单独的,允许任何想要以自己的意思提供字符串的人重用它。 [编辑:31/03/2016]:我最近在一个回顾董事会(敏捷回顾),用React& Redux,并且是多语言的。 你可以在这里找到代码:https://github.com/antoinejaussoin/retro-board/tree/master (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |