mirror of
https://git.netzspielplatz.de/docker-multiarch/openwrt-firmware-selector.git
synced 2025-11-08 23:39:37 +00:00
adds translation support via i18n.js
Uses react-i18next library to provide APIs for translational
purposes.
Translation data is loaded from `src/locales/{{lng}}/translation.json`
and is accessed by dot notation.
The data can be translated in two ways:
1. In functional components, a method `t` can be instantiated using the
`useTranslation` method from rect-18next.
2. In class components, a method `t` can be accessed via props while
exporting the component with `withTranslation` method from react-i18next
library.
The syntax will look like `t('data.data')` or `this.props.t('data.data')`
Signed-off-by: Sudhanshu Gautam <me@sudhanshug.com>
This commit is contained in:
parent
8f68dc328e
commit
07b13c3f7a
10 changed files with 156 additions and 54 deletions
|
|
@ -9,7 +9,6 @@
|
|||
"gh-pages": "^2.0.1",
|
||||
"i18next": "^17.0.4",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
"i18next-xhr-backend": "^3.0.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<title>OpenWrt Firmware Selector Wizard </title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
|
|
|||
25
src/App.js
25
src/App.js
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
|
||||
import './App.scss';
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ import { ThemeProvider } from '@material-ui/styles';
|
|||
import Header from './components/header.js'
|
||||
import Home from './containers/home/home';
|
||||
import NotFound from './containers/not-found/not-found';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
|
|
@ -22,15 +23,19 @@ const theme = createMuiTheme({
|
|||
function App() {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<div className="App">
|
||||
<Header></Header>
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home}></Route>
|
||||
<Route default component={NotFound}></Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</div>
|
||||
<Suspense fallback={
|
||||
<LinearProgress />
|
||||
}>
|
||||
<div className="App">
|
||||
<Header></Header>
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route path="" component={Home}></Route>
|
||||
<Route default component={NotFound}></Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</div>
|
||||
</Suspense>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
color: white;
|
||||
}
|
||||
|
||||
.language-selector-popper {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,67 @@
|
|||
import React from "react";
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import LanguageIcon from '@material-ui/icons/Language';
|
||||
import { Toolbar } from '@material-ui/core';
|
||||
import { Toolbar, Typography, AppBar, Button, Radio, RadioGroup, FormControlLabel, FormControl, FormLabel, Popper, Fade, Paper } from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18next from 'i18next';
|
||||
|
||||
class Header extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<Typography edge="start" variant="h6">OpenWrt Firmware Selector Wizard</Typography>
|
||||
<div style={{flexGrow: 1}}></div>
|
||||
<Button color="secondary" variant="contained">
|
||||
Change Language
|
||||
<LanguageIcon />
|
||||
</Button>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
export default function Header() {
|
||||
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const [value, setValue] = React.useState('en');
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
|
||||
const changeLanguage = event => {
|
||||
var val = event.target.value;
|
||||
i18n.changeLanguage(val);
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const openChangeLanguagePopper = event => {
|
||||
setValue(i18next.language.substring(0, 2));
|
||||
setAnchorEl(anchorEl ? null : event.currentTarget);
|
||||
}
|
||||
}
|
||||
|
||||
export default Header;
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? 'simple-popper' : undefined;
|
||||
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<Typography edge="start" variant="h6">OpenWrt Firmware Selector Wizard</Typography>
|
||||
<div style={{flexGrow: 1}}></div>
|
||||
<Button aria-describedby={id} color="secondary" variant="contained" onClick={openChangeLanguagePopper}>
|
||||
{t('components.changeLanguage')}
|
||||
<LanguageIcon />
|
||||
</Button>
|
||||
<Popper
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
transition
|
||||
disablePortal = {true}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper className="language-selector-popper">
|
||||
<FormControl component="fieldset">
|
||||
<FormLabel component="legend">Change Language</FormLabel>
|
||||
<br />
|
||||
<RadioGroup
|
||||
aria-label="Language"
|
||||
name="language"
|
||||
value={value}
|
||||
onChange={changeLanguage}
|
||||
>
|
||||
<FormControlLabel value="en" control={<Radio />} label="English" />
|
||||
<FormControlLabel value="de" control={<Radio />} label="German" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</Paper>
|
||||
</Fade>
|
||||
)}
|
||||
</Popper>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Container, Paper, Typography, Grid, Button } from "@material-ui/core";
|
|||
import './home.scss';
|
||||
import Select from 'react-select';
|
||||
import data from '../../data.json';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
class Home extends React.Component {
|
||||
|
||||
|
|
@ -145,12 +146,19 @@ class Home extends React.Component {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
noOptionsMessage = (props) => <Typography {...props.innerProps}>{this.props.t('components.select.noOptions')}</Typography>;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container className="home-container">
|
||||
<Paper>
|
||||
<Typography variant="h5">Download OpenWrt firmware for your device!</Typography>
|
||||
<Typography>Please use the input below to download firmware for your device!</Typography>
|
||||
<Typography variant="h5">
|
||||
{this.props.t('appIntro.head')}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{this.props.t('appIntro.para')}
|
||||
</Typography>
|
||||
<br />
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={4}>
|
||||
|
|
@ -158,6 +166,8 @@ class Home extends React.Component {
|
|||
onChange={this.changeVendor}
|
||||
options={this.devices}
|
||||
value={this.state.vendor}
|
||||
placeholder={this.props.t('components.select.placeholder')}
|
||||
noOptionsMessage={this.noOptionsMessage}
|
||||
/>
|
||||
</Grid>
|
||||
{
|
||||
|
|
@ -167,6 +177,8 @@ class Home extends React.Component {
|
|||
onChange={this.changeModel}
|
||||
options={this.state.vendor.value}
|
||||
value={this.state.model}
|
||||
placeholder={this.props.t('components.select.placeholder')}
|
||||
noOptionsMessage={this.noOptionsMessage}
|
||||
/>
|
||||
</Grid>
|
||||
)
|
||||
|
|
@ -179,6 +191,8 @@ class Home extends React.Component {
|
|||
onChange={this.changeVariant}
|
||||
options={this.state.model.value}
|
||||
value={this.state.variant}
|
||||
placeholder={this.props.t('components.select.placeholder')}
|
||||
noOptionsMessage={this.noOptionsMessage}
|
||||
/>
|
||||
</Grid>
|
||||
)
|
||||
|
|
@ -191,24 +205,24 @@ class Home extends React.Component {
|
|||
variant="contained"
|
||||
onClick={this.findDevice.bind(this)}
|
||||
>
|
||||
Submit
|
||||
{this.props.t('components.submit')}
|
||||
</Button>
|
||||
<br />
|
||||
{this.state.showDeviceData ? (
|
||||
<table className="device-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Model</td>
|
||||
<td>{this.props.t('table.model')}</td>
|
||||
<td>{this.state.device.model}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vendor</td>
|
||||
<td>{this.props.t('table.vendor')}</td>
|
||||
<td>{this.state.device.vendor}</td>
|
||||
</tr>
|
||||
{
|
||||
this.state.device.variant === null || this.state.device.variant === '' ? '' : (
|
||||
<tr>
|
||||
<td>Variant</td>
|
||||
<td>{this.props.t('table.variant')}</td>
|
||||
<td>{this.state.device.variant}</td>
|
||||
</tr>
|
||||
)
|
||||
|
|
@ -230,4 +244,4 @@ class Home extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default Home;
|
||||
export default withTranslation()(Home);
|
||||
|
|
|
|||
21
src/i18n.js
21
src/i18n.js
|
|
@ -1,16 +1,20 @@
|
|||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
import Backend from 'i18next-xhr-backend';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
// not like to use this?
|
||||
// have a look at the Quick start guide
|
||||
// for passing in lng and translations on init
|
||||
import translationEN from './locales/en/translation.json';
|
||||
import translationDE from './locales/de/translation.json';
|
||||
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: translationEN
|
||||
},
|
||||
de: {
|
||||
translation: translationDE
|
||||
}
|
||||
};
|
||||
|
||||
i18n
|
||||
// load translation using xhr -> see /public/locales
|
||||
// learn more: https://github.com/i18next/i18next-xhr-backend
|
||||
.use(Backend)
|
||||
// detect user language
|
||||
// learn more: https://github.com/i18next/i18next-browser-languageDetector
|
||||
.use(LanguageDetector)
|
||||
|
|
@ -19,6 +23,7 @@ i18n
|
|||
// init i18next
|
||||
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||
.init({
|
||||
resources,
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
|
||||
|
|
|
|||
20
src/locales/de/translation.json
Normal file
20
src/locales/de/translation.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"title": "OpenWrt Firmware Selector Wizard",
|
||||
"appIntro": {
|
||||
"head": "Laden Sie die OpenWrt-Firmware für Ihr Gerät herunter!",
|
||||
"para": "Bitte benutzen Sie den unten stehenden Eingang, um die Firmware für Ihr Gerät herunterzuladen!"
|
||||
},
|
||||
"components": {
|
||||
"submit": "einreichen",
|
||||
"changeLanguage": "Sprache ändern",
|
||||
"select": {
|
||||
"placeholder": "Wählen...",
|
||||
"noOptions": "Keine Optionen"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"model": "Modell",
|
||||
"vendor": "Verkäufer",
|
||||
"variant": "Variante"
|
||||
}
|
||||
}
|
||||
20
src/locales/en/translation.json
Normal file
20
src/locales/en/translation.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"title": "OpenWrt Firmware Selector Wizard",
|
||||
"appIntro": {
|
||||
"head": "Download OpenWrt firmware for your device!",
|
||||
"para": "Please use the input below to download firmware for your device!"
|
||||
},
|
||||
"components": {
|
||||
"submit": "Submit",
|
||||
"changeLanguage": "Change Language",
|
||||
"select": {
|
||||
"placeholder": "Select...",
|
||||
"noOptions": "No options"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"model": "Model",
|
||||
"vendor": "Vendor",
|
||||
"variant": "Variant"
|
||||
}
|
||||
}
|
||||
|
|
@ -5055,13 +5055,6 @@ i18next-browser-languagedetector@^3.0.1:
|
|||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-3.0.1.tgz#a47c43176e8412c91e808afb7c6eb5367649aa8e"
|
||||
integrity sha512-WFjPLNPWl62uu07AHY2g+KsC9qz0tyMq+OZEB/H7N58YKL/JLiCz9U709gaR20Mule/Ppn+uyfVx5REJJjn1HA==
|
||||
|
||||
i18next-xhr-backend@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/i18next-xhr-backend/-/i18next-xhr-backend-3.0.0.tgz#75235870c920291dbfd32043505b7ede0dc87da3"
|
||||
integrity sha512-Pi/X91Zk2nEqdEHTV+FG6VeMHRcMcPKRsYW/A0wlaCfKsoJc3TI7A75Tqse/d5LVGN2Ymzx0FT+R+gLag9Eb2g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.5"
|
||||
|
||||
i18next@^17.0.4:
|
||||
version "17.0.4"
|
||||
resolved "https://registry.yarnpkg.com/i18next/-/i18next-17.0.4.tgz#c690b9de0c950ff8abe626562d03c4144dd75030"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue