From 2edad0d5ec6c7b2ff78dc30735f6ddfb7c52bdc6 Mon Sep 17 00:00:00 2001
From: Chris <chris@chrissnijder.nl>
Date: Thu, 4 Feb 2021 00:43:07 +0100
Subject: [PATCH] First stab at i18n, not full l10n, but it will do.

---
 jest.setup.js                                 |  3 +-
 package.json                                  |  7 +-
 pnpm-lock.yaml                                | 75 ++++++++++++++++++-
 src/App.tsx                                   | 17 ++---
 .../locale-switcher/LocaleSwitcher.test.tsx   | 14 ++++
 .../locale-switcher/LocaleSwitcher.tsx        | 14 ++++
 src/index.tsx                                 |  1 +
 src/services/i18n.ts                          | 33 ++++++++
 8 files changed, 150 insertions(+), 14 deletions(-)
 create mode 100644 src/components/locale-switcher/LocaleSwitcher.test.tsx
 create mode 100644 src/components/locale-switcher/LocaleSwitcher.tsx
 create mode 100644 src/services/i18n.ts

diff --git a/jest.setup.js b/jest.setup.js
index cbe7c3d..dbc2608 100644
--- a/jest.setup.js
+++ b/jest.setup.js
@@ -1 +1,2 @@
-import "@testing-library/jest-dom/extend-expect";
\ No newline at end of file
+import "@testing-library/jest-dom/extend-expect";
+import "./src/services/i18n";
diff --git a/package.json b/package.json
index 8468be0..e3df250 100644
--- a/package.json
+++ b/package.json
@@ -17,17 +17,22 @@
   "author": "Mark Swillus, Tin Geber, Chris Snijder",
   "license": "Apache-2.0",
   "dependencies": {
+    "i18next": "^19.8.7",
+    "js-yaml": "^4.0.0",
     "react": "^17.0.0",
-    "react-dom": "^17.0.0"
+    "react-dom": "^17.0.0",
+    "react-i18next": "^11.8.5"
   },
   "devDependencies": {
     "@snowpack/app-scripts-react": "^2.0.0",
+    "@snowpack/plugin-build-script": "^2.1.0",
     "@snowpack/plugin-dotenv": "^2.0.5",
     "@snowpack/plugin-react-refresh": "^2.4.0",
     "@snowpack/plugin-sass": "^1.3.0",
     "@snowpack/plugin-typescript": "^1.2.0",
     "@testing-library/jest-dom": "^5.11.9",
     "@testing-library/react": "^11.0.0",
+    "@testing-library/user-event": "^12.6.3",
     "@types/jest": "^26.0.20",
     "@types/react": "^17.0.0",
     "@types/react-dom": "^17.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 154297b..38b3c86 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,14 +1,19 @@
 dependencies:
+  i18next: 19.8.7
+  js-yaml: 4.0.0
   react: 17.0.1
   react-dom: 17.0.1_react@17.0.1
+  react-i18next: 11.8.5_i18next@19.8.7+react@17.0.1
 devDependencies:
   '@snowpack/app-scripts-react': 2.0.0_c39e9db791ea05e3ec4e0e74abb7a6b5
+  '@snowpack/plugin-build-script': 2.1.0
   '@snowpack/plugin-dotenv': 2.0.5
   '@snowpack/plugin-react-refresh': 2.4.0_react-dom@17.0.1+react@17.0.1
   '@snowpack/plugin-sass': 1.3.0
   '@snowpack/plugin-typescript': 1.2.1_typescript@4.1.3
   '@testing-library/jest-dom': 5.11.9
   '@testing-library/react': 11.2.3_react-dom@17.0.1+react@17.0.1
+  '@testing-library/user-event': 12.6.3
   '@types/jest': 26.0.20
   '@types/react': 17.0.0
   '@types/react-dom': 17.0.0
@@ -1223,6 +1228,11 @@ packages:
     dev: true
     resolution:
       integrity: sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==
+  /@babel/runtime/7.12.13:
+    dependencies:
+      regenerator-runtime: 0.13.7
+    resolution:
+      integrity: sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==
   /@babel/runtime/7.12.5:
     dependencies:
       regenerator-runtime: 0.13.7
@@ -1517,6 +1527,13 @@ packages:
     dev: true
     resolution:
       integrity: sha512-UB5KNQDQ0vnPUSGJ1xscILuuT8eyDK46VCAuImDITYbCy5mf812qwhrvNjbZmGIfnkDmTS2RKopP2cbouDzzSw==
+  /@snowpack/plugin-build-script/2.1.0:
+    dependencies:
+      execa: 5.0.0
+      npm-run-path: 4.0.1
+    dev: true
+    resolution:
+      integrity: sha512-rNuNxI5fM4QieNSOlwhZVD+0iA0nhEAS8MgXStCeH3mr0lC8dVLSYRTt83bS4Q6pxF9zFFfY5z+CTq/JVz8aUw==
   /@snowpack/plugin-dotenv/2.0.5:
     dependencies:
       dotenv: 8.2.0
@@ -1601,6 +1618,17 @@ packages:
       react-dom: '*'
     resolution:
       integrity: sha512-BirBUGPkTW28ULuCwIbYo0y2+0aavHczBT6N9r3LrsswEW3pg25l1wgoE7I8QBIy1upXWkwKpYdWY7NYYP0Bxw==
+  /@testing-library/user-event/12.6.3:
+    dependencies:
+      '@babel/runtime': 7.12.13
+    dev: true
+    engines:
+      node: '>=10'
+      npm: '>=6'
+    peerDependencies:
+      '@testing-library/dom': '>=7.21.4'
+    resolution:
+      integrity: sha512-PCmbUKofE4SXA7l8jphZAbvv5H3c4ix34xPZ/GNe99fASX//msJRgiMbHIBP+GwRfgVG9c7zmkODSPu2X2vNRw==
   /@types/aria-query/4.2.1:
     dev: true
     resolution:
@@ -1805,6 +1833,10 @@ packages:
     dev: true
     resolution:
       integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  /argparse/2.0.1:
+    dev: false
+    resolution:
+      integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
   /aria-query/4.2.2:
     dependencies:
       '@babel/runtime': 7.12.5
@@ -3013,6 +3045,12 @@ packages:
     dev: true
     resolution:
       integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+  /html-parse-stringify2/2.0.1:
+    dependencies:
+      void-elements: 2.0.1
+    dev: false
+    resolution:
+      integrity: sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
   /http-signature/1.2.0:
     dependencies:
       assert-plus: 1.0.0
@@ -3036,6 +3074,12 @@ packages:
       node: '>=10.17.0'
     resolution:
       integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+  /i18next/19.8.7:
+    dependencies:
+      '@babel/runtime': 7.12.13
+    dev: false
+    resolution:
+      integrity: sha512-ezo1gb7QO4OQ5gQCdZMUxopwQSoqpRp6whdEjm1grxMSmkGj1NJ+kYS0UQd4NnpPIVqsgqTQ2L2eqSQYQ+U3Fw==
   /iconv-lite/0.4.24:
     dependencies:
       safer-buffer: 2.1.2
@@ -3770,6 +3814,13 @@ packages:
     hasBin: true
     resolution:
       integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+  /js-yaml/4.0.0:
+    dependencies:
+      argparse: 2.0.1
+    dev: false
+    hasBin: true
+    resolution:
+      integrity: sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
   /jsbn/0.1.1:
     dev: true
     resolution:
@@ -4483,6 +4534,18 @@ packages:
       react: 17.0.1
     resolution:
       integrity: sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==
+  /react-i18next/11.8.5_i18next@19.8.7+react@17.0.1:
+    dependencies:
+      '@babel/runtime': 7.12.13
+      html-parse-stringify2: 2.0.1
+      i18next: 19.8.7
+      react: 17.0.1
+    dev: false
+    peerDependencies:
+      i18next: '>= 19.0.0'
+      react: '>= 16.8.0'
+    resolution:
+      integrity: sha512-2jY/8NkhNv2KWBnZuhHxTn13aMxAbvhiDUNskm+1xVVnrPId78l8fA7fCyVeO3XU1kptM0t4MtvxV1Nu08cjLw==
   /react-is/17.0.1:
     dev: true
     resolution:
@@ -4553,7 +4616,6 @@ packages:
     resolution:
       integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
   /regenerator-runtime/0.13.7:
-    dev: true
     resolution:
       integrity: sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
   /regenerator-transform/0.14.5:
@@ -5392,6 +5454,12 @@ packages:
       '0': node >=0.6.0
     resolution:
       integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+  /void-elements/2.0.1:
+    dev: false
+    engines:
+      node: '>=0.10.0'
+    resolution:
+      integrity: sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
   /w3c-hr-time/1.0.2:
     dependencies:
       browser-process-hrtime: 1.0.0
@@ -5566,21 +5634,26 @@ packages:
       integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
 specifiers:
   '@snowpack/app-scripts-react': ^2.0.0
+  '@snowpack/plugin-build-script': ^2.1.0
   '@snowpack/plugin-dotenv': ^2.0.5
   '@snowpack/plugin-react-refresh': ^2.4.0
   '@snowpack/plugin-sass': ^1.3.0
   '@snowpack/plugin-typescript': ^1.2.0
   '@testing-library/jest-dom': ^5.11.9
   '@testing-library/react': ^11.0.0
+  '@testing-library/user-event': ^12.6.3
   '@types/jest': ^26.0.20
   '@types/react': ^17.0.0
   '@types/react-dom': ^17.0.0
   '@types/snowpack-env': ^2.3.2
+  i18next: ^19.8.7
   jest-cli: ^26.6.3
   jest-each: ^26.6.2
+  js-yaml: ^4.0.0
   prettier: ^2.0.5
   react: ^17.0.0
   react-dom: ^17.0.0
+  react-i18next: ^11.8.5
   rxjs: ^6.6.3
   sass: ^1.32.6
   snowpack: ^3.0.11
diff --git a/src/App.tsx b/src/App.tsx
index da61c30..9754928 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,22 +1,17 @@
-import React, { useState, useEffect } from 'react';
-import PotentialSolutionList, { PotentialSolutionListProps } from './components/potential-solution-list/PotentialSolutionList';
+import React from 'react';
+import { useTranslation } from "react-i18next";
 import './App.css';
-import Spinner from './components/spinner/Spinner';
+import LocaleSwitcher from "./components/locale-switcher/LocaleSwitcher"
 
 interface AppProps { }
 
 function App({ }: AppProps) {
-
-  const solution = { link: "http://example.com", description: "What is your bankaccountnumer?" };
-  const givenSolutions: PotentialSolutionListProps = {
-    intro: "Here are some of the most common examples of administrative issues:",
-    solutions: [solution]
-  };
+  const { i18n, t } = useTranslation();
 
   return (
     <>
-      <PotentialSolutionList {...givenSolutions} />
-      <Spinner big={false} loading={true}/>
+      <LocaleSwitcher />
+      <header><img src="" /><h1>{t("title")}</h1><p>{t("subtitle")}</p></header>
     </>
   );
 }
diff --git a/src/components/locale-switcher/LocaleSwitcher.test.tsx b/src/components/locale-switcher/LocaleSwitcher.test.tsx
new file mode 100644
index 0000000..065db32
--- /dev/null
+++ b/src/components/locale-switcher/LocaleSwitcher.test.tsx
@@ -0,0 +1,14 @@
+import * as React from 'react';
+import { screen, render, fireEvent } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import LocaleSwitcher from './LocaleSwitcher';
+
+describe('<LocaleSwitcher>', () => {
+    it('renders a list of languages', () => {
+        const { getByText, } = render(<LocaleSwitcher />);
+        const select = screen.getByRole("combobox");
+        expect(select).toHaveValue("en");
+        userEvent.selectOptions(select, ["nl"])
+        expect(select).toHaveValue("nl");
+    });
+});
\ No newline at end of file
diff --git a/src/components/locale-switcher/LocaleSwitcher.tsx b/src/components/locale-switcher/LocaleSwitcher.tsx
new file mode 100644
index 0000000..b4247b6
--- /dev/null
+++ b/src/components/locale-switcher/LocaleSwitcher.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+function LocaleSwitcher() {
+    const { i18n } = useTranslation();
+    return (
+        <select value={i18n.language} onChange={e => i18n.changeLanguage(e.target.value)}>
+            <option value="en">English</option>
+            <option value="nl">Nederlands</option>
+        </select>
+
+    );
+}
+export default LocaleSwitcher;
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
index fd82a6d..25ec269 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,6 +1,7 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
 import App from './App';
+import "./services/i18n";
 
 ReactDOM.render(
   <React.StrictMode>
diff --git a/src/services/i18n.ts b/src/services/i18n.ts
new file mode 100644
index 0000000..e7a2943
--- /dev/null
+++ b/src/services/i18n.ts
@@ -0,0 +1,33 @@
+import i18next, { Resource, ResourceKey } from "i18next";
+import { initReactI18next } from "react-i18next";
+
+const resources: Resource = {
+  en: {
+    translation: {
+      title: "Report a problem",
+      subtitle: "Let's troubleshoot together. What type of issue are you experiencing?",
+      selectProblemGroup: "Select an issue type..",
+      selectProblem: "Select issue.."
+    },
+  },
+  nl: {
+    translation: {
+      title: "Meld een probleem",
+      subtitle: "Laten we samen uitzoeken wat er aan de hand is. Wat voor soort probleem ervaar je?",
+      selectProblemGroup: "Selecteer een type issue..",
+      selectProblem: "Selecteer issue.."
+    },
+  },
+};
+
+i18next
+  .use(initReactI18next)
+  .init({
+    resources,
+    lng: "en",
+    interpolation: {
+      escapeValue: false,
+    },
+  });
+
+export default i18next;
\ No newline at end of file
-- 
GitLab