Merged PR 12: i18n

i18n
master
Tudor Stanciu 2020-05-13 14:50:09 +00:00
commit badafa1c7c
10 changed files with 212 additions and 6 deletions

54
package-lock.json generated
View File

@ -4930,6 +4930,14 @@
"uglify-js": "3.4.x"
}
},
"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": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
@ -5076,6 +5084,30 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
"integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
},
"i18next": {
"version": "19.4.4",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.4.4.tgz",
"integrity": "sha512-ofaHtdsDdX3A5nYur1HWblB7J4hIcjr2ACdnwTAJgc8hTfPbyzZfGX0hVkKpI3vzDIgO6Uzc4v1ffW2W6gG6zw==",
"requires": {
"@babel/runtime": "^7.3.1"
}
},
"i18next-browser-languagedetector": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.1.1.tgz",
"integrity": "sha512-akv0zurR/2KU7s1qaWkirY9FEEOT1TNsQaezEg8+1BLLQre7vylqb7tYoUgYqP/0/BEzXJgnoQnj+sh5xYFMhg==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"i18next-http-backend": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.0.10.tgz",
"integrity": "sha512-HQl3N2plhU7WQd2Bcq3UWrpgM01w/Lkee76airTsKsLG4jnWKy6mYH3O7xz1da2ga9R6AN1MTSVVzJTp0uDl7A==",
"requires": {
"node-fetch": "2.6.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -6249,6 +6281,11 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.25.3",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz",
"integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -6352,8 +6389,7 @@
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
"dev": true
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"node-forge": {
"version": "0.9.0",
@ -7837,6 +7873,15 @@
"scheduler": "^0.13.4"
}
},
"react-i18next": {
"version": "11.4.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.4.0.tgz",
"integrity": "sha512-lyOZSSQkif4H9HnHN3iEKVkryLI+WkdZSEw3VAZzinZLopfYRMHVY5YxCopdkXPLEHs6S5GjKYPh3+j0j336Fg==",
"requires": {
"@babel/runtime": "^7.3.1",
"html-parse-stringify2": "2.0.1"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -9969,6 +10014,11 @@
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
"dev": true
},
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
"wait-for-expect": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.3.0.tgz",

View File

@ -15,10 +15,15 @@
"@material-ui/icons": "^4.9.1",
"axios": "^0.19.2",
"bootstrap": "4.3.1",
"i18next": "^19.4.4",
"i18next-browser-languagedetector": "^4.1.1",
"i18next-http-backend": "^1.0.10",
"immer": "2.1.3",
"moment": "^2.25.3",
"prop-types": "15.7.2",
"react": "16.8.4",
"react-dom": "16.8.4",
"react-i18next": "^11.4.0",
"react-redux": "6.0.1",
"react-router-dom": "5.0.0",
"react-toastify": "4.5.2",

9
private/Notes.txt Normal file
View File

@ -0,0 +1,9 @@
withTranslation()(LegacyComponentClass)
const { t } = this.props;
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t, i18n } = useTranslation();

View File

@ -0,0 +1,12 @@
{
"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}}",
"Session": "Session"
}

View File

@ -0,0 +1,3 @@
{
"Session": "Sesiune"
}

View File

@ -1,8 +1,11 @@
import i18next from "i18next";
function getHeaders() {
const headers = new Headers();
headers.append("Accept", "application/json");
headers.append("Content-Type", "application/json");
headers.append("Authorization", "Basic ***REMOVED***");
headers.append("Accept-Language", `${i18next.language}`);
return headers;
}

View File

@ -1,9 +1,11 @@
import axios from "axios";
import i18next from "i18next";
function getHeaders() {
return {
"Content-Type": "application/json",
Authorization: "Basic ***REMOVED***"
Authorization: "Basic ***REMOVED***",
"Accept-Language": `${i18next.language}`
};
}

View File

@ -3,6 +3,7 @@ import PropTypes from "prop-types";
import { Grid } from "@material-ui/core";
import { makeStyles } from "@material-ui/core/styles";
import { CheckCircleOutlineRounded, RemoveRounded } from "@material-ui/icons";
import { useTranslation } from "react-i18next";
const useStyles = makeStyles((theme) => ({
value: {
@ -15,12 +16,13 @@ const useStyles = makeStyles((theme) => ({
const SessionSummary = ({ session }) => {
const classes = useStyles();
const { t, i18n } = useTranslation();
return (
<>
<Grid container className={classes.miniContainer}>
<Grid item xs={12} sm={5} md={5}>
{"Session: "}
{`${t("Session")}: `}
<span className={classes.value}>{session.sessionId}</span>
</Grid>
<Grid item xs={12} sm={2} md={2}>
@ -33,12 +35,25 @@ const SessionSummary = ({ session }) => {
</Grid>
<Grid item xs={12} sm={3} md={3}>
{"Start date: "}
<span className={classes.value}>{session.startDate}</span>
<span className={classes.value}>
{t("DATE_FORMAT", {
date: { value: session.startDate, format: "DD-MM-YYYY HH:mm:ss" }
})}
</span>
</Grid>
<Grid item xs={12} sm={3} md={3}>
{"Stop date: "}
<span className={classes.value}>{session.stopDate || "---"}</span>
<span className={classes.value}>
{session.stopDate
? t("DATE_FORMAT", {
date: {
value: session.stopDate,
format: "DD-MM-YYYY HH:mm:ss"
}
})
: "---"}
</span>
</Grid>
<Grid item xs={12} sm={3} md={3}>

View File

@ -6,6 +6,7 @@ import App from "./components/App";
import "./index.css";
import configureStore from "./redux/configureStore";
import { Provider as ReduxProvider } from "react-redux";
import "./utils/i18n";
const store = configureStore();

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

@ -0,0 +1,106 @@
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()) {
//new Intl.DateTimeFormat(lng).format(new Date(value));
return moment(value).format("L");
}
return "";
}
if (format === "intlLongDate") {
if (value && moment(value).isValid()) {
//return new Intl.DateTimeFormat(lng, options).format(new Date(value));
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;
}
},
react: {
useSuspense: false
},
backend: {
loadPath: "/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;