Implement react i18n-next

This commit is contained in:
Reckless_Satoshi 2022-04-01 16:41:08 -07:00
parent 2c8dfdbff5
commit 1061403487
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
10 changed files with 3400 additions and 273 deletions

View File

@ -27,7 +27,7 @@ services:
build: ./frontend
container_name: npm-dev
restart: always
command: npm run build
command: npm run dev
volumes:
- ./frontend:/usr/src/frontend

View File

@ -4273,6 +4273,19 @@
}
}
},
"html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
},
"html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"requires": {
"void-elements": "3.1.0"
}
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
@ -4296,6 +4309,40 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
},
"i18next": {
"version": "21.6.14",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.14.tgz",
"integrity": "sha512-XL6WyD+xlwQwbieXRlXhKWoLb/rkch50/rA+vl6untHnJ+aYnkQ0YDZciTWE78PPhOpbi2gR0LTJCJpiAhA+uQ==",
"requires": {
"@babel/runtime": "^7.17.2"
},
"dependencies": {
"@babel/runtime": {
"version": "7.17.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz",
"integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
}
}
},
"i18next-browser-languagedetector": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.4.tgz",
"integrity": "sha512-wukWnFeU7rKIWT66VU5i8I+3Zc4wReGcuDK2+kuFhtoxBRGWGdvYI9UQmqNL/yQH1KogWwh+xGEaIPH8V/i2Zg==",
"requires": {
"@babel/runtime": "^7.14.6"
}
},
"i18next-xhr-backend": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-3.2.2.tgz",
"integrity": "sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"image-size": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz",
@ -6355,6 +6402,16 @@
"scheduler": "^0.20.2"
}
},
"react-i18next": {
"version": "11.16.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.16.2.tgz",
"integrity": "sha512-1iuZduvARUelL5ux663FvIoDZExwFO+9QtRAAt4uvs1/aun4cUZt8XBrVg7iiDgNls9cOSORAhE7Ri5KA9RMvg==",
"requires": {
"@babel/runtime": "^7.14.5",
"html-escaper": "^2.0.2",
"html-parse-stringify": "^3.0.1"
}
},
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@ -7993,6 +8050,11 @@
"resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
"integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="
},
"void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk="
},
"walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",

View File

@ -33,8 +33,12 @@
"@mui/x-data-grid": "^5.2.2",
"country-flag-icons": "^1.4.25",
"date-fns": "^2.28.0",
"i18next": "^21.6.14",
"i18next-browser-languagedetector": "^6.1.4",
"i18next-xhr-backend": "^3.2.2",
"material-ui-image": "^3.3.2",
"react-countdown": "^2.3.2",
"react-i18next": "^11.16.2",
"react-native": "^0.66.4",
"react-native-svg": "^12.1.1",
"react-qr-code": "^2.0.3",

View File

