Skip to content
This repository has been archived by the owner on Jan 5, 2025. It is now read-only.

Commit

Permalink
Merge pull request #614 from openchatai/widget/i18n-strings
Browse files Browse the repository at this point in the history
Simple, minimal i18n Solution
  • Loading branch information
faltawy authored Feb 7, 2024
2 parents a1a0d00 + d604687 commit 3396400
Show file tree
Hide file tree
Showing 19 changed files with 171 additions and 85 deletions.
1 change: 1 addition & 0 deletions copilot-widget/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ <h2>
apiUrl: apiUrl, // required
socketUrl: socketUrl, // required
defaultOpen: true, // optional
lang: "ar", // optional
containerProps: {}, // optional
headers: {
// optional
Expand Down
9 changes: 6 additions & 3 deletions copilot-widget/lib/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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%)",
Expand Down Expand Up @@ -33,9 +34,11 @@ function Root({ children, options, containerProps }: RootProps) {
}}
>
<ConfigDataProvider data={options}>
<WidgetState>
<AxiosProvider>{children}</AxiosProvider>
</WidgetState>
<LanguageProvider>
<WidgetState>
<AxiosProvider>{children}</AxiosProvider>
</WidgetState>
</LanguageProvider>
</ConfigDataProvider>
<style>{css}</style>
</root.div>
Expand Down
10 changes: 7 additions & 3 deletions copilot-widget/lib/components/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<header className="p-3 border-b border-b-black/10 w-full">
<div className=" w-full flex items-center justify-between">
Expand All @@ -30,7 +32,9 @@ export default function ChatHeader() {
<span className="text-rose-500">
<AlertTriangle className="size-10" />
</span>
<h2>are you sure?</h2>
<h2>
{get("are-you-sure")}
</h2>
</div>
</DialogHeader>
<div className="flex flex-row items-center justify-center gap-2">
Expand All @@ -40,11 +44,11 @@ export default function ChatHeader() {
SetState(false);
}}
>
Yes, exit
{get("yes-exit")}
</DialogClose>
</Button>
<Button asChild variant="secondary" className="font-semibold">
<DialogClose>No, Cancel</DialogClose>
<DialogClose>{get("no-cancel")}</DialogClose>
</Button>
</div>
</DialogContent>
Expand Down
8 changes: 5 additions & 3 deletions copilot-widget/lib/components/ChatInputFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DialogTrigger,
} from "./Dialog";
import { Button } from "./Button";
import { useLang } from "@lib/contexts/LocalesProvider";

function MessageSuggestions() {
const { data } = useInitialData();
Expand Down Expand Up @@ -48,6 +49,7 @@ function MessageSuggestions() {
function ResetButtonWithConfirmation() {
const { reset } = useChat();
const [open, setOpen] = useState(false);
const { get } = useLang();
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger>
Expand All @@ -59,7 +61,7 @@ function ResetButtonWithConfirmation() {
<span className="text-rose-500">
<AlertTriangle className="size-10" />
</span>
<h2>are you sure?</h2>
<h2>{get("are-you-sure")}</h2>
</div>
</DialogHeader>
<div className="flex flex-row items-center justify-center gap-2">
Expand All @@ -69,10 +71,10 @@ function ResetButtonWithConfirmation() {
className="font-semibold"
onClick={reset}
>
<DialogClose>Yes, reset</DialogClose>
<DialogClose>{get("yes-reset")}</DialogClose>
</Button>
<Button asChild variant="secondary" className="font-semibold">
<DialogClose>No, Cancel</DialogClose>
<DialogClose>{get("no-cancel")}</DialogClose>
</Button>
</div>
</DialogContent>
Expand Down
2 changes: 0 additions & 2 deletions copilot-widget/lib/components/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import {
ComponentPropsWithoutRef,
forwardRef,
useState,
ReactNode,
} from "react";
import { Button } from "./Button";

type DialogProps = {
open?: boolean;
Expand Down
6 changes: 3 additions & 3 deletions copilot-widget/lib/components/Messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ export function BotMessageError({ message }: { message?: FailedMessage }) {
every: 0.001,
});
return (
<div className=" clear-both shrink-0 w-full p-2">
<div className=" flex items-center gap-3 w-full">
<div className="clear-both shrink-0 w-full p-2">
<div className=" flex items-center gap-3 w-full">
<BotIcon error />
<div className=" text-rose-500 text-sm">{displayText}</div>
<div className=" text-rose-500 text-sm">{displayText}</div>
</div>
</div>
);
Expand Down
5 changes: 3 additions & 2 deletions copilot-widget/lib/components/VoiceRecorder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ 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,
}: {
onSuccess?: (text: string) => void;
}) {
const { axiosInstance } = useAxiosInstance();

const { get } = useLang();
const {
startRecording,
stopRecording,
Expand Down Expand Up @@ -51,7 +52,7 @@ export function VoiceRecorder({
return (
<Tooltip open={isRecording}>
<TooltipContent sideOffset={5} side="top">
Recording {recordingTime}s
{get("recording")} {recordingTime}s
</TooltipContent>
<TooltipTrigger asChild>
<button
Expand Down
4 changes: 3 additions & 1 deletion copilot-widget/lib/components/Vote.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useLang } from "@lib/contexts/LocalesProvider";
import { useDownvote, useUpvote } from "@lib/hooks/useVote";
import cn from "@lib/utils/cn";
import { ThumbsUp, ThumbsDown } from "lucide-react";
Expand All @@ -10,11 +11,12 @@ export function Vote({ messageId }: { messageId: number }) {
const isUpvoted = !!asyncUpvoteState.value?.data.message;
const isDownvoted = !!asyncDownvoteState.value?.data.message;
const userVoted = isUpvoted || isDownvoted;
const { get } = useLang();
return (
<div className="flex items-center justify-end w-full gap-px [&>button]:p-1">
{userVoted ? (
<span className="text-xs text-blur-out text-emerald-500">
thank you
{get("thank-you")}
</span>
) : (
<>
Expand Down
24 changes: 24 additions & 0 deletions copilot-widget/lib/contexts/LocalesProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type LangType, getStr } from "@lib/locales";
import { createSafeContext } from "./create-safe-context";
import { useConfigData } from "./ConfigData";

const [useLang, SafeLanguageProvider] = createSafeContext<{
get: (key: string) => string;
lang: LangType;
}>();

function LanguageProvider({ children }: { children: React.ReactNode }) {
const config = useConfigData();
console.log(config);
return (
<SafeLanguageProvider
value={{
get: (key: string) => getStr(key, config.lang ?? "en"),
lang: config.lang ?? "en",
}}
>
{children}
</SafeLanguageProvider>
);
}
export { LanguageProvider, useLang };
15 changes: 15 additions & 0 deletions copilot-widget/lib/locales/ar.locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Locale } from "./types";

const arLocale: Locale = {
ok: "حسنا",
agree: "موافق",
cancel: "إلغاء",
"yes-exit": "نعم، اخرج",
"yes-reset": "نعم، إعادة تعيين",
"no-cancel": "لا، إلغاء",
"are-you-sure": "هل أنت متأكد؟",
recording: "تسجيل",
"thank-you": "شكرا",
};

export default arLocale;
15 changes: 15 additions & 0 deletions copilot-widget/lib/locales/en.locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Locale } from "./types";

const enLocale: Locale = {
ok: "Ok",
agree: "Agree",
cancel: "Cancel",
"yes-exit": "Yes, Exit",
"yes-reset": "Yes, Reset",
"no-cancel": "No, Cancel",
"are-you-sure": "Are you sure?",
recording: "Recording",
"thank-you": "Thank you",
};

export default enLocale;
13 changes: 13 additions & 0 deletions copilot-widget/lib/locales/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import enLocale from "./en.locale";
import arLocale from "./ar.locale";

const locales = {
en: enLocale,
ar: arLocale,
};
export type LangType = keyof typeof locales;

export function getStr(key: string, lang: LangType): string {
const locale = locales[lang];
return locale ? locale[key] || "" : "";
}
2 changes: 2 additions & 0 deletions copilot-widget/lib/locales/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./types";
export * from "./helper";
3 changes: 3 additions & 0 deletions copilot-widget/lib/locales/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Locale = {
[key: string]: string;
};
3 changes: 3 additions & 0 deletions copilot-widget/lib/types/options.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { LangType } from "@lib/locales";

export type Options = {
token: string;
headers?: Record<string, string>;
Expand All @@ -6,6 +8,7 @@ export type Options = {
apiUrl: string;
socketUrl: string;
defaultOpen?: boolean;
lang?: LangType;
containerProps?: React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
Expand Down
2 changes: 1 addition & 1 deletion copilot-widget/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@openchatai/copilot-widget",
"private": false,
"version": "2.4.2",
"version": "2.5.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"dependencies": {
"@hookform/resolvers": "^3.3.1",
"@kbox-labs/react-echarts": "^1.0.3",
"@openchatai/copilot-widget": "^2.4.2",
"@openchatai/copilot-widget": "^2.5.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.4",
Expand Down
8 changes: 4 additions & 4 deletions dashboard/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3396400

Please sign in to comment.