From 35b4125b988f6161056c3ec5fb27849d03aa0db9 Mon Sep 17 00:00:00 2001 From: Zizwar Date: Sat, 24 Jun 2023 04:30:52 +0000 Subject: [PATCH 1/3] Added support Arabic language --- app/locales/ar.ts | 296 +++++++++++++++++++++++++++++++++++++++++++ app/locales/index.ts | 3 + 2 files changed, 299 insertions(+) create mode 100644 app/locales/ar.ts diff --git a/app/locales/ar.ts b/app/locales/ar.ts new file mode 100644 index 00000000..70bfb0ce --- /dev/null +++ b/app/locales/ar.ts @@ -0,0 +1,296 @@ +import { SubmitKey } from "../store/config"; +import { LocaleType } from "./index"; + +const ar: LocaleType = { + WIP: "قريبًا...", + Error: { + Unauthorized: + "غير مصرح بالوصول، يرجى إدخال رمز الوصول [auth](/#/auth) في صفحة المصادقة.", + }, + Auth: { + Title: "تحتاج إلى رمز الوصول", + Tips: "يرجى إدخال رمز الوصول أدناه", + Input: "رمز الوصول", + Confirm: "تأكيد", + Later: "لاحقًا", + }, + ChatItem: { + ChatItemCount: (count: number) => `${count} رسائل`, + }, + Chat: { + SubTitle: (count: number) => ` ${count} رسائل مع ChatGPT`, + Actions: { + ChatList: "الانتقال إلى قائمة الدردشة", + CompressedHistory: "ملخص ضغط ذاكرة التاريخ", + Export: "تصدير جميع الرسائل كـ Markdown", + Copy: "نسخ", + Stop: "توقف", + Retry: "إعادة المحاولة", + Delete: "حذف", + }, + InputActions: { + Stop: "توقف", + ToBottom: "إلى آخر", + Theme: { + auto: "تلقائي", + light: "نمط فاتح", + dark: "نمط داكن", + }, + Prompt: "الاقتراحات", + Masks: "الأقنعة", + Clear: "مسح السياق", + Settings: "الإعدادات", + }, + Rename: "إعادة تسمية الدردشة", + Typing: "كتابة...", + Input: (submitKey: string) => { + var inputHints = ` اضغط على ${submitKey} للإرسال`; + if (submitKey === String(SubmitKey.Enter)) { + inputHints += "، Shift + Enter للإنشاء"; + } + return inputHints + "، / للبحث في الاقتراحات"; + }, + Send: "إرسال", + Config: { + Reset: "إعادة التعيين إلى الإعدادات الافتراضية", + SaveAs: "حفظ كأقنعة", + }, + }, + Export: { + Title: "تصدير الرسائل", + Copy: "نسخ الكل", + Download: "تنزيل", + MessageFromYou: "رسالة منك", + MessageFromChatGPT: "رسالة من ChatGPT", + Share: "مشاركة على ShareGPT", + Format: { + Title: "صيغة التصدير", + SubTitle: "Markdown أو صورة PNG", + }, + IncludeContext: { + Title: "تضمين السياق", + SubTitle: "تصدير اقتراحات السياق في الأقنعة أم لا", + }, + Steps: { + Select: "تحديد", + Preview: "معاينة", + }, + }, + Select: { + Search: "بحث", + All: "تحديد الكل", + Latest: "تحديد أحدث", + Clear: "مسح", + }, + Memory: { + Title: "اقتراحات الذاكرة", + EmptyContent: "لا شيء حتى الآن.", + Send: "إرسال الذاكرة", + Copy: "نسخ الذاكرة", + Reset: "إعادة التعيين", + ResetConfirm: + "سيؤدي إعادة التعيين إلى مسح سجل المحادثة الحالي والذاكرة التاريخية. هل أنت متأكد أنك تريد الاستمرار؟", + }, + Home: { + NewChat: "دردشة جديدة", + DeleteChat: "هل تريد تأكيد حذف المحادثة المحددة؟", + DeleteToast: "تم حذف الدردشة", + Revert: "التراجع", + }, + Settings: { + Title: "الإعدادات", + SubTitle: "جميع الإعدادات", + Actions: { + ClearAll: "مسح جميع البيانات", + ResetAll: "إعادة تعيين جميع الإعدادات", + Close: "إغلاق", + ConfirmResetAll: "هل أنت متأكد من رغبتك في إعادة تعيين جميع الإعدادات؟", + ConfirmClearAll: "هل أنت متأكد من رغبتك في مسح جميع البيانات؟", + }, + Lang: { + Name: "Language", // تنبيه: إذا كنت ترغب في إضافة ترجمة جديدة، يرجى عدم ترجمة هذه القيمة وتركها "Language" + All: "كل اللغات", + }, + Avatar: "الصورة الرمزية", + FontSize: { + Title: "حجم الخط", + SubTitle: "ضبط حجم الخط لمحتوى الدردشة", + }, + InputTemplate: { + Title: "نموذج الإدخال", + SubTitle: "سيتم ملء أحدث رسالة في هذا النموذج", + }, + Update: { + Version: (x: string) => ` الإصدار: ${x}`, + IsLatest: "أحدث إصدار", + CheckUpdate: "التحقق من التحديث", + IsChecking: "جارٍ التحقق من التحديث...", + FoundUpdate: (x: string) => ` تم العثور على إصدار جديد: ${x}`, + GoToUpdate: "التحديث", + }, + SendKey: "مفتاح الإرسال", + Theme: "السمة", + TightBorder: "حدود ضيقة", + SendPreviewBubble: { + Title: "عرض معاينة الـ Send", + SubTitle: "معاينة Markdown في فقاعة", + }, + Mask: { + Title: "شاشة تظهر الأقنعة", + SubTitle: "عرض شاشة تظهر الأقنعة قبل بدء الدردشة الجديدة", + }, + Prompt: { + Disable: { + Title: "تعطيل الاكتمال التلقائي", + SubTitle: "اكتب / لتشغيل الاكتمال التلقائي", + }, + List: "قائمة الاقتراحات", + ListCount: (builtin: number, custom: number) => ` +${builtin} مدمجة، ${custom} تم تعريفها من قبل المستخدم`, + Edit: "تعديل", + Modal: { + Title: "قائمة الاقتراحات", + Add: "إضافة واحدة", + Search: "البحث في الاقتراحات", + }, + EditModal: { + Title: "تحرير الاقتراح", + }, + }, + HistoryCount: { + Title: "عدد الرسائل المرفقة", + SubTitle: "عدد الرسائل المرسلة المرفقة في كل طلب", + }, + CompressThreshold: { + Title: "حد الضغط للتاريخ", + SubTitle: "سيتم الضغط إذا تجاوزت طول الرسائل غير المضغوطة الحد المحدد", + }, + Token: { + Title: "مفتاح API", + SubTitle: "استخدم مفتاحك لتجاوز حد رمز الوصول", + Placeholder: "مفتاح OpenAI API", + }, + Usage: { + Title: "رصيد الحساب", + SubTitle(used: any, total: any) { + return `تم استخدام $${used} من هذا الشهر، الاشتراك ${total}`; + }, + IsChecking: "جارٍ التحقق...", + Check: "التحقق", + NoAccess: "أدخل مفتاح API للتحقق من الرصيد", + }, + AccessCode: { + Title: "رمز الوصول", + SubTitle: "تم تمكين التحكم في الوصول", + Placeholder: "رمز الوصول المطلوب", + }, + Endpoint: { + Title: "نقطة النهاية", + SubTitle: "يجب أن تبدأ نقطة النهاية المخصصة بـ http(s)://", + }, + Model: "النموذج", + Temperature: { + Title: "الحرارة", + SubTitle: "قيمة أكبر تجعل الإخراج أكثر عشوائية", + }, + MaxTokens: { + Title: "الحد الأقصى للرموز", + SubTitle: "الحد الأقصى لعدد الرموز المدخلة والرموز المُنشأة", + }, + PresencePenalty: { + Title: "تأثير الوجود", + SubTitle: "قيمة أكبر تزيد من احتمالية التحدث عن مواضيع جديدة", + }, + FrequencyPenalty: { + Title: "تأثير التكرار", + SubTitle: "قيمة أكبر تقلل من احتمالية تكرار نفس السطر", + }, + }, + Store: { + DefaultTopic: "محادثة جديدة", + BotHello: "مرحبًا! كيف يمكنني مساعدتك اليوم؟", + Error: "حدث خطأ ما، يرجى المحاولة مرة أخرى في وقت لاحق.", + Prompt: { + History: (content: string) => "هذا ملخص لسجل الدردشة كمراجعة: " + content, + Topic: + "يرجى إنشاء عنوان يتكون من أربع إلى خمس كلمات يلخص محادثتنا دون أي مقدمة أو ترقيم أو علامات ترقيم أو نقاط أو رموز إضافية. قم بإزالة علامات التنصيص المحيطة.", + Summarize: + "قم بتلخيص النقاش بشكل موجز في 200 كلمة أو أقل لاستخدامه كاقتراح للسياق في المستقبل.", + }, + }, + Copy: { + Success: "تم النسخ إلى الحافظة", + Failed: "فشلت عملية النسخ، يرجى منح الإذن للوصول إلى الحافظة", + }, + Context: { + Toast: (x: any) => `مع ${x} اقتراحًا ذا سياق`, + Edit: "الاقتراحات السياقية والذاكرة", + Add: "إضافة اقتراح", + Clear: "مسح السياق", + Revert: "التراجع", + }, + Plugin: { + Name: "المكوّن الإضافي", + }, + Mask: { + Name: "الأقنعة", + Page: { + Title: "قالب الاقتراح", + SubTitle: (count: number) => `${count} قوالب الاقتراح`, + Search: "البحث في القوالب", + Create: "إنشاء", + }, + Item: { + Info: (count: number) => `${count} اقتراحات`, + Chat: "الدردشة", + View: "عرض", + Edit: "تعديل", + Delete: "حذف", + DeleteConfirm: "تأكيد الحذف؟", + }, + EditModal: { + Title: (readonly: boolean) => ` +تعديل قالب الاقتراح ${readonly ? "(للقراءة فقط)" : ""}`, + Download: "تنزيل", + Clone: "استنساخ", + }, + Config: { + Avatar: "صورة الروبوت", + Name: "اسم الروبوت", + Sync: { + Title: "استخدام الإعدادات العامة", + SubTitle: "استخدام الإعدادات العامة في هذه الدردشة", + Confirm: "تأكيد الاستبدال بالإعدادات المخصصة بالإعدادات العامة؟", + }, + HideContext: { + Title: "إخفاء اقتراحات السياق", + SubTitle: "عدم عرض اقتراحات السياق في الدردشة", + }, + }, + }, + NewChat: { + Return: "العودة", + Skip: "ابدأ فقط", + Title: "اختيار قناع", + SubTitle: "دردشة مع الروح وراء القناع", + More: "المزيد", + NotShow: "عدم العرض مرة أخرى", + ConfirmNoShow: "تأكيد تعطيله؟ يمكنك تمكينه في الإعدادات لاحقًا.", + }, + + UI: { + Confirm: "تأكيد", + Cancel: "إلغاء", + Close: "إغلاق", + Create: "إنشاء", + Edit: "تعديل", + }, + Exporter: { + Model: "النموذج", + Messages: "الرسائل", + Topic: "الموضوع", + Time: "الوقت", + }, +}; + +export default ar; diff --git a/app/locales/index.ts b/app/locales/index.ts index 38d54770..abdb4eaa 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -12,6 +12,7 @@ import ru from "./ru"; import no from "./no"; import cs from "./cs"; import ko from "./ko"; +import ar from "./ar"; import { merge } from "../utils/merge"; import type { LocaleType } from "./cn"; @@ -32,6 +33,7 @@ const ALL_LANGS = { ru, cs, no, + ar, }; export type Lang = keyof typeof ALL_LANGS; @@ -53,6 +55,7 @@ export const ALL_LANG_OPTIONS: Record = { ru: "Русский", cs: "Čeština", no: "Nynorsk", + ar: "العربية", }; const LANG_KEY = "lang"; From 946e508e8fd0f50d7794b58e65537b771e0701fe Mon Sep 17 00:00:00 2001 From: Zizwar Date: Sat, 24 Jun 2023 05:10:34 +0000 Subject: [PATCH 2/3] Support left to right in language arabic --- app/components/home.module.scss | 4 ++++ app/components/home.tsx | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/components/home.module.scss b/app/components/home.module.scss index c6fc3674..918d8b85 100644 --- a/app/components/home.module.scss +++ b/app/components/home.module.scss @@ -567,3 +567,7 @@ height: 100%; width: 100%; } + +.rtl-screen{ + direction: rtl; +} diff --git a/app/components/home.tsx b/app/components/home.tsx index 46fd78e8..b4b19028 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -15,6 +15,8 @@ import dynamic from "next/dynamic"; import { Path, SlotID } from "../constant"; import { ErrorBoundary } from "./error"; +import { getLang } from "../locales"; + import { HashRouter as Router, Routes, @@ -124,7 +126,7 @@ function Screen() { config.tightBorder && !isMobileScreen ? styles["tight-container"] : styles.container - }` + } ${getLang() === "ar" ? styles["rtl-screen"] : ""}` } > {isAuth ? ( From 15f8d13d8199049daf55a3fb182a6822be3cf274 Mon Sep 17 00:00:00 2001 From: Zizwar Date: Sat, 24 Jun 2023 05:53:58 +0000 Subject: [PATCH 3/3] Set markdown-body RTL for Arabic text --- app/components/markdown.tsx | 1 + app/styles/markdown.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index fbde6453..4db5f573 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -195,6 +195,7 @@ export function Markdown( fontSize: `${props.fontSize ?? 14}px`, height: getSize(renderedHeight.current), width: getSize(renderedWidth.current), + direction: /[\u0600-\u06FF]/.test(props.content) ? "rtl" : "ltr", }} ref={mdRef} onContextMenu={props.onContextMenu} diff --git a/app/styles/markdown.scss b/app/styles/markdown.scss index 31d10c4c..672167d4 100644 --- a/app/styles/markdown.scss +++ b/app/styles/markdown.scss @@ -844,6 +844,7 @@ font-size: 85%; line-height: 1.45; border-radius: 6px; + direction: ltr; } .markdown-body pre code,