꽤 많은 솔루션을 시도한 후 잘 작동하고 React 0.14에 대한 관용적 솔루션이어야한다고 생각합니다 (즉, mixin을 사용하지 않지만 고차 구성 요소를 사용합니다) ( 편집 : 물론 React 15에서도 완벽하게 괜찮습니다! ).
따라서 여기에 솔루션은 하단 (개별 구성 요소)부터 시작됩니다.
구성 요소
컴포넌트가 (관습 적으로) 필요로하는 유일한 것은 strings
props입니다. 컴포넌트에 필요한 다양한 문자열을 포함하는 객체 여야하지만 실제로 모양은 사용자에게 달려 있습니다.
기본 번역이 포함되어 있으므로 번역을 제공 할 필요없이 다른 곳에서 구성 요소를 사용할 수 있습니다 (이 예에서는 기본 언어 인 영어로 즉시 작동 함).
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('MyComponent')(MyComponent)
translate
이 경우 컴포넌트를 래핑하고 몇 가지 추가 기능을 제공하는 Higher Order Component입니다 (이 구조는 이전 버전의 React 믹스 인을 대체합니다).
첫 번째 인수는 번역 파일에서 번역을 조회하는 데 사용되는 키입니다 (여기서는 구성 요소의 이름을 사용했지만 어떤 것이 든 가능). 두 번째 (ES7 데코레이터를 허용하기 위해 함수가 커리에 있음에 유의)는 랩핑 할 컴포넌트 자체입니다.
번역 구성 요소의 코드는 다음과 같습니다.
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 ()에 의해 래핑 될 필요가 없으며 분리 될 수 있으므로 strings
자신의 수단으로 를 제공하려는 다른 사람이 재사용 할 수 있습니다 .
[편집 : 2016 년 3 월 31 일] : 최근 React & Redux로 구축 된 Retrospective Board (Agile Retrospectives 용)에서 작업했으며 다국어를 사용합니다. 많은 사람들이 댓글에서 실제 사례를 요청했기 때문에 다음과 같습니다.
여기에서 코드를 찾을 수 있습니다 : https://github.com/antoinejaussoin/retro-board/tree/master