feat: Add i18n support for Chinese language (#142)
* feat: Add i18n support for Chinese language * fix: locale not working in Docker environment
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { IconCheck, IconTrash, IconX } from "@tabler/icons-react";
|
||||
import { FC, useState } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { SidebarButton } from "./SidebarButton";
|
||||
|
||||
interface Props {
|
||||
@@ -9,6 +10,8 @@ interface Props {
|
||||
export const ClearConversations: FC<Props> = ({ onClearConversations }) => {
|
||||
const [isConfirming, setIsConfirming] = useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation('sidebar')
|
||||
|
||||
const handleClearConversations = () => {
|
||||
onClearConversations();
|
||||
setIsConfirming(false);
|
||||
@@ -18,7 +21,7 @@ export const ClearConversations: FC<Props> = ({ onClearConversations }) => {
|
||||
<div className="flex hover:bg-[#343541] py-3 px-3 rounded-md cursor-pointer w-full items-center">
|
||||
<IconTrash size={16} />
|
||||
|
||||
<div className="ml-3 flex-1 text-left text-white">Are you sure?</div>
|
||||
<div className="ml-3 flex-1 text-left text-white">{t('Are you sure?')}</div>
|
||||
|
||||
<div className="flex w-[40px]">
|
||||
<IconCheck
|
||||
@@ -42,7 +45,7 @@ export const ClearConversations: FC<Props> = ({ onClearConversations }) => {
|
||||
</div>
|
||||
) : (
|
||||
<SidebarButton
|
||||
text="Clear conversations"
|
||||
text={t("Clear conversations")}
|
||||
icon={<IconTrash size={16} />}
|
||||
onClick={() => setIsConfirming(true)}
|
||||
/>
|
||||
|
||||
@@ -3,12 +3,14 @@ import { cleanConversationHistory } from "@/utils/app/clean";
|
||||
import { IconFileImport } from "@tabler/icons-react";
|
||||
import { FC } from "react";
|
||||
import { SidebarButton } from "./SidebarButton";
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
interface Props {
|
||||
onImport: (data: { conversations: Conversation[]; folders: ChatFolder[] }) => void;
|
||||
}
|
||||
|
||||
export const Import: FC<Props> = ({ onImport }) => {
|
||||
const { t} = useTranslation('sidebar')
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
@@ -36,7 +38,7 @@ export const Import: FC<Props> = ({ onImport }) => {
|
||||
/>
|
||||
|
||||
<SidebarButton
|
||||
text="Import conversations"
|
||||
text={t("Import conversations")}
|
||||
icon={<IconFileImport size={16} />}
|
||||
onClick={() => {
|
||||
const importFile = document.querySelector("#import-file") as HTMLInputElement;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IconCheck, IconKey, IconX } from "@tabler/icons-react";
|
||||
import { FC, KeyboardEvent, useState } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { SidebarButton } from "./SidebarButton";
|
||||
|
||||
interface Props {
|
||||
@@ -8,6 +9,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const Key: FC<Props> = ({ apiKey, onApiKeyChange }) => {
|
||||
const { t } = useTranslation('sidebar');
|
||||
const [isChanging, setIsChanging] = useState(false);
|
||||
const [newKey, setNewKey] = useState(apiKey);
|
||||
|
||||
@@ -58,7 +60,7 @@ export const Key: FC<Props> = ({ apiKey, onApiKeyChange }) => {
|
||||
</div>
|
||||
) : (
|
||||
<SidebarButton
|
||||
text="OpenAI API Key"
|
||||
text={t("OpenAI API Key")}
|
||||
icon={<IconKey size={16} />}
|
||||
onClick={() => setIsChanging(true)}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
import { FC } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
interface Props {
|
||||
searchTerm: string;
|
||||
@@ -7,6 +8,8 @@ interface Props {
|
||||
}
|
||||
|
||||
export const Search: FC<Props> = ({ searchTerm, onSearch }) => {
|
||||
const { t } = useTranslation('sidebar');
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onSearch(e.target.value);
|
||||
};
|
||||
@@ -20,7 +23,7 @@ export const Search: FC<Props> = ({ searchTerm, onSearch }) => {
|
||||
<input
|
||||
className="flex-1 w-full pr-10 bg-[#202123] border border-neutral-600 text-sm rounded-md px-4 py-3 text-white"
|
||||
type="text"
|
||||
placeholder="Search conversations..."
|
||||
placeholder={t('Search conversations...') || ''}
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChatFolder, Conversation, KeyValuePair } from "@/types";
|
||||
import { IconArrowBarLeft, IconFolderPlus, IconPlus } from "@tabler/icons-react";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { Conversations } from "./Conversations";
|
||||
import { Folders } from "./Folders";
|
||||
import { Search } from "./Search";
|
||||
@@ -29,6 +30,8 @@ interface Props {
|
||||
}
|
||||
|
||||
export const Sidebar: FC<Props> = ({ loading, conversations, lightMode, selectedConversation, apiKey, folders, onCreateFolder, onDeleteFolder, onUpdateFolder, onNewConversation, onToggleLightMode, onSelectConversation, onDeleteConversation, onToggleSidebar, onUpdateConversation, onApiKeyChange, onClearConversations, onExportConversations, onImportConversations }) => {
|
||||
|
||||
const { t } = useTranslation('sidebar');
|
||||
const [searchTerm, setSearchTerm] = useState<string>("");
|
||||
const [filteredConversations, setFilteredConversations] = useState<Conversation[]>(conversations);
|
||||
|
||||
@@ -87,12 +90,12 @@ export const Sidebar: FC<Props> = ({ loading, conversations, lightMode, selected
|
||||
}}
|
||||
>
|
||||
<IconPlus size={16} />
|
||||
New chat
|
||||
{t('New chat')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="ml-2 flex gap-3 p-3 items-center rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm flex-shrink-0 border border-white/20"
|
||||
onClick={() => onCreateFolder("New folder")}
|
||||
onClick={() => onCreateFolder(t("New folder"))}
|
||||
>
|
||||
<IconFolderPlus size={16} />
|
||||
</button>
|
||||
@@ -148,7 +151,7 @@ export const Sidebar: FC<Props> = ({ loading, conversations, lightMode, selected
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4 text-white text-center">
|
||||
<div>No conversations.</div>
|
||||
<div>{t('No conversations.')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChatFolder, Conversation } from "@/types";
|
||||
import { IconFileExport, IconMoon, IconSun } from "@tabler/icons-react";
|
||||
import { FC } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { ClearConversations } from "./ClearConversations";
|
||||
import { Import } from "./Import";
|
||||
import { Key } from "./Key";
|
||||
@@ -17,6 +18,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const SidebarSettings: FC<Props> = ({ lightMode, apiKey, onToggleLightMode, onApiKeyChange, onClearConversations, onExportConversations, onImportConversations }) => {
|
||||
const { t} = useTranslation('sidebar')
|
||||
return (
|
||||
<div className="flex flex-col pt-1 items-center border-t border-white/20 text-sm space-y-1">
|
||||
<ClearConversations onClearConversations={onClearConversations} />
|
||||
@@ -24,13 +26,13 @@ export const SidebarSettings: FC<Props> = ({ lightMode, apiKey, onToggleLightMod
|
||||
<Import onImport={onImportConversations} />
|
||||
|
||||
<SidebarButton
|
||||
text="Export conversations"
|
||||
text={t("Export conversations")}
|
||||
icon={<IconFileExport size={16} />}
|
||||
onClick={() => onExportConversations()}
|
||||
/>
|
||||
|
||||
<SidebarButton
|
||||
text={lightMode === "light" ? "Dark mode" : "Light mode"}
|
||||
text={lightMode === "light" ? t("Dark mode") : t("Light mode")}
|
||||
icon={lightMode === "light" ? <IconMoon size={16} /> : <IconSun size={16} />}
|
||||
onClick={() => onToggleLightMode(lightMode === "light" ? "dark" : "light")}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user