Setelah mencoba beberapa solusi, saya rasa saya menemukan satu yang bekerja dengan baik dan seharusnya menjadi solusi idiomatik untuk React 0.14 (yaitu tidak menggunakan mixin, tetapi Komponen Orde Tinggi) ( edit : juga baik-baik saja dengan React 15 tentunya! ).
Jadi inilah solusinya, dimulai dari bawah (komponen individu):
Komponen
Satu-satunya hal yang dibutuhkan komponen Anda (menurut konvensi), adalah strings
props. Ini harus berupa objek yang berisi berbagai string yang dibutuhkan Komponen Anda, tetapi sebenarnya bentuknya terserah Anda.
Itu memang berisi terjemahan default, jadi Anda dapat menggunakan komponen di tempat lain tanpa perlu memberikan terjemahan apa pun (ini akan berfungsi di luar kotak dengan bahasa default, bahasa Inggris dalam contoh ini)
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);
Komponen Tingkat Tinggi
Pada cuplikan sebelumnya, Anda mungkin telah memperhatikan ini di baris terakhir:
translate('MyComponent')(MyComponent)
translate
dalam hal ini adalah Higher Order Component yang membungkus komponen Anda, dan menyediakan beberapa fungsionalitas tambahan (konstruksi ini menggantikan mixin versi React sebelumnya).
Argumen pertama adalah kunci yang akan digunakan untuk mencari terjemahan dalam file terjemahan (Saya menggunakan nama komponen di sini, tetapi bisa jadi apa saja). Yang kedua (perhatikan bahwa fungsinya di-curry, untuk memungkinkan dekorator ES7) adalah Komponen itu sendiri untuk dibungkus.
Berikut kode untuk komponen terjemahan:
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;
};
}
Ini bukan sihir: ini hanya akan membaca bahasa saat ini dari konteks (dan konteks itu tidak tersebar di seluruh basis kode, hanya digunakan di sini di pembungkus ini), dan kemudian mendapatkan objek string yang relevan dari file yang dimuat. Potongan logika ini cukup naif dalam contoh ini, dapat dilakukan sesuai keinginan Anda.
Bagian penting adalah mengambil bahasa saat ini dari konteks dan mengubahnya menjadi string, mengingat kunci yang disediakan.
Di bagian paling atas hierarki
Pada komponen root, Anda hanya perlu menyetel bahasa saat ini dari status Anda saat ini. Contoh berikut menggunakan Redux sebagai implementasi seperti Flux, tetapi dapat dengan mudah dikonversi menggunakan kerangka / pola / pustaka lainnya.
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);
Dan untuk menyelesaikan, file terjemahan:
File Terjemahan
// 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'
}
};
apa yang kalian pikirkan?
Saya pikir ini memecahkan semua masalah yang saya coba hindari dalam pertanyaan saya: logika terjemahan tidak berdarah di seluruh kode sumber, itu cukup terisolasi dan memungkinkan menggunakan kembali komponen tanpa itu.
Misalnya, MyComponent tidak perlu dibungkus oleh translate () dan dapat dipisahkan, memungkinkannya digunakan kembali oleh orang lain yang ingin menyediakan strings
dengan caranya sendiri.
[Edit: 31/03/2016]: Saya baru-baru ini bekerja di Retrospective Board (untuk Agile Retrospectives), dibangun dengan React & Redux, dan multibahasa. Karena cukup banyak orang yang menanyakan contoh kehidupan nyata di komentar, ini dia:
Anda dapat menemukan kodenya di sini: https://github.com/antoinejaussoin/retro-board/tree/master