Sau khi thử một số giải pháp, tôi nghĩ rằng tôi đã tìm thấy một giải pháp hoạt động tốt và nên là một giải pháp thành ngữ cho React 0.14 (tức là nó không sử dụng mixin, mà là Các thành phần thứ tự cao hơn) ( chỉnh sửa : tất nhiên cũng hoàn toàn ổn với React 15! ).
Vì vậy, đây là giải pháp, bắt đầu bằng phần dưới cùng (các thành phần riêng lẻ):
Thanh phân
Điều duy nhất mà thành phần của bạn cần (theo quy ước), là một strings
đạo cụ. Nó phải là một đối tượng chứa các chuỗi khác nhau mà Thành phần của bạn cần, nhưng thực sự hình dạng của nó là tùy thuộc vào bạn.
Nó chứa các bản dịch mặc định, vì vậy bạn có thể sử dụng thành phần ở nơi khác mà không cần cung cấp bất kỳ bản dịch nào (nó sẽ hoạt động hiệu quả với ngôn ngữ mặc định, tiếng Anh trong ví dụ này)
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);
Thành phần thứ tự cao hơn
Trên đoạn mã trước, bạn có thể nhận thấy điều này ở dòng cuối cùng:
translate('MyComponent')(MyComponent)
translate
trong trường hợp này là Thành phần thứ tự cao hơn bao bọc thành phần của bạn và cung cấp một số chức năng bổ sung (cấu trúc này thay thế các hỗn hợp của các phiên bản React trước).
Đối số đầu tiên là một khóa sẽ được sử dụng để tra cứu các bản dịch trong tệp dịch (tôi đã sử dụng tên của thành phần ở đây, nhưng nó có thể là bất kỳ thứ gì). Cái thứ hai (lưu ý rằng chức năng được curryed, để cho phép trình trang trí ES7) là chính Thành phần để bọc.
Đây là mã cho thành phần dịch:
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;
};
}
Nó không phải là phép thuật: nó sẽ chỉ đọc ngôn ngữ hiện tại từ ngữ cảnh (và ngữ cảnh đó không chảy ra khắp cơ sở mã, chỉ được sử dụng ở đây trong trình bao bọc này), và sau đó lấy đối tượng chuỗi có liên quan từ các tệp được tải. Phần logic này khá đơn giản trong ví dụ này, có thể được thực hiện theo cách bạn thực sự muốn.
Phần quan trọng là nó lấy ngôn ngữ hiện tại từ ngữ cảnh và chuyển đổi ngôn ngữ đó thành chuỗi, với khóa được cung cấp.
Ở trên cùng của hệ thống phân cấp
Trên thành phần gốc, bạn chỉ cần đặt ngôn ngữ hiện tại từ trạng thái hiện tại của mình. Ví dụ sau đây đang sử dụng Redux như một triển khai giống như Flux, nhưng nó có thể dễ dàng được chuyển đổi bằng cách sử dụng bất kỳ khuôn khổ / mẫu / thư viện nào khác.
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);
Và để kết thúc, các tệp dịch:
Tệp dịch
// 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'
}
};
các bạn nghĩ sao?
Tôi nghĩ rằng nó giải quyết được tất cả vấn đề mà tôi đang cố gắng tránh trong câu hỏi của mình: logic dịch không tràn ra toàn bộ mã nguồn, nó khá cô lập và cho phép sử dụng lại các thành phần mà không có nó.
Ví dụ: MyComponent không cần phải được bao bọc bởi translate () và có thể tách biệt, cho phép sử dụng lại nó bởi bất kỳ ai khác muốn cung cấp strings
theo cách riêng của họ.
[Chỉnh sửa: 31/03/2016]: Gần đây tôi đã làm việc trong Hội đồng hồi cứu (cho Agile Retrospectives), được xây dựng bằng React & Redux và đa ngôn ngữ. Vì khá nhiều người đã yêu cầu một ví dụ thực tế trong các bình luận, đây là:
Bạn có thể tìm thấy mã ở đây: https://github.com/antoinejaussoin/retro-board/tree/master