From 378bef435ed2b8be8aec870dcdcf8f4edfd6754f Mon Sep 17 00:00:00 2001 From: Biki Kalita <86558912+Biki-dev@users.noreply.github.com> Date: Sat, 20 Dec 2025 20:18:54 +0530 Subject: [PATCH] Add i18n support, language toggle UI, and translate Settings dialog (#334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i18n support added * fix: align i18n implementation with Next.js 16 guide - Rename middleware.ts to proxy.ts (Next.js 16 convention) - Fix params type to Promise<{lang: string}> for layout/metadata - Add 'server-only' directive and dynamic imports to dictionaries.ts - Add hasLocale type guard and notFound() for invalid locales - Wrap LanguageToggle in Suspense for useSearchParams - Fix dictionary key mismatch (learnmore -> learnMore) - Improve Chinese translations per Gemini review: - loading ellipsis, new -> 新建, styledMode -> 精致 - goodResponse/badResponse -> 有帮助/无帮助 - closeProtection -> 关闭确认, fileExceeds phrasing - Improve Japanese translations per Gemini review: - closeProtection -> ページ離脱確認 - invalidAccessCode phrasing, appendDiagram -> に追加 - styledMode -> スタイル付き --------- Co-authored-by: dayuan.jiang --- app/{ => [lang]}/about/cn/page.tsx | 0 app/{ => [lang]}/about/ja/page.tsx | 0 app/{ => [lang]}/about/page.tsx | 0 app/[lang]/layout.tsx | 172 +++++++++++++++++++++++++++ app/{ => [lang]}/page.tsx | 8 +- app/layout.tsx | 125 -------------------- components/chat-example-panel.tsx | 48 ++++---- components/chat-input.tsx | 77 +++++++----- components/chat-panel.tsx | 35 +++--- components/file-preview-list.tsx | 15 +-- components/history-dialog.tsx | 26 ++-- components/language-toggle.tsx | 108 +++++++++++++++++ components/quota-limit-toast.tsx | 47 +++----- components/reset-warning-modal.tsx | 12 +- components/save-dialog.tsx | 48 +++++--- components/settings-dialog.tsx | 100 ++++++++++------ hooks/use-dictionary.ts | 29 +++++ lib/i18n/config.ts | 6 + lib/i18n/dictionaries.ts | 18 +++ lib/i18n/dictionaries/en.json | 184 +++++++++++++++++++++++++++++ lib/i18n/dictionaries/ja.json | 184 +++++++++++++++++++++++++++++ lib/i18n/dictionaries/zh.json | 184 +++++++++++++++++++++++++++++ lib/i18n/utils.ts | 14 +++ package-lock.json | 35 ++++++ package.json | 4 + proxy.ts | 63 ++++++++++ 26 files changed, 1235 insertions(+), 307 deletions(-) rename app/{ => [lang]}/about/cn/page.tsx (100%) rename app/{ => [lang]}/about/ja/page.tsx (100%) rename app/{ => [lang]}/about/page.tsx (100%) create mode 100644 app/[lang]/layout.tsx rename app/{ => [lang]}/page.tsx (95%) delete mode 100644 app/layout.tsx create mode 100644 components/language-toggle.tsx create mode 100644 hooks/use-dictionary.ts create mode 100644 lib/i18n/config.ts create mode 100644 lib/i18n/dictionaries.ts create mode 100644 lib/i18n/dictionaries/en.json create mode 100644 lib/i18n/dictionaries/ja.json create mode 100644 lib/i18n/dictionaries/zh.json create mode 100644 lib/i18n/utils.ts create mode 100644 proxy.ts diff --git a/app/about/cn/page.tsx b/app/[lang]/about/cn/page.tsx similarity index 100% rename from app/about/cn/page.tsx rename to app/[lang]/about/cn/page.tsx diff --git a/app/about/ja/page.tsx b/app/[lang]/about/ja/page.tsx similarity index 100% rename from app/about/ja/page.tsx rename to app/[lang]/about/ja/page.tsx diff --git a/app/about/page.tsx b/app/[lang]/about/page.tsx similarity index 100% rename from app/about/page.tsx rename to app/[lang]/about/page.tsx diff --git a/app/[lang]/layout.tsx b/app/[lang]/layout.tsx new file mode 100644 index 0000000..5ab56c9 --- /dev/null +++ b/app/[lang]/layout.tsx @@ -0,0 +1,172 @@ +import { GoogleAnalytics } from "@next/third-parties/google" +import type { Metadata, Viewport } from "next" +import { JetBrains_Mono, Plus_Jakarta_Sans } from "next/font/google" +import { notFound } from "next/navigation" +import { DiagramProvider } from "@/contexts/diagram-context" +import { DictionaryProvider } from "@/hooks/use-dictionary" +import type { Locale } from "@/lib/i18n/config" +import { i18n } from "@/lib/i18n/config" +import { getDictionary, hasLocale } from "@/lib/i18n/dictionaries" + +import "../globals.css" + +const plusJakarta = Plus_Jakarta_Sans({ + variable: "--font-sans", + subsets: ["latin"], + weight: ["400", "500", "600", "700"], +}) + +const jetbrainsMono = JetBrains_Mono({ + variable: "--font-mono", + subsets: ["latin"], + weight: ["400", "500"], +}) + +export const viewport: Viewport = { + width: "device-width", + initialScale: 1, + maximumScale: 1, + userScalable: false, +} + +// Generate static params for all locales +export async function generateStaticParams() { + return i18n.locales.map((locale) => ({ lang: locale })) +} + +// Generate metadata per locale +export async function generateMetadata({ + params, +}: { + params: Promise<{ lang: string }> +}): Promise { + const { lang: rawLang } = await params + const lang = (rawLang in { en: 1, zh: 1, ja: 1 } ? rawLang : "en") as Locale + + // Default to English metadata + const titles: Record = { + en: "Next AI Draw.io - AI-Powered Diagram Generator", + zh: "Next AI Draw.io - AI powered diagram generator", + ja: "Next AI Draw.io - AI-powered diagram generator", + } + + const descriptions: Record = { + en: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Free online tool integrating draw.io with AI assistance for professional diagram creation.", + zh: "Use AI to create AWS architecture diagrams, flowcharts, and technical diagrams. Free online tool integrated with draw.io and AI assistance for professional diagram creation.", + ja: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Create professional diagrams with a free online tool that integrates draw.io with an AI assistant.", + } + + return { + title: titles[lang], + description: descriptions[lang], + keywords: [ + "AI diagram generator", + "AWS architecture", + "flowchart creator", + "draw.io", + "AI drawing tool", + "technical diagrams", + "diagram automation", + "free diagram generator", + "online diagram maker", + ], + authors: [{ name: "Next AI Draw.io" }], + creator: "Next AI Draw.io", + publisher: "Next AI Draw.io", + metadataBase: new URL("https://next-ai-drawio.jiang.jp"), + openGraph: { + title: titles[lang], + description: descriptions[lang], + type: "website", + url: "https://next-ai-drawio.jiang.jp", + siteName: "Next AI Draw.io", + locale: lang === "zh" ? "zh_CN" : lang === "ja" ? "ja_JP" : "en_US", + images: [ + { + url: "/architecture.png", + width: 1200, + height: 630, + alt: "Next AI Draw.io - AI-powered diagram creation tool", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: titles[lang], + description: descriptions[lang], + images: ["/architecture.png"], + }, + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + "max-video-preview": -1, + "max-image-preview": "large", + "max-snippet": -1, + }, + }, + icons: { + icon: "/favicon.ico", + }, + alternates: { + languages: { + en: "/en", + zh: "/zh", + ja: "/ja", + }, + }, + } +} + +export default async function RootLayout({ + children, + params, +}: Readonly<{ + children: React.ReactNode + params: Promise<{ lang: string }> +}>) { + const { lang } = await params + if (!hasLocale(lang)) notFound() + const validLang = lang as Locale + const dictionary = await getDictionary(validLang) + + const jsonLd = { + "@context": "https://schema.org", + "@type": "SoftwareApplication", + name: "Next AI Draw.io", + applicationCategory: "DesignApplication", + operatingSystem: "Web Browser", + description: + "AI-powered diagram generator with targeted XML editing capabilities that integrates with draw.io for creating AWS architecture diagrams, flowcharts, and technical diagrams. Features diagram history, multi-provider AI support, and real-time collaboration.", + url: "https://next-ai-drawio.jiang.jp", + inLanguage: validLang, + offers: { + "@type": "Offer", + price: "0", + priceCurrency: "USD", + }, + } + + return ( + + +