diff --git a/package-lock.json b/package-lock.json index 81aa6d4..57c8911 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7300,6 +7300,14 @@ "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": { "version": "4.5.0", "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", "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": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10326,6 +10358,11 @@ "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": { "version": "1.0.1", "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": { "version": "0.10.0", "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", "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": { "version": "16.13.1", "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", "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": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -15576,11 +15632,6 @@ "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": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/package.json b/package.json index 6cefca5..b8cbb39 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,11 @@ "react-dom": "^17.0.1", "react-router-dom": "^5.2.0", "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": { "start": "react-scripts start", diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json new file mode 100644 index 0000000..a9b85d9 --- /dev/null +++ b/public/locales/en/translations.json @@ -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" + } +} diff --git a/public/locales/ro/translations.json b/public/locales/ro/translations.json new file mode 100644 index 0000000..2a3987a --- /dev/null +++ b/public/locales/ro/translations.json @@ -0,0 +1,10 @@ +{ + "Language": { + "English": "Engleză", + "Romanian": "Română" + }, + "Login": { + "Username": "Utilizator", + "Password": "Parolă" + } +} diff --git a/src/features/login/components/LoginComponent.js b/src/features/login/components/LoginComponent.js index 6f9aa03..997f9f7 100644 --- a/src/features/login/components/LoginComponent.js +++ b/src/features/login/components/LoginComponent.js @@ -7,6 +7,7 @@ import { ApplicationStateContext, ApplicationDispatchContext } from "../../../state/ApplicationContexts"; +import { useTranslation } from "react-i18next"; const useStyles = makeStyles(theme => ({ field: { @@ -17,6 +18,7 @@ const useStyles = makeStyles(theme => ({ const LoginComponent = () => { const classes = useStyles(); + const { t } = useTranslation(); const state = useContext(ApplicationStateContext); const dispatchActions = useContext(ApplicationDispatchContext); @@ -30,7 +32,7 @@ const LoginComponent = () => { {
{ + 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;