commit af3e36c5dfb002d13543738a31f58443946bf68d
parent 5401431c5385a1b340bce3d534077ee15e809371
Author: MTRNord <mtrnord1@gmail.com>
Date: Wed, 4 Jan 2023 20:58:10 +0100
readd translations
Diffstat:
10 files changed, 298 insertions(+), 44 deletions(-)
diff --git a/package-lock.json b/package-lock.json
@@ -11,11 +11,15 @@
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz",
"buffer": "^6.0.3",
"events": "^3.3.0",
+ "i18next": "^22.4.8",
+ "i18next-browser-languagedetector": "^7.0.1",
+ "i18next-http-backend": "^2.1.1",
"inquirer": "^9.1.4",
"matrix-events-sdk": "^0.0.1",
"matrix-js-sdk": "^23.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-i18next": "^12.1.1",
"react-plock": "github:MTRNord/react-plock#MTRNord/patch-react",
"react-router-dom": "^6.6.1",
"react-spinners": "^0.13.7"
@@ -1883,6 +1887,14 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/cross-fetch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+ "dependencies": {
+ "node-fetch": "2.6.7"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -2742,6 +2754,52 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "node_modules/html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
+ "node_modules/i18next": {
+ "version": "22.4.8",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.8.tgz",
+ "integrity": "sha512-XSOy17ZWqflOiJRYE/dzv6vDle2Se32dnHREHb93UnZzZ1+UnvQ8yKtt1fpNL3zvXz5AwCqqixrtTVZmRetaiQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "dependencies": {
+ "@babel/runtime": "^7.20.6"
+ }
+ },
+ "node_modules/i18next-browser-languagedetector": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz",
+ "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==",
+ "dependencies": {
+ "@babel/runtime": "^7.19.4"
+ }
+ },
+ "node_modules/i18next-http-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.1.tgz",
+ "integrity": "sha512-jByfUCDVgQ8+/Wens7queQhYYvMcGTW/lR4IJJNEDDXnmqjLrwi8ubXKpmp76/JIWEZHffNdWqnxFJcTVGeaOw==",
+ "dependencies": {
+ "cross-fetch": "3.1.5"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -3323,6 +3381,25 @@
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true
},
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
@@ -3862,6 +3939,27 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-i18next": {
+ "version": "12.1.1",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
+ "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==",
+ "dependencies": {
+ "@babel/runtime": "^7.14.5",
+ "html-parse-stringify": "^3.0.1"
+ },
+ "peerDependencies": {
+ "i18next": ">= 19.0.0",
+ "react": ">= 16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-is": {
"version": "18.1.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz",
@@ -4647,6 +4745,11 @@
"node": ">=8.0"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
"node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
@@ -4831,6 +4934,14 @@
"ejs": "^3.1.8"
}
},
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -4839,6 +4950,20 @@
"defaults": "^1.0.3"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -6095,6 +6220,14 @@
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww=="
},
+ "cross-fetch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+ "requires": {
+ "node-fetch": "2.6.7"
+ }
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -6749,6 +6882,38 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "requires": {
+ "void-elements": "3.1.0"
+ }
+ },
+ "i18next": {
+ "version": "22.4.8",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.8.tgz",
+ "integrity": "sha512-XSOy17ZWqflOiJRYE/dzv6vDle2Se32dnHREHb93UnZzZ1+UnvQ8yKtt1fpNL3zvXz5AwCqqixrtTVZmRetaiQ==",
+ "requires": {
+ "@babel/runtime": "^7.20.6"
+ }
+ },
+ "i18next-browser-languagedetector": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz",
+ "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==",
+ "requires": {
+ "@babel/runtime": "^7.19.4"
+ }
+ },
+ "i18next-http-backend": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.1.tgz",
+ "integrity": "sha512-jByfUCDVgQ8+/Wens7queQhYYvMcGTW/lR4IJJNEDDXnmqjLrwi8ubXKpmp76/JIWEZHffNdWqnxFJcTVGeaOw==",
+ "requires": {
+ "cross-fetch": "3.1.5"
+ }
+ },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7162,6 +7327,14 @@
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true
},
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
"node-releases": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
@@ -7504,6 +7677,15 @@
"scheduler": "^0.23.0"
}
},
+ "react-i18next": {
+ "version": "12.1.1",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
+ "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==",
+ "requires": {
+ "@babel/runtime": "^7.14.5",
+ "html-parse-stringify": "^3.0.1"
+ }
+ },
"react-is": {
"version": "18.1.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz",
@@ -8063,6 +8245,11 @@
"is-number": "^7.0.0"
}
},
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
"tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
@@ -8172,6 +8359,11 @@
"ejs": "^3.1.8"
}
},
+ "void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
+ },
"wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -8180,6 +8372,20 @@
"defaults": "^1.0.3"
}
},
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
@@ -13,11 +13,15 @@
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz",
"buffer": "^6.0.3",
"events": "^3.3.0",
+ "i18next": "^22.4.8",
+ "i18next-browser-languagedetector": "^7.0.1",
+ "i18next-http-backend": "^2.1.1",
"inquirer": "^9.1.4",
"matrix-events-sdk": "^0.0.1",
"matrix-js-sdk": "^23.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-i18next": "^12.1.1",
"react-plock": "github:MTRNord/react-plock#MTRNord/patch-react",
"react-router-dom": "^6.6.1",
"react-spinners": "^0.13.7"
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
@@ -0,0 +1,13 @@
+{
+ "Loading...": "Loading...",
+ "Login": "Login",
+ "Register": "Register",
+ "Search": "Search",
+ "Join": "Join",
+ "Post": "Post",
+ "Homeserver": "Homeserver",
+ "Username": "Username",
+ "Password": "Password",
+ "Create account": "Create account",
+ "Explore": "Explore"
+}
+\ No newline at end of file
diff --git a/src/app.tsx b/src/app.tsx
@@ -10,6 +10,7 @@ import olmWasmPath from "@matrix-org/olm/olm.wasm?url";
import OlmLegacy from '@matrix-org/olm/olm_legacy.js?url';
import Olm from '@matrix-org/olm';
import { Route, Routes } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
const Join = lazy(() => import("./pages/Join"));
const Post = lazy(() => import("./pages/Post"));
@@ -76,48 +77,36 @@ export function App() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="join" element={
- <Suspense fallback={
- <div className="flex flex-col">
- <header>
- <Header />
- </header>
- <main className="m-12 mt-6 flex items-center justify-center">
- <p className="text-lg text-data font-bold">Loading...</p>
- </main>
- </div>
- }>
+ <Suspense fallback={<LoadingPage />}>
<Join />
</Suspense>
} />
<Route path="/post/:postId" element={
- <Suspense fallback={
- <div className="flex flex-col">
- <header>
- <Header />
- </header>
- <main className="m-12 mt-6 flex items-center justify-center">
- <p className="text-lg text-data font-bold">Loading...</p>
- </main>
- </div>
- }>
+ <Suspense fallback={<LoadingPage />}>
<Post />
</Suspense>
} />
<Route path="/profile/:userId" element={
- <Suspense fallback={
- <div className="flex flex-col">
- <header>
- <Header />
- </header>
- <main className="m-12 mt-6 flex items-center justify-center">
- <p className="text-lg text-data font-bold">Loading...</p>
- </main>
- </div>
- }>
+ <Suspense fallback={<LoadingPage />}>
<Profile />
</Suspense>
} />
</Routes>
</Client.Provider >
);
+}
+
+function LoadingPage() {
+ const { t } = useTranslation();
+
+ return (
+ <div className="flex flex-col">
+ <header>
+ <Header />
+ </header>
+ <main className="m-12 mt-6 flex items-center justify-center">
+ <p className="text-lg text-data font-bold">{t('Loading...')}</p>
+ </main>
+ </div>
+ );
}
\ No newline at end of file
diff --git a/src/components/header.tsx b/src/components/header.tsx
@@ -2,9 +2,12 @@ import { Link } from "react-router-dom";
import { useContext } from "react";
import { Client } from "../context";
import logo_url from "./Logo_colored.svg";
+import { useTranslation } from "react-i18next";
export function Header() {
const client = useContext(Client);
+ const { t } = useTranslation();
+
return (
<div className="m-12 flex flex-col lg:flex-row items-center justify-between">
<Link to="/"><img alt="Matrix Art" src={logo_url} /></Link>
@@ -16,12 +19,12 @@ export function Header() {
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
</svg>
</div>
- <input className="search-bg shadow rounded-2xl border-0 py-3 px-4 pl-12 text-data" placeholder="Search"></input>
+ <input className="search-bg shadow rounded-2xl border-0 py-3 px-4 pl-12 text-data" placeholder={t("Search") as string}></input>
</div>
{
- !client?.isLoggedIn() ? <Link to="/join" className="text-white font-bold text-1xl logo-bg rounded-2xl py-3 px-12 shadow mt-4 sm:mt-0 transform transition-transform ease-in-out duration-300 hover:scale-105">Join</Link> :
- <Link to="/" className="text-white font-bold text-1xl logo-bg rounded-2xl py-3 px-12 shadow mt-4 sm:mt-0 transform transition-transform ease-in-out duration-300 hover:scale-105">Post</Link>
+ !client?.isLoggedIn() ? <Link to="/join" className="text-white font-bold text-1xl logo-bg rounded-2xl py-3 px-12 shadow mt-4 sm:mt-0 transform transition-transform ease-in-out duration-300 hover:scale-105">{t('Join')}</Link> :
+ <Link to="/" className="text-white font-bold text-1xl logo-bg rounded-2xl py-3 px-12 shadow mt-4 sm:mt-0 transform transition-transform ease-in-out duration-300 hover:scale-105">{t('Post')}</Link>
}
</div>
diff --git a/src/i18n.ts b/src/i18n.ts
@@ -0,0 +1,32 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+
+import Backend from 'i18next-http-backend';
+import LanguageDetector from 'i18next-browser-languagedetector';
+// don't want to use this?
+// have a look at the Quick start guide
+// for passing in lng and translations on init
+
+i18n
+ // load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
+ // learn more: https://github.com/i18next/i18next-http-backend
+ // want your translations to be loaded from a professional CDN? => https://github.com/locize/react-tutorial#step-2---use-the-locize-cdn
+ .use(Backend)
+ // detect user language
+ // learn more: https://github.com/i18next/i18next-browser-languageDetector
+ .use(LanguageDetector)
+ // pass the i18n instance to react-i18next.
+ .use(initReactI18next)
+ // init i18next
+ // for all options read: https://www.i18next.com/overview/configuration-options
+ .init({
+ fallbackLng: 'en',
+ debug: true,
+
+ interpolation: {
+ escapeValue: false, // not needed for react as it escapes by default
+ }
+ });
+
+
+export default i18n;
+\ No newline at end of file
diff --git a/src/main.tsx b/src/main.tsx
@@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { App } from './app';
import './index.css';
+import './i18n';
+
ReactDOM.createRoot(document.querySelector('#app') as HTMLElement).render(
<React.StrictMode>
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
@@ -3,6 +3,7 @@ import { Post } from "../components/post";
import { Plock } from "react-plock";
import { UserData } from "../data/user";
import { PostData } from "../data/post";
+import { useTranslation } from "react-i18next";
const BREAKPOINTS = [
@@ -13,13 +14,15 @@ const BREAKPOINTS = [
];
export function Home() {
+ const { t } = useTranslation();
+
return (
<div className="flex flex-col">
<header>
<Header />
</header>
<main className="m-12 mt-6">
- <h1 className="text-3xl font-bold mb-4 text-white">Explore</h1>
+ <h1 className="text-3xl font-bold mb-4 text-white">{t('Explore')}</h1>
<div className="flex justify-center" id="gallery">
<Plock gap={"24px"} breakpoints={BREAKPOINTS}>
{/*
diff --git a/src/pages/Join.tsx b/src/pages/Join.tsx
@@ -2,6 +2,7 @@ import React, { useState, useContext } from "react";
import { Client } from "../context";
import { Header } from "../components/header";
import { useNavigate } from "react-router-dom";
+import { useTranslation } from "react-i18next";
const ACTIVE_TAB_CSS = "inline-block p-4 w-full text-gray-900 bg-gray-100 hover:ring-blue-300 hover:ring-1 focus:ring-transparent focus:outline-none dark:bg-gray-700 dark:text-white";
const TAB_CSS = "inline-block p-4 w-full bg-white hover:text-gray-700 hover:bg-gray-50 hover:ring-blue-300 hover:ring-1 focus:ring-transparent focus:outline-none dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700";
@@ -14,6 +15,7 @@ export default function Join() {
const [password, setPassword] = useState("");
const [createProfile, setCreateProfile] = useState(true);
const [currentTab, setCurrentTab] = useState("login");
+ const { t } = useTranslation();
const onSubmit = async (e: React.FormEvent) => {
if (!client) {
@@ -60,26 +62,26 @@ export default function Join() {
</header>
<main className="m-12 mt-6">
- <h1 className="text-3xl font-bold mb-4 text-white">Join</h1>
+ <h1 className="text-3xl font-bold mb-4 text-white">{t('Join')}</h1>
<div className="flex items-center flex-col">
<ul className="w-1/4 mb-8 hidden text-sm font-medium text-center text-gray-500 rounded-lg divide-x divide-gray-200 shadow sm:flex dark:divide-gray-700 dark:text-gray-400">
<li className="w-full">
- <a href="#" className={currentTab === "login" ? `${ACTIVE_TAB_CSS} rounded-l-lg` : `${TAB_CSS} rounded-l-lg`} onClick={(e) => { setCurrentTab("login"); }}>Login</a>
+ <a href="#" className={currentTab === "login" ? `${ACTIVE_TAB_CSS} rounded-l-lg` : `${TAB_CSS} rounded-l-lg`} onClick={(e) => { setCurrentTab("login"); }}>{t('Login')}</a>
</li>
<li className="w-full">
- <a href="#" className={currentTab === "register" ? `${ACTIVE_TAB_CSS} rounded-r-lg` : `${TAB_CSS} rounded-r-lg`} onClick={(e) => { setCurrentTab("register"); }}>Register</a>
+ <a href="#" className={currentTab === "register" ? `${ACTIVE_TAB_CSS} rounded-r-lg` : `${TAB_CSS} rounded-r-lg`} onClick={(e) => { setCurrentTab("register"); }}>{t('Register')}</a>
</li>
</ul>
<form onSubmit={onSubmit} className="flex flex-col items-start w-1/4">
- <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" type="url" placeholder="Homeserver" name="homeserver" value={homeserver} onInput={onInput} />
- <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" autoComplete="username" type="text" placeholder="Username" name="username" value={username} onInput={onInput} />
- <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" autoComplete="current-password" type="password" placeholder="Password" name="password" value={password} onInput={onInput} />
+ <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" type="url" placeholder={t("Homeserver") as string} name="homeserver" value={homeserver} onInput={onInput} />
+ <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" autoComplete="username" type="text" placeholder={t("Username") as string} name="username" value={username} onInput={onInput} />
+ <input className="search-bg shadow rounded-lg border-0 py-3 px-4 placeholder-data text-white mb-4 w-full" autoComplete="current-password" type="password" placeholder={t("Password") as string} name="password" value={password} onInput={onInput} />
<label className="mb-4 flex items-center">
<input className="checked:bg-blue-600 checked:border-transparent checked:bg-no-repeat checked:bg-[url('/tick.svg')] outline-none focus:outline-offset-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white p-0 inline-block align-middle box-border select-none shrink-0 shadow h-5 w-5 appearance-none rounded bg-white border-none" type="checkbox" name="createProfile" checked={createProfile} onChange={onInput} />
- <span className="ml-4 text-data text-base font-medium">Create account</span>
+ <span className="ml-4 text-data text-base font-medium">{t('Create account')}</span>
</label>
- <button type="submit" className="text-white font-bold text-lg logo-bg rounded-xl py-2 px-10 shadow transform transition-transform ease-in-out duration-300 hover:scale-105 w-1/2 self-center justify-center flex">{currentTab === "login" ? "Login" : "Register"}</button>
+ <button type="submit" className="text-white font-bold text-lg logo-bg rounded-xl py-2 px-10 shadow transform transition-transform ease-in-out duration-300 hover:scale-105 w-1/2 self-center justify-center flex">{currentTab === "login" ? t("Login") : t("Register")}</button>
</form>
</div>
</main >
diff --git a/src/utils/asyncImages.tsx b/src/utils/asyncImages.tsx
@@ -1,6 +1,4 @@
// First we need a type of cache to avoid creating resources for images
-
-import React from "react";
import { ImgHTMLAttributes } from "react";
import { createResource, Resource } from "./resources";