@ -5,6 +5,9 @@ import { CssBaseline, IconButton} from "@mui/material";
import { ThemeProvider, createTheme } from '@mui/material/styles';
import UnsafeAlert from "./UnsafeAlert";
import { I18nextProvider } from "react-i18next";
import i18n from "./i18n";
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
@ -12,18 +15,16 @@ export default class App extends Component {
constructor(props) {
super(props);
this.state = {
nickname: null,
token: null,
dark: false,
lang: 'en',
}
}
setAppState=(newState)=>{
this.setState(newState)
setLang=(newLang)=>{
this.setState({lang:newLang})
}
lightTheme = createTheme({
});
lightTheme = createTheme({});
darkTheme = createTheme({
palette: {
@ -36,14 +37,16 @@ export default class App extends Component {
render() {
return (
<I18nextProvider i18n={i18n}>
<ThemeProvider theme={this.state.dark ? this.darkTheme : this.lightTheme}>
<CssBaseline/>
<IconButton sx={{position:'fixed',right:'0px'}} onClick={()=>this.setState({dark:!this.state.dark})}>
{this.state.dark ? <LightModeIcon/>:<DarkModeIcon/>}
</IconButton>
<UnsafeAlert className="unsafeAlert"/>
<HomePage setAppState={this.setAppState}/>
<HomePage changeLang={i18n.changeLanguage}/>
</ThemeProvider>
</I18nextProvider>
);
}
}

View File

@ -553,14 +553,7 @@ bottomBarDesktop =()=>{
<Grid container item xs={1}>
<Grid item xs={6}>
<Select
size = 'small'
defaultValue={1}
inputProps={{
style: {textAlign:"center"}
}}>
<MenuItem value={1}>EN</MenuItem>
</Select>
<this.LangSelect/>
</Grid>
<Grid item xs={3}>
<Tooltip enterTouchDelay="250" title="Show community and support links">
@ -587,6 +580,26 @@ bottomBarDesktop =()=>{
</Paper>
)
}
handleChangeLang=(e)=>{
this.props.changeLang(e.target.value)
}
LangSelect = () => {
return(
<Select
size = 'small'
defaultValue={'en'}
inputProps={{
style: {textAlign:"center"}
}}
onChange={this.handleChangeLang}>
<MenuItem value={'en'}>EN</MenuItem>
<MenuItem value={'es'}>ES</MenuItem>
<MenuItem value={'de'}>DE</MenuItem>
<MenuItem value={'ru'}>RU</MenuItem>
<MenuItem value={'cn'}>CN</MenuItem>
</Select>
)
}
handleClickOpenExchangeSummary = () => {
this.getInfo();
@ -770,14 +783,7 @@ bottomBarPhone =()=>{
<Grid container item xs={3.8}>
<Grid item xs={6}>
<Select
size = 'small'
defaultValue={1}
inputProps={{
style: {textAlign:"center"}
}}>
<MenuItem value={1}>EN</MenuItem>
</Select>
<this.LangSelect/>
</Grid>
<Grid item xs={3}>
<Tooltip enterTouchDelay="250" title="Show community and support links">

View File

@ -41,7 +41,7 @@ export default class HomePage extends Component {
</Switch>
</div>
<div className='bottomBar'>
<BottomBar redirectTo={this.redirectTo} {...this.state} setAppState={this.setAppState} />
<BottomBar changeLang={this.props.changeLang} redirectTo={this.redirectTo} {...this.state} setAppState={this.setAppState} />
</div>
</Router>
);

View File

@ -10,6 +10,8 @@ import RoboSatsNoTextIcon from "./icons/RoboSatsNoTextIcon"
import BoltIcon from '@mui/icons-material/Bolt';
import { withTranslation } from "react-i18next";
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
@ -27,7 +29,7 @@ function getCookie(name) {
}
const csrftoken = getCookie('csrftoken');
export default class UserGenPage extends Component {
class UserGenPage extends Component {
constructor(props) {
super(props);
this.state = {
@ -101,8 +103,7 @@ export default class UserGenPage extends Component {
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken')},
};
fetch("/api/user", requestOptions)
.then((response) => response.json())
.then((data) => console.log(data));
.then((response) => response.json());
}
handleClickNewRandomToken=()=>{
@ -150,6 +151,7 @@ export default class UserGenPage extends Component {
}
render() {
const { t } = this.props;
return (
<Grid container spacing={1}>
<Grid item>
@ -168,7 +170,7 @@ export default class UserGenPage extends Component {
</Typography>
</Grid>
<Grid item xs={12} align="center">
<Tooltip enterTouchDelay="0" title="This is your trading avatar">
<Tooltip enterTouchDelay="0" title={t("This is your trading avatar")}>
<div style={{ maxWidth: 200, maxHeight: 200 }}>
<Image className='newAvatar'
disableError='true'
@ -276,3 +278,5 @@ export default class UserGenPage extends Component {
);
}
}
export default withTranslation()(UserGenPage);

View File

@ -0,0 +1,104 @@
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
// we init with resources
resources: {
en: {
translations: {
Your_avatar: "Avatar",
"This is your trading avatar":
"This is your trading avatar",
"Plugins to detect the user language":
"Plugins to detect the user language",
"Plugins to load translations": "Plugins to load translations",
"Optionally cache the translations":
"Optionally cache the translations",
Advantages: "Advantages",
"Flexibility to use other packages": "Flexibility to use other packages"
}
},
es: {
translations: {
Your_avatar: "Avatar",
"This is your trading avatar":
"Este es tu avatar para comprar y vender",
"Plugins to detect the user language":
"ユーザー言語を検出するためのプラグイン",
"Plugins to load translations": "翻訳をロードするためのプラグイン",
"Optionally cache the translations": "必要に応じて翻訳をキャッシュする",
Advantages: "利点",
"Flexibility to use other packages": "他のパッケージを使用する柔軟性"
}
},
ru: {
translations: {
Introduction: "प्रस्तावना",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"एक अंतर्राष्ट्रीयकरण - ढांचा है जो आपके उत्पाद को वेब से मोबाइल और डेस्कटॉप पर स्थानांतरित करने का एक संपूर्ण समाधान प्रदान करता है",
"Plugins to detect the user language":
"उपयोगकर्ता भाषा का पता लगाने के लिए प्लगइन्स",
"Plugins to load translations": "अनुवाद लोड करने के लिए प्लगइन्स",
"Optionally cache the translations": "वैकल्पिक रूप से अनुवाद कैश करें",
Advantages: "लाभ",
"Flexibility to use other packages":
"अन्य पैकेजों का उपयोग करने के लिए लचीलापन"
}
},
de: {
translations: {
Introduction: "Einführung",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"ist ein Internationalisierungs-Framework, das eine Komplettlösung für die Lokalisierung Ihres Produkts vom Web auf das Handy und den Desktop bietet",
"Plugins to detect the user language":
"Plugins zur Erkennung der Benutzersprache",
"Plugins to load translations": "Plugins zum Laden von Übersetzungen",
"Optionally cache the translations":
"Optional die Übersetzungen zwischenspeichern",
Advantages: "Vorteile",
"Flexibility to use other packages":
"Flexibilität zur Verwendung anderer Pakete"
}
},
cn: {
translations: {
Introduction: "Introduction",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"est un cadre d'internationalisation qui offre une solution complète pour localiser votre produit du Web au mobile et au bureau",
"Plugins to detect the user language":
"Plugins pour détecter la langue de l'utilisateur",
"Plugins to load translations": "Plugins pour charger les traductions",
"Optionally cache the translations":
"Cachez éventuellement les traductions",
Advantages: "Les avantages",
"Flexibility to use other packages":
"Flexibilité d'utiliser d'autres packages"
}
}
},
fallbackLng: "en",
debug: true,
// have a common namespace used around the full app
ns: ["translations"],
defaultNS: "translations",
keySeparator: false, // we use content as keys
interpolation: {
escapeValue: false,
formatSeparator: ","
},
react: {
wait: true
}
});
export default i18n;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff