Преглед на файлове

AppBar: add language switcher + translate Survey

Joystream Stats преди 3 години
родител
ревизия
114d05623b
променени са 10 файла, в които са добавени 139 реда и са изтрити 4 реда
  1. 3 0
      package.json
  2. 27 0
      src/components/AppBar/SelectLanguage.tsx
  3. 10 1
      src/components/AppBar/config.ts
  4. 2 0
      src/components/AppBar/index.tsx
  5. 4 3
      src/components/Survey/index.tsx
  6. 22 0
      src/i18n.ts
  7. 2 0
      src/index.tsx
  8. 14 0
      src/lang/en.json
  9. 14 0
      src/lang/ru.json
  10. 41 0
      yarn.lock

+ 3 - 0
package.json

@@ -13,6 +13,8 @@
     "d3-timeline": "^1.0.1",
     "d3-timeline-chart": "^1.3.0",
     "htmr": "^0.9.2",
+    "i18next": "^20.4.0",
+    "i18next-browser-languagedetector": "^6.1.2",
     "interactjs": "^1.10.2",
     "pako": "^2.0.4",
     "react": "^17.0.1",
@@ -21,6 +23,7 @@
     "react-dom": "^17.0.1",
     "react-feather": "^2.0.9",
     "react-horizontal-timeline": "^1.5.3",
+    "react-i18next": "^11.11.4",
     "react-markdown": "^5.0.3",
     "react-router": "^5.2.0",
     "react-router-dom": "^5.2.0",

+ 27 - 0
src/components/AppBar/SelectLanguage.tsx

@@ -0,0 +1,27 @@
+import { useTranslation } from "react-i18next";
+import { MenuItem, Select } from "@material-ui/core";
+
+const SelectLanguage = (props: { classes: string }) => {
+  const { t, i18n } = useTranslation();
+  const { language, store } = i18n;
+  const languages = Object.keys(store.data);
+  return (
+    <div className={props.classes}>
+      <Select
+        id="select-lang"
+        className="form-control"
+        variant="outlined"
+        autoWidth={true}
+        defaultValue={language}
+        value={language}
+        children={languages.map((l) => (
+          <MenuItem key={l} value={l} onClick={() => i18n.changeLanguage(l)}>
+            {t(`lang.${l}`)}
+          </MenuItem>
+        ))}
+      />
+    </div>
+  );
+};
+
+export default SelectLanguage;

+ 10 - 1
src/components/AppBar/config.ts

@@ -25,11 +25,20 @@ export const css = {
     width: "150px",
     color: "#4038ff",
   },
+  lang: {
+    position: "fixed",
+    right: "0px",
+    top: "0px",
+  },
   navBar: {
     "&:hover": {
       backgroundColor: "#4038ff",
     },
   },
   navBarLink: { color: "#fff" },
-  toolBar: { paddingLeft: "12px", backgroundColor: "#000", textAlign: "center" },
+  toolBar: {
+    paddingLeft: "12px",
+    backgroundColor: "#000",
+    textAlign: "center",
+  },
 };

+ 2 - 0
src/components/AppBar/index.tsx

@@ -1,6 +1,7 @@
 import React from "react";
 import { Link } from "react-router-dom";
 import { AppBar, Button, makeStyles, Toolbar } from "@material-ui/core";
+import SelectLanguage from "./SelectLanguage";
 import joystream from "../../joystream.svg";
 
 import { css, routes } from "./config";
@@ -32,6 +33,7 @@ const Bar = () => {
             {routes[route]}
           </Button>
         ))}
+        <SelectLanguage classes={classes.lang} />
       </Toolbar>
     </AppBar>
   );

+ 4 - 3
src/components/Survey/index.tsx

@@ -1,4 +1,5 @@
 import React from "react";
+import { Trans } from "react-i18next";
 import PropTypes from "prop-types";
 import { Grid, withStyles, Theme, Typography } from "@material-ui/core";
 import { Button } from "react-bootstrap";
