feat(i18n): Update language handling and remove unused imports for improved performance
This commit is contained in:
parent
f8896b0f7b
commit
7b30992971
10 changed files with 13 additions and 49 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { searchSearxng } from '@/lib/searxng';
|
import { searchSearxng } from '@/lib/searxng';
|
||||||
import { getLocale } from 'next-intl/server';
|
import { DEFAULT_LOCALE } from '@/i18n/locales';
|
||||||
|
|
||||||
const websitesForTopic = {
|
const websitesForTopic = {
|
||||||
tech: {
|
tech: {
|
||||||
|
|
@ -38,10 +38,6 @@ export const GET = async (req: Request) => {
|
||||||
|
|
||||||
let data = [];
|
let data = [];
|
||||||
|
|
||||||
// derive base language from current locale (e.g., zh-TW -> zh)
|
|
||||||
const locale = await getLocale();
|
|
||||||
const searxLanguage = 'en';
|
|
||||||
|
|
||||||
if (mode === 'normal') {
|
if (mode === 'normal') {
|
||||||
const seenUrls = new Set();
|
const seenUrls = new Set();
|
||||||
|
|
||||||
|
|
@ -53,7 +49,7 @@ export const GET = async (req: Request) => {
|
||||||
await searchSearxng(`site:${link} ${query}`, {
|
await searchSearxng(`site:${link} ${query}`, {
|
||||||
engines: ['google news', 'bing news'],
|
engines: ['google news', 'bing news'],
|
||||||
pageno: 1,
|
pageno: 1,
|
||||||
language: searxLanguage,
|
language: DEFAULT_LOCALE,
|
||||||
})
|
})
|
||||||
).results;
|
).results;
|
||||||
}),
|
}),
|
||||||
|
|
@ -75,7 +71,7 @@ export const GET = async (req: Request) => {
|
||||||
{
|
{
|
||||||
engines: ['google news', 'bing news'],
|
engines: ['google news', 'bing news'],
|
||||||
pageno: 1,
|
pageno: 1,
|
||||||
language: searxLanguage,
|
language: DEFAULT_LOCALE,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
).results;
|
).results;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import DeleteChat from '@/components/DeleteChat';
|
import DeleteChat from '@/components/DeleteChat';
|
||||||
import { cn, formatTimeDifference, formatRelativeTime } from '@/lib/utils';
|
import { cn, formatRelativeTime } from '@/lib/utils';
|
||||||
import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react';
|
import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import ChatWindow from '@/components/ChatWindow';
|
import ChatWindow from '@/components/ChatWindow';
|
||||||
import type { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import LocaleSwitcher from '@/components/LocaleSwitcher';
|
||||||
import { ImagesIcon, VideoIcon } from 'lucide-react';
|
import { ImagesIcon, VideoIcon } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { PROVIDER_METADATA } from '@/lib/providers';
|
import { PROVIDER_METADATA } from '@/lib/providers';
|
||||||
import { useLocale, useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
interface SettingsType {
|
interface SettingsType {
|
||||||
chatModelProviders: {
|
chatModelProviders: {
|
||||||
|
|
@ -131,7 +131,6 @@ const SettingsSection = ({
|
||||||
|
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
const t = useTranslations('pages.settings');
|
const t = useTranslations('pages.settings');
|
||||||
const locale = useLocale();
|
|
||||||
const [config, setConfig] = useState<SettingsType | null>(null);
|
const [config, setConfig] = useState<SettingsType | null>(null);
|
||||||
const [chatModels, setChatModels] = useState<Record<string, any>>({});
|
const [chatModels, setChatModels] = useState<Record<string, any>>({});
|
||||||
const [embeddingModels, setEmbeddingModels] = useState<Record<string, any>>(
|
const [embeddingModels, setEmbeddingModels] = useState<Record<string, any>>(
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ const DeleteChat = ({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status != 200) {
|
if (res.status != 200) {
|
||||||
throw new Error(t('common.errors.failedToDeleteChat'));
|
throw new Error('Failed to delete chat');
|
||||||
}
|
}
|
||||||
|
|
||||||
const newChats = chats.filter((chat) => chat.id !== chatId);
|
const newChats = chats.filter((chat) => chat.id !== chatId);
|
||||||
|
|
@ -50,7 +50,8 @@ const DeleteChat = ({
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
toast.error(err.message || t('common.errors.failedToDeleteChat'));
|
console.error(err);
|
||||||
|
toast.error(t('common.errors.failedToDeleteChat'));
|
||||||
} finally {
|
} finally {
|
||||||
setConfirmationDialogOpen(false);
|
setConfirmationDialogOpen(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,8 @@ export default function LocaleBootstrap({
|
||||||
initialLocale: AppLocale;
|
initialLocale: AppLocale;
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 若已有 cookie,跳過
|
|
||||||
const hasCookie = /(?:^|; )locale=/.test(document.cookie);
|
const hasCookie = /(?:^|; )locale=/.test(document.cookie);
|
||||||
if (hasCookie) return;
|
if (hasCookie) return;
|
||||||
// 僅接受支援清單內的語系
|
|
||||||
const supported = new Set<string>(LOCALES as readonly string[]);
|
const supported = new Set<string>(LOCALES as readonly string[]);
|
||||||
const loc = (initialLocale || DEFAULT_LOCALE) as string;
|
const loc = (initialLocale || DEFAULT_LOCALE) as string;
|
||||||
const chosen = Array.from(supported).find(
|
const chosen = Array.from(supported).find(
|
||||||
|
|
|
||||||
|
|
@ -218,9 +218,9 @@ const MessageBox = ({
|
||||||
className="p-2 text-black/70 dark:text-white/70 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary transition duration-200 hover:text-black dark:hover:text-white"
|
className="p-2 text-black/70 dark:text-white/70 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary transition duration-200 hover:text-black dark:hover:text-white"
|
||||||
>
|
>
|
||||||
{speechStatus === 'started' ? (
|
{speechStatus === 'started' ? (
|
||||||
<StopCircle size={18} aria-label="Stop TTS" />
|
<StopCircle size={18} />
|
||||||
) : (
|
) : (
|
||||||
<Volume2 size={18} aria-label="Start TTS" />
|
<Volume2 size={18} />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
import { Clock, Edit, Share, Trash, FileText, FileDown } from 'lucide-react';
|
import { Clock, Edit, Share, Trash, FileText, FileDown } from 'lucide-react';
|
||||||
import { Message } from './ChatWindow';
|
import { Message } from './ChatWindow';
|
||||||
import { useEffect, useState, Fragment } from 'react';
|
import { useEffect, useState, Fragment } from 'react';
|
||||||
import {
|
import { formatRelativeTime, formatDate } from '@/lib/utils';
|
||||||
formatTimeDifference,
|
|
||||||
formatRelativeTime,
|
|
||||||
formatDate,
|
|
||||||
} from '@/lib/utils';
|
|
||||||
import { useLocale, useTranslations } from 'next-intl';
|
import { useLocale, useTranslations } from 'next-intl';
|
||||||
import DeleteChat from './DeleteChat';
|
import DeleteChat from './DeleteChat';
|
||||||
import {
|
import {
|
||||||
|
|
@ -168,12 +164,9 @@ const Navbar = ({
|
||||||
? `${messages[0].content.substring(0, 20).trim()}...`
|
? `${messages[0].content.substring(0, 20).trim()}...`
|
||||||
: messages[0].content;
|
: messages[0].content;
|
||||||
setTitle(newTitle);
|
setTitle(newTitle);
|
||||||
// title already set above
|
|
||||||
}
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
// Removed per-locale relative time uses render-time computation
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed z-40 top-0 left-0 right-0 px-4 lg:pl-[104px] lg:pr-6 lg:px-8 flex flex-row items-center justify-between w-full py-4 text-sm text-black dark:text-white/70 border-b bg-light-primary dark:bg-dark-primary border-light-100 dark:border-dark-200">
|
<div className="fixed z-40 top-0 left-0 right-0 px-4 lg:pl-[104px] lg:pr-6 lg:px-8 flex flex-row items-center justify-between w-full py-4 text-sm text-black dark:text-white/70 border-b bg-light-primary dark:bg-dark-primary border-light-100 dark:border-dark-200">
|
||||||
<a
|
<a
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export const LOCALE_LABELS: Record<AppLocale, string> = {
|
||||||
de: 'Deutsch',
|
de: 'Deutsch',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Human-readable language name for prompt prefix
|
// Human-readable language name for prompt
|
||||||
export function getPromptLanguageName(loc: string): string {
|
export function getPromptLanguageName(loc: string): string {
|
||||||
const l = (loc || '').toLowerCase();
|
const l = (loc || '').toLowerCase();
|
||||||
const match = (
|
const match = (
|
||||||
|
|
|
||||||
|
|
@ -19,29 +19,6 @@ export const formatDate = (
|
||||||
return new Intl.DateTimeFormat(locale || undefined, options).format(d);
|
return new Intl.DateTimeFormat(locale || undefined, options).format(d);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatTimeDifference = (
|
|
||||||
date1: Date | string,
|
|
||||||
date2: Date | string,
|
|
||||||
): string => {
|
|
||||||
date1 = new Date(date1);
|
|
||||||
date2 = new Date(date2);
|
|
||||||
|
|
||||||
const diffInSeconds = Math.floor(
|
|
||||||
Math.abs(date2.getTime() - date1.getTime()) / 1000,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (diffInSeconds < 60)
|
|
||||||
return `${diffInSeconds} second${diffInSeconds !== 1 ? 's' : ''}`;
|
|
||||||
else if (diffInSeconds < 3600)
|
|
||||||
return `${Math.floor(diffInSeconds / 60)} minute${Math.floor(diffInSeconds / 60) !== 1 ? 's' : ''}`;
|
|
||||||
else if (diffInSeconds < 86400)
|
|
||||||
return `${Math.floor(diffInSeconds / 3600)} hour${Math.floor(diffInSeconds / 3600) !== 1 ? 's' : ''}`;
|
|
||||||
else if (diffInSeconds < 31536000)
|
|
||||||
return `${Math.floor(diffInSeconds / 86400)} day${Math.floor(diffInSeconds / 86400) !== 1 ? 's' : ''}`;
|
|
||||||
else
|
|
||||||
return `${Math.floor(diffInSeconds / 31536000)} year${Math.floor(diffInSeconds / 31536000) !== 1 ? 's' : ''}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Locale-aware relative time using Intl.RelativeTimeFormat
|
// Locale-aware relative time using Intl.RelativeTimeFormat
|
||||||
export const formatRelativeTime = (
|
export const formatRelativeTime = (
|
||||||
date1: Date | string,
|
date1: Date | string,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue