diff --git a/web/global.d.ts b/web/global.d.ts index 2fa15462b..3cc0c7de1 100644 --- a/web/global.d.ts +++ b/web/global.d.ts @@ -10,11 +10,25 @@ declare global { const path: string; export default path; } + interface Window { + google: { + translate: { + TranslateElement: new ( + config: { + pageLanguage: string; + includedLanguages: string; + }, + elementId: string + ) => void; + }; + }; + googleTranslateElementInit: () => void; + } } declare module "styled-components" { type Theme = typeof lightTheme; - //eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface DefaultTheme extends Theme {} } diff --git a/web/src/app.tsx b/web/src/app.tsx index 23a158b6c..2c52cdd79 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -25,6 +25,7 @@ import Loader from "components/Loader"; import Layout from "layout/index"; import ErrorFallback from "./components/ErrorFallback"; +import TranslateProvider from "./context/TranslateProvider"; import { SentryRoutes } from "./utils/sentry"; const App: React.FC = () => { @@ -37,67 +38,69 @@ const App: React.FC = () => { - - }> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> - - + + + }> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> + + + diff --git a/web/src/components/ConnectWallet/AccountDisplay.tsx b/web/src/components/ConnectWallet/AccountDisplay.tsx index 2a415237a..b0b3a2ccb 100644 --- a/web/src/components/ConnectWallet/AccountDisplay.tsx +++ b/web/src/components/ConnectWallet/AccountDisplay.tsx @@ -140,13 +140,13 @@ export const AddressOrName: React.FC = ({ address: propAddress } chainId: 1, }); - return ; + return ; }; export const ChainDisplay: React.FC = () => { const chainId = useChainId(); const chain = getChain(chainId); - return ; + return ; }; const AccountDisplay: React.FC = () => { diff --git a/web/src/components/EvidenceCard.tsx b/web/src/components/EvidenceCard.tsx index 75eb614d8..44fcd3e6d 100644 --- a/web/src/components/EvidenceCard.tsx +++ b/web/src/components/EvidenceCard.tsx @@ -177,7 +177,7 @@ const EvidenceCard: React.FC = ({ - +

{shortenAddress(sender)}

diff --git a/web/src/components/TranslateDropdown.tsx b/web/src/components/TranslateDropdown.tsx new file mode 100644 index 000000000..c23b57308 --- /dev/null +++ b/web/src/components/TranslateDropdown.tsx @@ -0,0 +1,34 @@ +import React from "react"; + +import { DropdownSelect } from "@kleros/ui-components-library"; + +import { SupportedLangs, useTranslate } from "context/TranslateProvider"; + +const Langs: { value: SupportedLangs; text: string }[] = [ + { text: "English", value: "en" }, + { text: "Spanish", value: "es" }, + { text: "Hindi", value: "hi" }, + { text: "Japanese", value: "ja" }, + { text: "Korean", value: "ko" }, + { text: "French", value: "fr" }, +]; + +const TranslateDropdown: React.FC = () => { + const { currentLang, setLang } = useTranslate(); + return ( + ({ + value: range.value, + text: range.text, + }))} + defaultValue={currentLang} + callback={(val) => { + setLang(val as SupportedLangs); + }} + /> + ); +}; + +export default TranslateDropdown; diff --git a/web/src/context/TranslateProvider.tsx b/web/src/context/TranslateProvider.tsx new file mode 100644 index 000000000..280a83db7 --- /dev/null +++ b/web/src/context/TranslateProvider.tsx @@ -0,0 +1,73 @@ +import React, { createContext, useCallback, useContext, useEffect, useMemo } from "react"; + +import { useLocalStorage } from "hooks/useLocalStorage"; + +export type SupportedLangs = "en" | "es" | "fr" | "hi" | "ko" | "ja"; + +interface ITranslate { + currentLang: SupportedLangs; + setLang: (lang: SupportedLangs) => void; +} +const TranslateContext = createContext(undefined); + +export const useTranslate = () => { + const context = useContext(TranslateContext); + if (!context) { + throw new Error("Context Provider not found."); + } + return context; +}; + +export const TranslateProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [currentLang, setCurrentLang] = useLocalStorage("lang", "en"); + + useEffect(() => { + try { + const existingScript = document.querySelector('script[src*="translate.google.com/translate_a/element.js"]'); + if (!existingScript) { + const addScript = document.createElement("script"); + addScript.setAttribute("src", "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"); + document.body.appendChild(addScript); + + window.googleTranslateElementInit = () => { + new window.google.translate.TranslateElement( + { + pageLanguage: "en", + includedLanguages: "en,es,hi,ja,fr,ko", + }, + "google_translate_element" + ); + }; + } + } catch (err) { + // eslint-disable-next-line no-console + console.log("Error injecting google translate script", err); + } + }, []); + + const setLang = useCallback( + (cValue: SupportedLangs) => { + setCurrentLang(cValue); + document.cookie = "googtrans" + "=" + `/en/${cValue}` + ";" + "Session" + ";path=/"; + if (window.google?.translate?.TranslateElement) { + const select = document.querySelector(".goog-te-combo") as HTMLSelectElement; + if (select) { + select.value = cValue; + + select.dispatchEvent(new Event("change", { bubbles: true })); + select.click(); + } + } + }, + [setCurrentLang] + ); + + return ( + ({ currentLang, setLang }), [currentLang, setLang])}> +
+ {children} +
+ ); +}; + +export default TranslateProvider; diff --git a/web/src/layout/Header/navbar/Menu/Settings/General.tsx b/web/src/layout/Header/navbar/Menu/Settings/General.tsx index 398f6673d..6b75187fb 100644 --- a/web/src/layout/Header/navbar/Menu/Settings/General.tsx +++ b/web/src/layout/Header/navbar/Menu/Settings/General.tsx @@ -7,12 +7,14 @@ import { Button } from "@kleros/ui-components-library"; import { AddressOrName, ChainDisplay, IdenticonOrAvatar } from "components/ConnectWallet/AccountDisplay"; import { EnsureChain } from "components/EnsureChain"; +import TranslateDropdown from "components/TranslateDropdown"; const Container = styled.div` display: flex; flex-direction: column; justify-content: center; margin-top: 12px; + align-items: center; `; const StyledChainContainer = styled.div` @@ -57,6 +59,9 @@ const StyledButton = styled.div` const EnsureChainContainer = styled.div` display: flex; + flex-direction: column; + align-items: center; + gap: 16px; justify-content: center; padding: 16px; `; @@ -93,6 +98,7 @@ const General: React.FC = () => { return ( + {address && ( diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx index 4eaed0799..8d9836fd4 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx @@ -3,8 +3,8 @@ import styled, { css } from "styled-components"; import Identicon from "react-identicons"; -import { Answer } from "context/NewDisputeContext"; import { DEFAULT_CHAIN, getChain } from "consts/chains"; +import { Answer } from "context/NewDisputeContext"; import { getVoteChoice } from "utils/getVoteChoice"; import { isUndefined } from "utils/index"; import { shortenAddress } from "utils/shortenAddress"; @@ -94,7 +94,7 @@ const AccordionTitle: React.FC<{ return ( - + {shortenAddress(juror)} diff --git a/web/src/styles/global-style.ts b/web/src/styles/global-style.ts index cb5f5caa0..4b3f06901 100644 --- a/web/src/styles/global-style.ts +++ b/web/src/styles/global-style.ts @@ -17,6 +17,7 @@ export const GlobalStyle = createGlobalStyle` body { font-family: "Open Sans", sans-serif; margin: 0px; + top:0px !important } html { @@ -120,4 +121,15 @@ export const GlobalStyle = createGlobalStyle` .hiddenCanvasElement{ display: none; } + + //hide-default-google-translate +.skiptranslate{ + display: none !important ; + visibility: hidden !important; + }; + +font{ + background-color: transparent !important; + box-shadow: none !important ; +} `; diff --git a/web/tsconfig.json b/web/tsconfig.json index fae4af75b..543ee43c4 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -66,7 +66,8 @@ "noImplicitAny": false, "resolveJsonModule": true, "lib": [ - "ESNext.Array" + "ESNext.Array", + "DOM" ], "types": [ "vite/client",