@@ -76,17 +77,17 @@ class Survey extends React.Component<IProps, IState> {
     return (
       <Grid className={classes.root} item lg={12}>
         <Typography variant="h2" className="mb-3">
-          Survey
+          <Trans i18nKey="survey.head">Survey</Trans>
         </Typography>
         {!started ? (
           <div>
             {survey.length ? (
               <Button disabled={!survey.length} onClick={this.startSurvey}>
-                Start Survey
+                <Trans i18nKey="survey.start">Start Survey</Trans>
               </Button>
             ) : (
               <Button disabled={loading} onClick={this.loadSurvey}>
-                Load Survey
+                <Trans i18nKey="survey.load">Load Survey</Trans>
               </Button>
             )}
           </div>

+ 22 - 0
src/i18n.ts

@@ -0,0 +1,22 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import LanguageDetector from "i18next-browser-languagedetector";
+
+import en from "./lang/en.json";
+import ru from "./lang/ru.json";
+
+// https://github.com/i18next/i18next-browser-languageDetector
+// https://www.i18next.com/overview/configuration-options
+
+i18n
+  .use(LanguageDetector)
+  .use(initReactI18next)
+  .init({
+    debug: true,
+    fallbackLng: "en",
+    interpolation: { escapeValue: false },
+    resources: { en, ru },
+    saveMissing: true,
+  });
+
+export default i18n;

+ 2 - 0
src/index.tsx

@@ -4,6 +4,8 @@ import { BrowserRouter as Router } from "react-router-dom";
 import "./index.css";
 import App from "./App";
 
+import "./i18n";
+
 ReactDOM.render(
   <Router>
     <App />

+ 14 - 0
src/lang/en.json

@@ -0,0 +1,14 @@
+{
+    "translation": {
+        "lang": {
+            "label": "Language",
+            "en": "english",
+            "ru": "russian"
+        },
+        "survey": {
+            "head": "Survey",
+            "start": "Start Survey",
+            "load": "Load Survey"
+        }
+    }
+}

+ 14 - 0
src/lang/ru.json

@@ -0,0 +1,14 @@
+{
+    "translation": {
+        "lang": {
+            "label": "Language",
+            "en": "english",
+            "ru": "russian"
+        },
+        "survey": {
+            "head": "Survey RU",
+            "start": "Start Survey",
+            "load": "Load Survey"
+        }
+    }
+}

+ 41 - 0
yarn.lock

@@ -1164,6 +1164,13 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.12.0", "@babel/runtime@^7.14.5":
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
+  integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/template@^7.10.4", "@babel/template@^7.14.5", "@babel/template@^7.3.3":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
@@ -6447,6 +6454,13 @@ html-minifier-terser@^5.0.1:
     relateurl "^0.2.7"
     terser "^4.6.3"
 
+html-parse-stringify@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
+  integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
+  dependencies:
+    void-elements "3.1.0"
+
 html-to-react@^1.3.4:
   version "1.4.5"
   resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.5.tgz#59091c11021d1ef315ef738460abb6a4a41fe1ce"
@@ -6614,6 +6628,20 @@ hyphenate-style-name@^1.0.2, hyphenate-style-name@^1.0.3:
   resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
   integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
 
+i18next-browser-languagedetector@^6.1.2:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.2.tgz#68565a28b929cbc98ab6a56826ef2faf0e927ff8"
+  integrity sha512-YDzIGHhMRvr7M+c8B3EQUKyiMBhfqox4o1qkFvt4QXuu5V2cxf74+NCr+VEkUuU0y+RwcupA238eeolW1Yn80g==
+  dependencies:
+    "@babel/runtime" "^7.14.6"
+
+i18next@^20.4.0:
+  version "20.4.0"
+  resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.4.0.tgz#6897229a7898e23f3c4885f10315c978b594d3b9"
+  integrity sha512-89iWWJudmaHJwzIdJ/1eu98GtsJnwBhOUWwlAre70itPMuTE/NTPtgVeaS1CGaB8Q3XrYBGpEqlq4jsScDx9kg==
+  dependencies:
+    "@babel/runtime" "^7.12.0"
+
 iconv-lite@0.4.24:
   version "0.4.24"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -10559,6 +10587,14 @@ react-horizontal-timeline@^1.5.3:
     react-motion "^0.5.0"
     uglifyjs-webpack-plugin "^1.2.4"
 
+react-i18next@^11.11.4:
+  version "11.11.4"
+  resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.11.4.tgz#f6f9a1c827e7a5271377de2bf14db04cb1c9e5ce"
+  integrity sha512-ayWFlu8Sc7GAxW1PzMaPtzq+yiozWMxs0P1WeITNVzXAVRhC0Httkzw/IiODBta6seJRBCLrtUeFUSXhAIxlRg==
+  dependencies:
+    "@babel/runtime" "^7.14.5"
+    html-parse-stringify "^3.0.1"
+
 react-icon-base@2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.1.0.tgz#a196e33fdf1e7aaa1fda3aefbb68bdad9e82a79d"
@@ -12844,6 +12880,11 @@ vm-browserify@^1.0.1:
   resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
   integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 
+void-elements@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
+  integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
+
 w3c-hr-time@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"