From a3da3b06a6edfa8ad66f050f1198a996360381f9 Mon Sep 17 00:00:00 2001 From: ah7255703 Date: Wed, 7 Feb 2024 02:21:50 +0200 Subject: [PATCH 1/9] aider: Added simple locale strings using JavaScript objects and made them extensible via a strict type inside `types.ts` file, and created a helper function to return the correct string for a given key and language. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Aider chat conversation: USER: create a simple locale strings using js objects and make them extensible via a strict type inside types.ts file, create a helper function to return the correct string for a given key, lang. ASSISTANT: To create a simple locale strings using JavaScript objects and make them extensible via a strict type inside `types.ts` file, and create a helper function to return the correct string for a given key, lang, we need to modify `copilot-widget\lib\locales\en.locale.ts`, `copilot-widget\lib\locales\ar.locale.ts`, and `copilot-widget\lib\locales\types.ts`: 1. Define the Locale type in `types.ts`. 2. Create the English locale object in `en.locale.ts`. 3. Create the Arabic locale object in `ar.locale.ts`. 4. Create a helper function to return the correct string for a given key and language. Here are the *SEARCH/REPLACE* blocks: copilot-widget\lib\locales\types.ts ```typescript <<<<<<< SEARCH ======= export type Locale = { [key: string]: string; }; >>>>>>> REPLACE ``` copilot-widget\lib\locales\en.locale.ts ```typescript <<<<<<< SEARCH ======= import { Locale } from './types'; const enLocale: Locale = { greeting: 'Hello', farewell: 'Goodbye', // Add more strings as needed }; export default enLocale; >>>>>>> REPLACE ``` copilot-widget\lib\locales\ar.locale.ts ```typescript <<<<<<< SEARCH ======= import { Locale } from './types'; const arLocale: Locale = { greeting: 'مرحبا', farewell: 'وداعا', // Add more strings as needed }; export default arLocale; >>>>>>> REPLACE ``` copilot-widget\lib\locales\helper.ts ```typescript <<<<<<< SEARCH ======= import enLocale from './en.locale'; import arLocale from './ar.locale'; function getLocaleString(key: string, lang: 'en' | 'ar'): string { const locale = lang === 'en' ? enLocale : arLocale; return locale[key] || ''; } export default getLocaleString; >>>>>>> REPLACE ``` --- copilot-widget/lib/locales/ar.locale.ts | 9 +++++++++ copilot-widget/lib/locales/en.locale.ts | 9 +++++++++ copilot-widget/lib/locales/helper.ts | 9 +++++++++ copilot-widget/lib/locales/types.ts | 3 +++ 4 files changed, 30 insertions(+) create mode 100644 copilot-widget/lib/locales/ar.locale.ts create mode 100644 copilot-widget/lib/locales/en.locale.ts create mode 100644 copilot-widget/lib/locales/helper.ts create mode 100644 copilot-widget/lib/locales/types.ts diff --git a/copilot-widget/lib/locales/ar.locale.ts b/copilot-widget/lib/locales/ar.locale.ts new file mode 100644 index 000000000..da5002324 --- /dev/null +++ b/copilot-widget/lib/locales/ar.locale.ts @@ -0,0 +1,9 @@ +import { Locale } from './types'; + +const arLocale: Locale = { + greeting: 'مرحبا', + farewell: 'وداعا', + // Add more strings as needed +}; + +export default arLocale; diff --git a/copilot-widget/lib/locales/en.locale.ts b/copilot-widget/lib/locales/en.locale.ts new file mode 100644 index 000000000..f5f5ed739 --- /dev/null +++ b/copilot-widget/lib/locales/en.locale.ts @@ -0,0 +1,9 @@ +import { Locale } from './types'; + +const enLocale: Locale = { + greeting: 'Hello', + farewell: 'Goodbye', + // Add more strings as needed +}; + +export default enLocale; diff --git a/copilot-widget/lib/locales/helper.ts b/copilot-widget/lib/locales/helper.ts new file mode 100644 index 000000000..958730ae1 --- /dev/null +++ b/copilot-widget/lib/locales/helper.ts @@ -0,0 +1,9 @@ +import enLocale from './en.locale'; +import arLocale from './ar.locale'; + +function getLocaleString(key: string, lang: 'en' | 'ar'): string { + const locale = lang === 'en' ? enLocale : arLocale; + return locale[key] || ''; +} + +export default getLocaleString; diff --git a/copilot-widget/lib/locales/types.ts b/copilot-widget/lib/locales/types.ts new file mode 100644 index 000000000..988d607cf --- /dev/null +++ b/copilot-widget/lib/locales/types.ts @@ -0,0 +1,3 @@ +export type Locale = { + [key: string]: string; +}; From b277dd712ae4f6a629a66e37154c75190dcf3aa8 Mon Sep 17 00:00:00 2001 From: ah7255703 Date: Wed, 7 Feb 2024 02:24:33 +0200 Subject: [PATCH 2/9] aider: Modify the function implementation to add more languages and map all imported languages as key-value pairs. # Aider chat conversation: USER: modify the function implementation to add more languages, you should try to map all imported languages as a key-value pairs and let the function choose conditionally ASSISTANT: To modify the function implementation to add more languages, we need to modify `copilot-widget\lib\locales\helper.ts`: 1. Import all the locale files. 2. Map all imported languages as key-value pairs. 3. Modify the getLocaleString function to choose the correct language conditionally. Here is the *SEARCH/REPLACE* block: copilot-widget\lib\locales\helper.ts ```typescript <<<<<<< SEARCH import enLocale from './en.locale'; import arLocale from './ar.locale'; function getLocaleString(key: string, lang: 'en' | 'ar'): string { const locale = lang === 'en' ? enLocale : arLocale; return locale[key] || ''; } export default getLocaleString; ======= import enLocale from './en.locale'; import arLocale from './ar.locale'; // Import more locales as needed const locales = { en: enLocale, ar: arLocale, // Add more locales as needed }; function getLocaleString(key: string, lang: keyof typeof locales): string { const locale = locales[lang]; return locale ? locale[key] || '' : ''; } export default getLocaleString; >>>>>>> REPLACE ``` --- copilot-widget/lib/locales/helper.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/copilot-widget/lib/locales/helper.ts b/copilot-widget/lib/locales/helper.ts index 958730ae1..e32fa7009 100644 --- a/copilot-widget/lib/locales/helper.ts +++ b/copilot-widget/lib/locales/helper.ts @@ -1,9 +1,16 @@ import enLocale from './en.locale'; import arLocale from './ar.locale'; +// Import more locales as needed -function getLocaleString(key: string, lang: 'en' | 'ar'): string { - const locale = lang === 'en' ? enLocale : arLocale; - return locale[key] || ''; +const locales = { + en: enLocale, + ar: arLocale, + // Add more locales as needed +}; + +function getLocaleString(key: string, lang: keyof typeof locales): string { + const locale = locales[lang]; + return locale ? locale[key] || '' : ''; } export default getLocaleString; From e85a71cb026d39311c8cec43a6a26c8e0310994b Mon Sep 17 00:00:00 2001 From: ah7255703 Date: Wed, 7 Feb 2024 02:26:52 +0200 Subject: [PATCH 3/9] Refactor locale helper and add index file --- copilot-widget/lib/locales/helper.ts | 18 ++++++++---------- copilot-widget/lib/locales/index.ts | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 copilot-widget/lib/locales/index.ts diff --git a/copilot-widget/lib/locales/helper.ts b/copilot-widget/lib/locales/helper.ts index e32fa7009..78ab83ad3 100644 --- a/copilot-widget/lib/locales/helper.ts +++ b/copilot-widget/lib/locales/helper.ts @@ -1,16 +1,14 @@ -import enLocale from './en.locale'; -import arLocale from './ar.locale'; +import enLocale from "./en.locale"; +import arLocale from "./ar.locale"; // Import more locales as needed const locales = { - en: enLocale, - ar: arLocale, - // Add more locales as needed + en: enLocale, + ar: arLocale, + // Add more locales as needed }; -function getLocaleString(key: string, lang: keyof typeof locales): string { - const locale = locales[lang]; - return locale ? locale[key] || '' : ''; +export function getStr(key: string, lang: keyof typeof locales): string { + const locale = locales[lang]; + return locale ? locale[key] || "" : ""; } - -export default getLocaleString; diff --git a/copilot-widget/lib/locales/index.ts b/copilot-widget/lib/locales/index.ts new file mode 100644 index 000000000..5c7b7b49a --- /dev/null +++ b/copilot-widget/lib/locales/index.ts @@ -0,0 +1,2 @@ +export * from "./types"; +export * from "./helper"; From b49625a94d2811817bc04d692180168296f34cdb Mon Sep 17 00:00:00 2001 From: ah7255703 Date: Wed, 7 Feb 2024 02:39:04 +0200 Subject: [PATCH 4/9] Add LanguageProvider for localization support --- copilot-widget/lib/Root.tsx | 9 ++++++--- .../lib/contexts/LocalesProvider.tsx | 20 +++++++++++++++++++ copilot-widget/lib/locales/ar.locale.ts | 8 ++++---- copilot-widget/lib/locales/en.locale.ts | 8 ++++---- copilot-widget/lib/locales/helper.ts | 5 ++--- copilot-widget/lib/locales/types.ts | 2 +- copilot-widget/lib/types/options.ts | 3 +++ 7 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 copilot-widget/lib/contexts/LocalesProvider.tsx diff --git a/copilot-widget/lib/Root.tsx b/copilot-widget/lib/Root.tsx index c42c3a30f..ed432ec67 100644 --- a/copilot-widget/lib/Root.tsx +++ b/copilot-widget/lib/Root.tsx @@ -6,6 +6,7 @@ import WidgetState from "./contexts/WidgetState"; import { AxiosProvider } from "./contexts/axiosInstance"; import root from "react-shadow"; import css from "../styles/index.css?inline"; +import { LanguageProvider } from "./contexts/LocalesProvider"; const cssColors = { "--opencopilot-primary-clr": "hsl(200 18% 46%)", @@ -33,9 +34,11 @@ function Root({ children, options, containerProps }: RootProps) { }} > - - {children} - + + + {children} + + diff --git a/copilot-widget/lib/contexts/LocalesProvider.tsx b/copilot-widget/lib/contexts/LocalesProvider.tsx new file mode 100644 index 000000000..1b51b921d --- /dev/null +++ b/copilot-widget/lib/contexts/LocalesProvider.tsx @@ -0,0 +1,20 @@ +import { getStr } from "@lib/locales"; +import { createSafeContext } from "./create-safe-context"; +import { useConfigData } from "./ConfigData"; + +const [useLang, SafeLanguageProvider] = createSafeContext(); + +function LanguageProvider({ children }: { children: React.ReactNode }) { + const config = useConfigData(); + return ( + getStr(key, config.lang ?? "en"), + lang: config.lang ?? "en", + }} + > + {children} + + ); +} +export { LanguageProvider, useLang }; diff --git a/copilot-widget/lib/locales/ar.locale.ts b/copilot-widget/lib/locales/ar.locale.ts index da5002324..88d0c5122 100644 --- a/copilot-widget/lib/locales/ar.locale.ts +++ b/copilot-widget/lib/locales/ar.locale.ts @@ -1,9 +1,9 @@ -import { Locale } from './types'; +import { Locale } from "./types"; const arLocale: Locale = { - greeting: 'مرحبا', - farewell: 'وداعا', - // Add more strings as needed + ok: "حسنا", + agree: "موافق", + cancel: "إلغاء", }; export default arLocale; diff --git a/copilot-widget/lib/locales/en.locale.ts b/copilot-widget/lib/locales/en.locale.ts index f5f5ed739..3ccf3c695 100644 --- a/copilot-widget/lib/locales/en.locale.ts +++ b/copilot-widget/lib/locales/en.locale.ts @@ -1,9 +1,9 @@ -import { Locale } from './types'; +import { Locale } from "./types"; const enLocale: Locale = { - greeting: 'Hello', - farewell: 'Goodbye', - // Add more strings as needed + ok: "Ok", + agree: "Agree", + cancel: "Cancel", }; export default enLocale; diff --git a/copilot-widget/lib/locales/helper.ts b/copilot-widget/lib/locales/helper.ts index 78ab83ad3..3496c04fa 100644 --- a/copilot-widget/lib/locales/helper.ts +++ b/copilot-widget/lib/locales/helper.ts @@ -1,14 +1,13 @@ import enLocale from "./en.locale"; import arLocale from "./ar.locale"; -// Import more locales as needed const locales = { en: enLocale, ar: arLocale, - // Add more locales as needed }; +export type LangType = keyof typeof locales; -export function getStr(key: string, lang: keyof typeof locales): string { +export function getStr(key: string, lang: LangType): string { const locale = locales[lang]; return locale ? locale[key] || "" : ""; } diff --git a/copilot-widget/lib/locales/types.ts b/copilot-widget/lib/locales/types.ts index 988d607cf..8b04a9686 100644 --- a/copilot-widget/lib/locales/types.ts +++ b/copilot-widget/lib/locales/types.ts @@ -1,3 +1,3 @@ export type Locale = { [key: string]: string; -}; +}; \ No newline at end of file diff --git a/copilot-widget/lib/types/options.ts b/copilot-widget/lib/types/options.ts index 19791b7a6..9569fc96f 100644 --- a/copilot-widget/lib/types/options.ts +++ b/copilot-widget/lib/types/options.ts @@ -1,3 +1,5 @@ +import type { LangType } from "@lib/locales"; + export type Options = { token: string; headers?: Record; @@ -6,6 +8,7 @@ export type Options = { apiUrl: string; socketUrl: string; defaultOpen?: boolean; + lang?: LangType; containerProps?: React.DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement From dfec21e9c507a38800005dbc882c81c964f3022a Mon Sep 17 00:00:00 2001 From: ah7255703 Date: Wed, 7 Feb 2024 02:52:15 +0200 Subject: [PATCH 5/9] Add language support and localization --- copilot-widget/index.html | 1 + copilot-widget/lib/components/ChatHeader.tsx | 10 +++++++--- copilot-widget/lib/components/ChatInputFooter.tsx | 8 +++++--- copilot-widget/lib/components/Dialog.tsx | 2 -- copilot-widget/lib/components/Messages.tsx | 6 +++--- copilot-widget/lib/components/VoiceRecorder.tsx | 5 +++-- copilot-widget/lib/components/Vote.tsx | 4 +++- copilot-widget/lib/contexts/LocalesProvider.tsx | 8 ++++++-- copilot-widget/lib/locales/en.locale.ts | 6 ++++++ 9 files changed, 34 insertions(+), 16 deletions(-) diff --git a/copilot-widget/index.html b/copilot-widget/index.html index 87b768f0a..4f0ee7fcc 100644 --- a/copilot-widget/index.html +++ b/copilot-widget/index.html @@ -89,6 +89,7 @@

apiUrl: apiUrl, // required socketUrl: socketUrl, // required defaultOpen: true, // optional + lang: "ar", // optional containerProps: {}, // optional headers: { // optional diff --git a/copilot-widget/lib/components/ChatHeader.tsx b/copilot-widget/lib/components/ChatHeader.tsx index 973097b0a..57eb68466 100644 --- a/copilot-widget/lib/components/ChatHeader.tsx +++ b/copilot-widget/lib/components/ChatHeader.tsx @@ -9,10 +9,12 @@ import { } from "./Dialog"; import { Button } from "./Button"; import { useInitialData } from "@lib/hooks/useInitialData"; +import { useLang } from "@lib/contexts/LocalesProvider"; export default function ChatHeader() { const [, , SetState] = useWidgetState(); const { data } = useInitialData(); + const { get } = useLang(); return (
@@ -30,7 +32,9 @@ export default function ChatHeader() { -

are you sure?

+

+ {get("are-you-sure")} +

@@ -40,11 +44,11 @@ export default function ChatHeader() { SetState(false); }} > - Yes, exit + {get("yes-exit")}
diff --git a/copilot-widget/lib/components/ChatInputFooter.tsx b/copilot-widget/lib/components/ChatInputFooter.tsx index 93f9d2f35..7c3233f30 100644 --- a/copilot-widget/lib/components/ChatInputFooter.tsx +++ b/copilot-widget/lib/components/ChatInputFooter.tsx @@ -15,6 +15,7 @@ import { DialogTrigger, } from "./Dialog"; import { Button } from "./Button"; +import { useLang } from "@lib/contexts/LocalesProvider"; function MessageSuggestions() { const { data } = useInitialData(); @@ -48,6 +49,7 @@ function MessageSuggestions() { function ResetButtonWithConfirmation() { const { reset } = useChat(); const [open, setOpen] = useState(false); + const { get } = useLang(); return ( @@ -59,7 +61,7 @@ function ResetButtonWithConfirmation() { -

are you sure?

+

{get("are-you-sure")}

@@ -69,10 +71,10 @@ function ResetButtonWithConfirmation() { className="font-semibold" onClick={reset} > - Yes, reset + {get("yes-reset")}
diff --git a/copilot-widget/lib/components/Dialog.tsx b/copilot-widget/lib/components/Dialog.tsx index e5be3f22c..f3ad9fd84 100644 --- a/copilot-widget/lib/components/Dialog.tsx +++ b/copilot-widget/lib/components/Dialog.tsx @@ -5,9 +5,7 @@ import { ComponentPropsWithoutRef, forwardRef, useState, - ReactNode, } from "react"; -import { Button } from "./Button"; type DialogProps = { open?: boolean; diff --git a/copilot-widget/lib/components/Messages.tsx b/copilot-widget/lib/components/Messages.tsx index 5f1bef9ea..42289b663 100644 --- a/copilot-widget/lib/components/Messages.tsx +++ b/copilot-widget/lib/components/Messages.tsx @@ -138,10 +138,10 @@ export function BotMessageError({ message }: { message?: FailedMessage }) { every: 0.001, }); return ( -
-
+
+
-
{displayText}
+
{displayText}
); diff --git a/copilot-widget/lib/components/VoiceRecorder.tsx b/copilot-widget/lib/components/VoiceRecorder.tsx index d93d8c778..6bcb94d18 100644 --- a/copilot-widget/lib/components/VoiceRecorder.tsx +++ b/copilot-widget/lib/components/VoiceRecorder.tsx @@ -4,6 +4,7 @@ import { useAxiosInstance } from "@lib/contexts/axiosInstance"; import now from "@lib/utils/timenow"; import { useEffect } from "react"; import useAudioRecorder from "@lib/hooks/useAudioRecord"; +import { useLang } from "@lib/contexts/LocalesProvider"; export function VoiceRecorder({ onSuccess, @@ -11,7 +12,7 @@ export function VoiceRecorder({ onSuccess?: (text: string) => void; }) { const { axiosInstance } = useAxiosInstance(); - + const { get } = useLang(); const { startRecording, stopRecording, @@ -51,7 +52,7 @@ export function VoiceRecorder({ return ( - Recording {recordingTime}s + {get("recording")} {recordingTime}s