feat(i18n): Update language handling and remove unused imports for improved performance

This commit is contained in:
wei840222 2025-08-17 22:53:19 +08:00
parent f8896b0f7b
commit 7b30992971
10 changed files with 13 additions and 49 deletions

View file

@ -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;

View file

@ -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';

View file

@ -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';

View file

@ -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>>(

View file

@ -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);

View file

@ -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(

View file

@ -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>

View file

@ -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

View file

@ -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 = (

View file

@ -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,