Skip to content

Commit 1c20e01

Browse files
feat(web): google-translate
1 parent 49932e2 commit 1c20e01

File tree

6 files changed

+183
-62
lines changed

6 files changed

+183
-62
lines changed

web/src/app.tsx

+64-61
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Web3Provider from "context/Web3Provider";
2222
import Loader from "components/Loader";
2323
import Layout from "layout/index";
2424

25+
import TranslateProvider from "./context/TranslateProvider";
2526
import { SentryRoutes } from "./utils/sentry";
2627

2728
const App: React.FC = () => {
@@ -33,67 +34,69 @@ const App: React.FC = () => {
3334
<AtlasProvider>
3435
<IsListProvider>
3536
<NewDisputeProvider>
36-
<SentryRoutes>
37-
<Route path="/" element={<Layout />}>
38-
<Route
39-
index
40-
element={
41-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
42-
<Home />
43-
</Suspense>
44-
}
45-
/>
46-
<Route
47-
path="cases/*"
48-
element={
49-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
50-
<Cases />
51-
</Suspense>
52-
}
53-
/>
54-
<Route
55-
path="courts/*"
56-
element={
57-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
58-
<Courts />
59-
</Suspense>
60-
}
61-
/>
62-
<Route
63-
path="dashboard/:page/:order/:filter"
64-
element={
65-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
66-
<Dashboard />
67-
</Suspense>
68-
}
69-
/>
70-
<Route
71-
path="resolver/*"
72-
element={
73-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
74-
<DisputeResolver />
75-
</Suspense>
76-
}
77-
/>
78-
<Route
79-
path="get-pnk/*"
80-
element={
81-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
82-
<GetPnk />
83-
</Suspense>
84-
}
85-
/>
86-
<Route
87-
path="settings/*"
88-
element={
89-
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
90-
<Settings />
91-
</Suspense>
92-
}
93-
/>
94-
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
95-
</Route>
96-
</SentryRoutes>
37+
<TranslateProvider>
38+
<SentryRoutes>
39+
<Route path="/" element={<Layout />}>
40+
<Route
41+
index
42+
element={
43+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
44+
<Home />
45+
</Suspense>
46+
}
47+
/>
48+
<Route
49+
path="cases/*"
50+
element={
51+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
52+
<Cases />
53+
</Suspense>
54+
}
55+
/>
56+
<Route
57+
path="courts/*"
58+
element={
59+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
60+
<Courts />
61+
</Suspense>
62+
}
63+
/>
64+
<Route
65+
path="dashboard/:page/:order/:filter"
66+
element={
67+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
68+
<Dashboard />
69+
</Suspense>
70+
}
71+
/>
72+
<Route
73+
path="resolver/*"
74+
element={
75+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
76+
<DisputeResolver />
77+
</Suspense>
78+
}
79+
/>
80+
<Route
81+
path="get-pnk/*"
82+
element={
83+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
84+
<GetPnk />
85+
</Suspense>
86+
}
87+
/>
88+
<Route
89+
path="settings/*"
90+
element={
91+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
92+
<Settings />
93+
</Suspense>
94+
}
95+
/>
96+
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
97+
</Route>
98+
</SentryRoutes>
99+
</TranslateProvider>
97100
</NewDisputeProvider>
98101
</IsListProvider>
99102
</AtlasProvider>
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from "react";
2+
3+
import { DropdownSelect } from "@kleros/ui-components-library";
4+
5+
import { SupportedLangs, useTranslate } from "context/TranslateProvider";
6+
7+
const Langs: { value: SupportedLangs; text: string }[] = [
8+
{ text: "en", value: "en" },
9+
{ text: "es", value: "es" },
10+
{ text: "hi", value: "hi" },
11+
{ text: "js", value: "ja" },
12+
{ text: "zh", value: "zh" },
13+
{ text: "ko", value: "ko" },
14+
{ text: "fr", value: "fr" },
15+
];
16+
17+
const TranslateDropdown: React.FC = () => {
18+
const { setLang } = useTranslate();
19+
return (
20+
<DropdownSelect
21+
smallButton
22+
simpleButton
23+
items={Langs.map((range) => ({
24+
value: range.value,
25+
text: range.text,
26+
}))}
27+
defaultValue={"en"}
28+
callback={(val) => {
29+
//@ts-expect-error is string
30+
setLang(val);
31+
}}
32+
/>
33+
);
34+
};
35+
36+
export default TranslateDropdown;

web/src/context/TranslateProvider.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React, { createContext, useCallback, useContext, useEffect, useMemo } from "react";
2+
3+
import { useLocalStorage } from "hooks/useLocalStorage";
4+
5+
export type SupportedLangs = "en" | "es" | "zh" | "fr" | "hi" | "ko" | "ja";
6+
7+
interface ITranslate {
8+
currentLang: SupportedLangs;
9+
setLang: (lang: SupportedLangs) => void;
10+
}
11+
const TranslateContext = createContext<ITranslate | undefined>(undefined);
12+
13+
export const useTranslate = () => {
14+
const context = useContext(TranslateContext);
15+
if (!context) {
16+
throw new Error("Context Provider not found.");
17+
}
18+
return context;
19+
};
20+
21+
export const TranslateProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
22+
const [currentLang, setCurrentLang] = useLocalStorage<SupportedLangs>("lang", "en");
23+
24+
useEffect(() => {
25+
try {
26+
// Check if the Google Translate script is already in the document
27+
const existingScript = document.querySelector('script[src*="translate.google.com/translate_a/element.js"]');
28+
if (!existingScript) {
29+
const addScript = document.createElement("script");
30+
addScript.setAttribute("src", "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit");
31+
document.body.appendChild(addScript);
32+
33+
//@ts-expect-error will exist
34+
window.googleTranslateElementInit = () => {
35+
//@ts-expect-error will exist
36+
new window.google.translate.TranslateElement(
37+
{
38+
pageLanguage: "en",
39+
includedLanguages: "en,es,hi,ja,zh,fr,ko", // Include all languages you need here
40+
},
41+
"google_translate_element"
42+
);
43+
};
44+
}
45+
} catch (err) {
46+
// eslint-disable-next-line no-console
47+
console.log("Error injecting google translate script", err);
48+
}
49+
}, []);
50+
51+
const setLang = useCallback(
52+
(cValue: SupportedLangs) => {
53+
setCurrentLang(cValue);
54+
document.cookie = "googtrans" + "=" + `/en/${cValue}` + ";" + "Session" + ";path=/";
55+
window.location.reload();
56+
},
57+
[setCurrentLang]
58+
);
59+
60+
return (
61+
<TranslateContext.Provider value={useMemo(() => ({ currentLang, setLang }), [currentLang, setLang])}>
62+
<div id="google_translate_element"></div>
63+
{children}
64+
</TranslateContext.Provider>
65+
);
66+
};
67+
68+
export default TranslateProvider;

web/src/layout/Header/navbar/Menu/Settings/General.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import { Button } from "@kleros/ui-components-library";
77

88
import { AddressOrName, ChainDisplay, IdenticonOrAvatar } from "components/ConnectWallet/AccountDisplay";
99
import { EnsureChain } from "components/EnsureChain";
10+
import TranslateDropdown from "components/TranslateDropdown";
1011

1112
const Container = styled.div`
1213
display: flex;
1314
flex-direction: column;
1415
justify-content: center;
1516
margin-top: 12px;
17+
align-items: center;
1618
`;
1719

1820
const StyledChainContainer = styled.div`
@@ -57,6 +59,9 @@ const StyledButton = styled.div`
5759

5860
const EnsureChainContainer = styled.div`
5961
display: flex;
62+
flex-direction: column;
63+
align-items: center;
64+
gap: 16px;
6065
justify-content: center;
6166
padding: 16px;
6267
`;
@@ -93,6 +98,7 @@ const General: React.FC = () => {
9398

9499
return (
95100
<EnsureChainContainer>
101+
<TranslateDropdown />
96102
<EnsureChain>
97103
<Container>
98104
{address && (

web/src/styles/global-style.ts

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const GlobalStyle = createGlobalStyle`
1717
body {
1818
font-family: "Open Sans", sans-serif;
1919
margin: 0px;
20+
top:0px !important
2021
}
2122
2223
html {
@@ -120,4 +121,10 @@ export const GlobalStyle = createGlobalStyle`
120121
.hiddenCanvasElement{
121122
display: none;
122123
}
124+
125+
//hide-default-google-translate
126+
.skiptranslate{
127+
display: none;
128+
};
129+
123130
`;

web/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
"noImplicitAny": false,
6767
"resolveJsonModule": true,
6868
"lib": [
69-
"ESNext.Array"
69+
"ESNext.Array",
70+
"DOM"
7071
],
7172
"types": [
7273
"vite/client",

0 commit comments

Comments
 (0)