From bed2a772329d3f503db4744297452c50417274f9 Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Mon, 29 Jul 2024 20:32:59 +0530 Subject: [PATCH] feat: implement feature of multisupport language --- apps/OpenSign/package-lock.json | 93 ++++++++++++++++++- apps/OpenSign/package.json | 4 + .../public/locales/en/translation.json | 20 ++++ .../public/locales/fr/translation.json | 20 ++++ apps/OpenSign/src/i18n.js | 20 ++++ apps/OpenSign/src/index.js | 3 +- apps/OpenSign/src/pages/UserProfile.js | 53 +++++++++-- apps/OpenSign/src/script/PublicTemplate.js | 8 +- 8 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 apps/OpenSign/public/locales/en/translation.json create mode 100644 apps/OpenSign/public/locales/fr/translation.json create mode 100644 apps/OpenSign/src/i18n.js diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index 7ba367ff7..bf1031f0b 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -15,6 +15,9 @@ "@reduxjs/toolkit": "^2.2.6", "axios": "^1.7.2", "file-saver": "^2.0.5", + "i18next": "^23.12.2", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-http-backend": "^2.5.2", "jwt-decode": "^4.0.0", "moment": "^2.30.1", "nth-check": "^2.1.1", @@ -34,6 +37,7 @@ "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", "react-helmet": "^6.1.0", + "react-i18next": "^15.0.0", "react-konva": "^18.2.10", "react-pdf": "^9.1.0", "react-quill": "^2.0.0", @@ -2003,9 +2007,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -16579,6 +16583,14 @@ "node": ">= 12" } }, + "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/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -16739,6 +16751,52 @@ "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.10.4.tgz", "integrity": "sha512-SejXzIpv9gOVdDWXd4suM1fdF1k2dxZGvuTdkOVLoazYfK7O4DykIQbdrvuyG+EaTNlXAGhMndtKrhykgbt0gg==" }, + "node_modules/i18next": { + "version": "23.12.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.12.2.tgz", + "integrity": "sha512-XIeh5V+bi8SJSWGL3jqbTEBW5oD6rbP5L+E7dVQh1MNTxxYef0x15rhJVcRb7oiuq4jLtgy2SD8eFlf6P2cmqg==", + "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.23.2" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", + "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz", + "integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, + "node_modules/i18next-http-backend/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -24327,6 +24385,27 @@ "react": ">=16.3.0" } }, + "node_modules/react-i18next": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.0.tgz", + "integrity": "sha512-2O3IgF4zivg57Q6p6i+ChDgJ371IDcEWbuWC6gvoh5NbkDMs0Q+O7RPr4v61+Se32E0V+LmtwePAeqWZW0bi6g==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -28410,6 +28489,14 @@ "node": ">= 6" } }, + "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/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index 45295d609..4572be0b1 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -10,6 +10,9 @@ "@reduxjs/toolkit": "^2.2.6", "axios": "^1.7.2", "file-saver": "^2.0.5", + "i18next": "^23.12.2", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-http-backend": "^2.5.2", "jwt-decode": "^4.0.0", "moment": "^2.30.1", "nth-check": "^2.1.1", @@ -29,6 +32,7 @@ "react-dom": "^18.2.0", "react-gtm-module": "^2.0.11", "react-helmet": "^6.1.0", + "react-i18next": "^15.0.0", "react-konva": "^18.2.10", "react-pdf": "^9.1.0", "react-quill": "^2.0.0", diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json new file mode 100644 index 000000000..61b9382ac --- /dev/null +++ b/apps/OpenSign/public/locales/en/translation.json @@ -0,0 +1,20 @@ +{ + "create-account": "Create account", + "login": "Login", + "language":"Language", + "name":"Name", + "phone":"Phone", + "email":"Email", + "company":"Company", + "job-title":"Job title", + "is-email-verified":"Is Email verified", + "public-profile":"Public profile", + "tagline":"Tagline ", + "has-requested-you-to-sign":"has requested you to sign", + "has-requested-you-to-review-and-sign":" has requested you to review and sign", + "ascending":"Ascending", + "Action":"Action", + "add":"add", + "add-new-folder":"ajouter un nouveau dossier" + } + \ No newline at end of file diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json new file mode 100644 index 000000000..7b0894916 --- /dev/null +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -0,0 +1,20 @@ +{ + "create account": "Créer un compte", + "login": "se connecter", + "language":"Langue", + "name":"Nom", + "phone":"Téléphone", + "email":"E-mail", + "company":"Entreprise", + "job-title":"Titre d'emploi", + "is-email-verified":"L'e-mail est-il vérifié", + "public-profile":"Profil public", + "tagline":"Slogan", + "has-requested-you-to-sign":" vous a demandé de signer", + "has-requested-you-to-review-and-sign":"vous a demandé de consulter et de signer", + "Ascending":"Ascendant", + "Action":"Action", + "add":"ajouter", + "add-new-folder":"add new folder" + } + \ No newline at end of file diff --git a/apps/OpenSign/src/i18n.js b/apps/OpenSign/src/i18n.js new file mode 100644 index 000000000..697dc3b08 --- /dev/null +++ b/apps/OpenSign/src/i18n.js @@ -0,0 +1,20 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import Backend from "i18next-http-backend"; +import LanguageDetector from "i18next-browser-languagedetector"; + +i18n + .use(Backend) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + lng: "en", // Set English as the default language + fallbackLng: "en", // Fallback to English if no other language is detected + debug: true, + interpolation: { + escapeValue: false // Not needed for react as it escapes by default + }, + whitelist: ["en", "fr"] // List of allowed languages + }); + +export default i18n; diff --git a/apps/OpenSign/src/index.js b/apps/OpenSign/src/index.js index f11064560..4b6b18061 100644 --- a/apps/OpenSign/src/index.js +++ b/apps/OpenSign/src/index.js @@ -16,7 +16,8 @@ import { import DragElement from "./components/pdf/DragElement"; import TagManager from "react-gtm-module"; import Parse from "parse"; -import './polyfills' +import "./polyfills"; +import "./i18n"; const appId = process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign"; diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index df48555cf..d3228d5d8 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -16,9 +16,11 @@ import { import Upgrade from "../primitives/Upgrade"; import ModalUi from "../primitives/ModalUi"; import Loader from "../primitives/Loader"; +import { useTranslation } from "react-i18next"; function UserProfile() { const navigate = useNavigate(); + const { t, i18n } = useTranslation(); let UserProfile = JSON.parse(localStorage.getItem("UserInformation")); let extendUser = JSON.parse(localStorage.getItem("Extand_Class")); const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); @@ -51,6 +53,12 @@ function UserProfile() { extendUser && extendUser?.[0]?.Tagline ); const [isTeam, setIsTeam] = useState(false); + const languages = [ + { value: "en", text: "English" }, + { value: "fr", text: "French" } + ]; + const [lang, setLang] = useState("en"); + useEffect(() => { getUserDetail(); }, []); @@ -303,6 +311,12 @@ function UserProfile() { setJobTitle(extendUser?.[0]?.JobTitle); setIsDisableDocId(extendUser?.[0]?.HeaderDocId); }; + // This function put query that helps to + // change the language + const handleChangeLang = (e) => { + setLang(e.target.value); + i18n.changeLanguage(e.target.value); + }; return ( @@ -360,7 +374,30 @@ function UserProfile() { editmode ? "py-1.5" : "py-2" }`} > - <span className="font-semibold">Name:</span>{" "} + <span className="font-semibold">{t("language")}:</span>{" "} + <select + value={lang} + onChange={handleChangeLang} + className="select select-bordered w-[30%] border-[1px] max-w-xs" + > + <option disabled selected> + select + </option> + {languages.map((item) => { + return ( + <option key={item.value} value={item.value}> + {item.text} + </option> + ); + })} + </select> + </li> + <li + className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${ + editmode ? "py-1.5" : "py-2" + }`} + > + <span className="font-semibold">{t("name")}:</span>{" "} {editmode ? ( <input type="text" @@ -377,7 +414,7 @@ function UserProfile() { editmode ? "py-1.5" : "py-2" }`} > - <span className="font-semibold">Phone:</span>{" "} + <span className="font-semibold">{t("phone")}:</span>{" "} {editmode ? ( <input type="text" @@ -390,7 +427,7 @@ function UserProfile() { )} </li> <li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> - <span className="font-semibold">Email:</span>{" "} + <span className="font-semibold">{t("email")}:</span>{" "} <span>{UserProfile && UserProfile.email}</span> </li> <li @@ -398,7 +435,7 @@ function UserProfile() { editmode ? "py-1.5" : "py-2" }`} > - <span className="font-semibold">Company:</span>{" "} + <span className="font-semibold">{t("company")}:</span>{" "} {editmode ? ( <input type="text" @@ -415,7 +452,7 @@ function UserProfile() { editmode ? "py-1.5" : "py-2" }`} > - <span className="font-semibold">Job title:</span>{" "} + <span className="font-semibold">{t("job-title")}:</span>{" "} {editmode ? ( <input type="text" @@ -428,7 +465,7 @@ function UserProfile() { )} </li> <li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all"> - <span className="font-semibold">Is Email verified:</span>{" "} + <span className="font-semibold">{t("is-email-verified")}:</span>{" "} <span> {isEmailVerified ? ( "Verified" @@ -450,7 +487,7 @@ function UserProfile() { <> <li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all"> <span className="font-semibold flex gap-1"> - Public profile :{" "} + {t("public-profile")} :{" "} <Tooltip maxWidth="max-w-[250px]" message={`This is your public URL. Copy or share it with the signer, and you will be able to see all your publicly set templates.`} @@ -486,7 +523,7 @@ function UserProfile() { </li> <li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all"> <span className="font-semibold flex gap-1"> - Tagline :{" "} + {t("tagline")} :{" "} <Tooltip maxWidth="max-w-[250px]" message={`This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex`} diff --git a/apps/OpenSign/src/script/PublicTemplate.js b/apps/OpenSign/src/script/PublicTemplate.js index 3ef08df4c..c76252f6b 100644 --- a/apps/OpenSign/src/script/PublicTemplate.js +++ b/apps/OpenSign/src/script/PublicTemplate.js @@ -18,9 +18,11 @@ const PublicScriptFileWrapper = ({ initialProps }) => { return <PdfRequestFiles {...props} />; }; -const appId = "legadranaxn"; -// "opensign"; -const serverUrl = "https://app.opensignlabs.com/api/app"; +const appId = + //"legadranaxn"; + "opensign"; +const serverUrl = "http://localhost:8080/app"; +//"https://app.opensignlabs.com/api/app"; // "https://staging-app.opensignlabs.com/api/app"; localStorage.setItem("baseUrl", `${serverUrl}/`); localStorage.setItem("parseAppId", appId);