added i18next translation

master
Tudor Stanciu 2020-12-23 02:24:38 +02:00
parent 4b07aae6bc
commit df9c92d909
7 changed files with 198 additions and 8 deletions

61
package-lock.json generated
View File

@ -7300,6 +7300,14 @@
"terser": "^4.6.3" "terser": "^4.6.3"
} }
}, },
"html-parse-stringify2": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
"integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
"requires": {
"void-elements": "^2.0.1"
}
},
"html-webpack-plugin": { "html-webpack-plugin": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz",
@ -7532,6 +7540,30 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
}, },
"i18next": {
"version": "19.8.4",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.8.4.tgz",
"integrity": "sha512-FfVPNWv+felJObeZ6DSXZkj9QM1Ivvh7NcFCgA8XPtJWHz0iXVa9BUy+QY8EPrCLE+vWgDfV/sc96BgXVo6HAA==",
"requires": {
"@babel/runtime": "^7.12.0"
}
},
"i18next-browser-languagedetector": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.3.1.tgz",
"integrity": "sha512-KIToAzf8zwWvacgnRwJp63ase26o24AuNUlfNVJ5YZAFmdGhsJpmFClxXPuk9rv1FMI4lnc8zLSqgZPEZMrW4g==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"i18next-http-backend": {
"version": "1.0.21",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.0.21.tgz",
"integrity": "sha512-UDeHoV2B+31Gr++0KFAVjM5l+SEwePpF6sfDyaDq5ennM9QNJ78PBEMPStwkreEm4h5C8sT7M1JdNQrLcU1Wdg==",
"requires": {
"node-fetch": "2.6.1"
}
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -10326,6 +10358,11 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -10440,6 +10477,11 @@
} }
} }
}, },
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-forge": { "node-forge": {
"version": "0.10.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -12591,6 +12633,15 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz",
"integrity": "sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==" "integrity": "sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw=="
}, },
"react-i18next": {
"version": "11.8.4",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.8.4.tgz",
"integrity": "sha512-QlPJfX+Roi+jEQ6frBSsLHHH+VWbUoCl6wZDT8XHMd6PsSgepjgD2sZf/h7F46JnHeuy0U+SxY3TtrJF+aDIyg==",
"requires": {
"@babel/runtime": "^7.3.1",
"html-parse-stringify2": "2.0.1"
}
},
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -15301,6 +15352,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
}, },
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
"w3c-hr-time": { "w3c-hr-time": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@ -15576,11 +15632,6 @@
"minimalistic-assert": "^1.0.0" "minimalistic-assert": "^1.0.0"
} }
}, },
"web-vitals": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-0.2.4.tgz",
"integrity": "sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg=="
},
"webidl-conversions": { "webidl-conversions": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",

View File

@ -12,7 +12,11 @@
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.1", "react-scripts": "4.0.1",
"web-vitals": "^0.2.4" "i18next": "^19.4.4",
"i18next-browser-languagedetector": "^4.1.1",
"i18next-http-backend": "^1.0.10",
"react-i18next": "^11.4.0",
"moment": "^2.25.3"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

View File

@ -0,0 +1,19 @@
{
"DATE": "{{date,intlDate}}",
"LONG_DATE": "{{date,intlLongDate}}",
"DATE_FORMAT": "{{date, format}}",
"TIME_FROM_X": "{{date,intlTimeFromX}}",
"H_FROM_X": "{{date,intlHoursFromX}}",
"H_FROM_M": "{{number,intlHoursFromMinutes}}",
"NUMBER": "{{number,intlNumber}}",
"DECIMAL": "{{number,intlDecimal}}",
"DECIMAL2": "{{number,intlDecimal2}}",
"Language": {
"English": "English",
"Romanian": "Romanian"
},
"Login": {
"Username": "Username",
"Password": "Password"
}
}

View File

@ -0,0 +1,10 @@
{
"Language": {
"English": "Engleză",
"Romanian": "Română"
},
"Login": {
"Username": "Utilizator",
"Password": "Parolă"
}
}

View File

@ -7,6 +7,7 @@ import {
ApplicationStateContext, ApplicationStateContext,
ApplicationDispatchContext ApplicationDispatchContext
} from "../../../state/ApplicationContexts"; } from "../../../state/ApplicationContexts";
import { useTranslation } from "react-i18next";
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles(theme => ({
field: { field: {
@ -17,6 +18,7 @@ const useStyles = makeStyles(theme => ({
const LoginComponent = () => { const LoginComponent = () => {
const classes = useStyles(); const classes = useStyles();
const { t } = useTranslation();
const state = useContext(ApplicationStateContext); const state = useContext(ApplicationStateContext);
const dispatchActions = useContext(ApplicationDispatchContext); const dispatchActions = useContext(ApplicationDispatchContext);
@ -30,7 +32,7 @@ const LoginComponent = () => {
<TextField <TextField
className={classes.field} className={classes.field}
id="username" id="username"
label="Username" label={t("Login.Username")}
onChange={handleChange("userName")} onChange={handleChange("userName")}
value={state.credentials.userName} value={state.credentials.userName}
InputProps={{ InputProps={{
@ -44,7 +46,7 @@ const LoginComponent = () => {
<br /> <br />
<PasswordField <PasswordField
id="password" id="password"
label="Password" label={t("Login.Password")}
className={classes.field} className={classes.field}
onChange={handleChange("password")} onChange={handleChange("password")}
value={state.credentials.password} value={state.credentials.password}

View File

@ -1,6 +1,7 @@
import React, { Suspense } from "react"; import React, { Suspense } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import "./index.css"; import "./index.css";
import "./utils/i18n";
import App from "./components/App"; import App from "./components/App";
import { BrowserRouter as Router } from "react-router-dom"; import { BrowserRouter as Router } from "react-router-dom";

103
src/utils/i18n.js Normal file
View File

@ -0,0 +1,103 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import Backend from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
import moment from "moment";
import "moment/locale/ro.js";
import "moment/locale/de.js";
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next) // passes i18n down to react-i18next
.init(
{
fallbackLng: "en",
debug: true,
ns: ["translations"],
defaultNS: "translations",
//whitelist: ["en", "ro"],
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
format: function (value, format, lng) {
if (format === "uppercase") return value.toUpperCase();
if (format === "intlDate") {
if (value && moment(value).isValid()) {
return moment(value).format("L");
}
return "";
}
if (format === "intlLongDate") {
if (value && moment(value).isValid()) {
return moment(value).format("LLLL");
}
return "";
}
if (format === "intlTimeFromX") {
if (value && moment(value.start).isValid()) {
let startDate = moment(value.start);
let endDate = moment(value.end);
return moment(endDate).from(startDate, true);
}
return "";
}
if (format === "intlHoursFromX") {
if (value && moment(value.start).isValid()) {
let startDate = moment(value.start);
let endDate = moment(value.end);
let span = moment.duration(endDate - startDate);
return `${parseInt(span.asHours(), 10)}h ${parseInt(
span.asMinutes() % 60,
10
)}m`;
}
return "";
}
if (format === "intlNumber")
return new Intl.NumberFormat(lng).format(value);
if (format === "intlDecimal")
return new Intl.NumberFormat(lng, {
minimumFractionDigits: 2
}).format(value);
if (format === "intlDecimal2")
return new Intl.NumberFormat(lng, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(value);
//dateformat
if (value && value.format) {
if (value.value && moment(value).isValid()) {
return moment(value.value).format(value.format);
}
return "";
}
return value;
}
},
backend: {
loadPath: `${
process.env.PUBLIC_URL || ""
}/public/locales/{{lng}}/{{ns}}.json`
}
},
() => {
const currentLang = i18n.language;
if (!currentLang || !currentLang.startsWith("ro")) {
i18n.changeLanguage("en");
} else {
i18n.changeLanguage("ro");
}
}
);
i18n.on("languageChanged", function (lng) {
moment.locale(lng);
});
export default i18n;