From 92eab6c6346b1e53921185eff254d051534ffd60 Mon Sep 17 00:00:00 2001 From: Jungley Date: Sat, 25 Mar 2023 23:42:48 +0800 Subject: [PATCH] feat: Add i18n support for Chinese language (#142) * feat: Add i18n support for Chinese language * fix: locale not working in Docker environment --- Dockerfile | 2 + components/Chat/Chat.tsx | 16 ++- components/Chat/ChatInput.tsx | 12 +- components/Chat/ChatMessage.tsx | 4 +- components/Chat/ModelSelect.tsx | 6 +- components/Chat/Regenerate.tsx | 6 +- components/Chat/SystemPrompt.tsx | 10 +- components/Markdown/CodeBlock.tsx | 6 +- components/Sidebar/ClearConversations.tsx | 7 +- components/Sidebar/Import.tsx | 4 +- components/Sidebar/Key.tsx | 4 +- components/Sidebar/Search.tsx | 5 +- components/Sidebar/Sidebar.tsx | 9 +- components/Sidebar/SidebarSettings.tsx | 6 +- next-i18next.config.js | 12 ++ next.config.js | 3 + package-lock.json | 166 ++++++++++++++++++++++ package.json | 3 + pages/_app.tsx | 5 +- pages/_document.tsx | 14 +- pages/index.tsx | 15 +- public/locales/en/common.json | 1 + public/locales/zh/chat.json | 25 ++++ public/locales/zh/common.json | 1 + public/locales/zh/markdown.json | 5 + public/locales/zh/sidebar.json | 13 ++ 26 files changed, 320 insertions(+), 40 deletions(-) create mode 100644 next-i18next.config.js create mode 100644 public/locales/en/common.json create mode 100644 public/locales/zh/chat.json create mode 100644 public/locales/zh/common.json create mode 100644 public/locales/zh/markdown.json create mode 100644 public/locales/zh/sidebar.json diff --git a/Dockerfile b/Dockerfile index 8998a71e54..6a79faf634 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,8 @@ COPY --from=dependencies /app/node_modules ./node_modules COPY --from=build /app/.next ./.next COPY --from=build /app/public ./public COPY --from=build /app/package*.json ./ +COPY --from=build /app/next.config.js ./next.config.js +COPY --from=build /app/next-i18next.config.js ./next-i18next.config.js # Expose the port the app will run on EXPOSE 3000 diff --git a/components/Chat/Chat.tsx b/components/Chat/Chat.tsx index 1d5c43244d..6bd5152a04 100644 --- a/components/Chat/Chat.tsx +++ b/components/Chat/Chat.tsx @@ -1,5 +1,6 @@ import { Conversation, KeyValuePair, Message, OpenAIModel } from "@/types"; import { FC, MutableRefObject, useCallback, useEffect, useRef, useState } from "react"; +import { useTranslation } from "next-i18next"; import { ChatInput } from "./ChatInput"; import { ChatLoader } from "./ChatLoader"; import { ChatMessage } from "./ChatMessage"; @@ -23,6 +24,7 @@ interface Props { } export const Chat: FC = ({ conversation, models, apiKey, serverSideApiKeyIsSet, messageIsStreaming, modelError, messageError, loading, lightMode, onSend, onUpdateConversation, onEditMessage, stopConversationRef }) => { + const { t } = useTranslation('chat'); const [currentMessage, setCurrentMessage] = useState(); const [autoScrollEnabled, setAutoScrollEnabled] = useState(true); @@ -71,14 +73,14 @@ export const Chat: FC = ({ conversation, models, apiKey, serverSideApiKey
{!(apiKey || serverSideApiKeyIsSet) ? (
-
OpenAI API Key Required
-
Please set your OpenAI API key in the bottom left of the sidebar.
+
{t('OpenAI API Key Required')}
+
{t('Please set your OpenAI API key in the bottom left of the sidebar.')}
) : modelError ? (
-
Error fetching models.
-
Make sure your OpenAI API key is set in the bottom left of the sidebar.
-
If you completed this step, OpenAI may be experiencing issues.
+
{t('Error fetching models.')}
+
{t('Make sure your OpenAI API key is set in the bottom left of the sidebar.')}
+
{t('If you completed this step, OpenAI may be experiencing issues.')}
) : ( <> @@ -89,7 +91,7 @@ export const Chat: FC = ({ conversation, models, apiKey, serverSideApiKey {conversation.messages.length === 0 ? ( <>
-
{models.length === 0 ? "Loading..." : "Chatbot UI"}
+
{models.length === 0 ? t("Loading...") : "Chatbot UI"}
{models.length > 0 && (
@@ -109,7 +111,7 @@ export const Chat: FC = ({ conversation, models, apiKey, serverSideApiKey ) : ( <> -
Model: {conversation.model.name}
+
{t('Model')}: {conversation.model.name}
{conversation.messages.map((message, index) => ( = ({ messageIsStreaming, model, messages, onSend, onRegenerate, stopConversationRef, textareaRef }) => { + const { t } = useTranslation('chat'); const [content, setContent] = useState(); const [isTyping, setIsTyping] = useState(false); @@ -21,7 +23,7 @@ export const ChatInput: FC = ({ messageIsStreaming, model, messages, onSe const maxLength = model.id === OpenAIModelID.GPT_3_5 ? 12000 : 24000; if (value.length > maxLength) { - alert(`Message limit is ${maxLength} characters. You have entered ${value.length} characters.`); + alert(t(`Message limit is {{maxLength}} characters. You have entered {{valueLength}} characters.`, { maxLength, valueLength: value.length })); return; } @@ -34,7 +36,7 @@ export const ChatInput: FC = ({ messageIsStreaming, model, messages, onSe } if (!content) { - alert("Please enter a message"); + alert(t("Please enter a message")); return; } @@ -88,7 +90,7 @@ export const ChatInput: FC = ({ messageIsStreaming, model, messages, onSe size={16} className="inline-block mb-[2px]" />{" "} - Stop Generating + {t('Stop Generating')} )} @@ -115,7 +117,7 @@ export const ChatInput: FC = ({ messageIsStreaming, model, messages, onSe maxHeight: "400px", overflow: `${textareaRef.current && textareaRef.current.scrollHeight > 400 ? "auto" : "hidden"}` }} - placeholder="Type a message..." + placeholder={t("Type a message...") || ''} value={content} rows={1} onCompositionStart={() => setIsTyping(true)} @@ -144,7 +146,7 @@ export const ChatInput: FC = ({ messageIsStreaming, model, messages, onSe > ChatBot UI - . Chatbot UI is an advanced chatbot kit for OpenAI's chat models aiming to mimic ChatGPT's interface and functionality. + . {t("Chatbot UI is an advanced chatbot kit for OpenAI's chat models aiming to mimic ChatGPT's interface and functionality.")}
); diff --git a/components/Chat/ChatMessage.tsx b/components/Chat/ChatMessage.tsx index a522f923d6..c087f9de91 100644 --- a/components/Chat/ChatMessage.tsx +++ b/components/Chat/ChatMessage.tsx @@ -1,6 +1,7 @@ import { Message } from "@/types"; import { IconEdit } from "@tabler/icons-react"; import { FC, useEffect, useRef, useState } from "react"; +import { useTranslation } from "next-i18next"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { CodeBlock } from "../Markdown/CodeBlock"; @@ -13,6 +14,7 @@ interface Props { } export const ChatMessage: FC = ({ message, messageIndex, lightMode, onEditMessage }) => { + const { t } = useTranslation('chat'); const [isEditing, setIsEditing] = useState(false); const [isHovering, setIsHovering] = useState(false); const [messageContent, setMessageContent] = useState(message.content); @@ -60,7 +62,7 @@ export const ChatMessage: FC = ({ message, messageIndex, lightMode, onEdi onMouseLeave={() => setIsHovering(false)} >
-
{message.role === "assistant" ? "AI:" : "You:"}
+
{message.role === "assistant" ? t("AI") : t("You")}:
{message.role === "user" ? ( diff --git a/components/Chat/ModelSelect.tsx b/components/Chat/ModelSelect.tsx index 6633e7e02d..ed851f0c6d 100644 --- a/components/Chat/ModelSelect.tsx +++ b/components/Chat/ModelSelect.tsx @@ -1,5 +1,6 @@ import { OpenAIModel } from "@/types"; import { FC } from "react"; +import { useTranslation } from "next-i18next"; interface Props { model: OpenAIModel; @@ -8,12 +9,13 @@ interface Props { } export const ModelSelect: FC = ({ model, models, onModelChange }) => { + const {t} = useTranslation('chat') return (
- +