diff --git a/frontend/src/components/LanguageSwitcher.tsx b/frontend/src/components/LanguageSwitcher.tsx new file mode 100644 index 0000000..455bb36 --- /dev/null +++ b/frontend/src/components/LanguageSwitcher.tsx @@ -0,0 +1,45 @@ +import { useTranslation } from 'react-i18next' +import { Globe } from 'lucide-react' + +const languages = [ + { code: 'zh-TW', label: '繁體中文' }, + { code: 'en-US', label: 'English' }, +] + +export default function LanguageSwitcher() { + const { i18n } = useTranslation() + + const handleLanguageChange = (langCode: string) => { + i18n.changeLanguage(langCode) + localStorage.setItem('tool-ocr-language', langCode) + } + + const currentLang = languages.find((lang) => lang.code === i18n.language) || languages[0] + + return ( +
+ + + {/* Dropdown */} +
+ {languages.map((lang) => ( + + ))} +
+
+ ) +} diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 799a5f7..f5df590 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -2,6 +2,7 @@ import { Outlet, NavLink, useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useAuthStore } from '@/store/authStore' import { apiClientV2 } from '@/services/apiV2' +import LanguageSwitcher from '@/components/LanguageSwitcher' import { Upload, Settings, @@ -11,8 +12,6 @@ import { LogOut, LayoutDashboard, ChevronRight, - Bell, - Search, History, Shield } from 'lucide-react' @@ -96,9 +95,9 @@ export default function Layout() { {/* User section */} -
+
{user && ( -
+
{user.username.charAt(0).toUpperCase()}
@@ -108,6 +107,9 @@ export default function Layout() {
)} +
+ +
-
- - - {/* Page content */} -
-
- -
-
-
+
+
+ +
+
) } diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 7646731..55174fa 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -1,9 +1,25 @@ import i18n from 'i18next' import { initReactI18next } from 'react-i18next' import zhTW from './locales/zh-TW.json' +import enUS from './locales/en-US.json' + +const LANGUAGE_STORAGE_KEY = 'tool-ocr-language' + +/** + * Get saved language preference from localStorage + * Falls back to zh-TW if no preference is saved + */ +function getSavedLanguage(): string { + const saved = localStorage.getItem(LANGUAGE_STORAGE_KEY) + if (saved && ['zh-TW', 'en-US'].includes(saved)) { + return saved + } + return 'zh-TW' +} /** * i18n Configuration + * Supported languages: Traditional Chinese (zh-TW), English (en-US) * Default language: Traditional Chinese (zh-TW) */ i18n.use(initReactI18next).init({ @@ -11,8 +27,11 @@ i18n.use(initReactI18next).init({ 'zh-TW': { translation: zhTW, }, + 'en-US': { + translation: enUS, + }, }, - lng: 'zh-TW', + lng: getSavedLanguage(), fallbackLng: 'zh-TW', interpolation: { escapeValue: false, diff --git a/frontend/src/i18n/locales/en-US.json b/frontend/src/i18n/locales/en-US.json new file mode 100644 index 0000000..4020eb6 --- /dev/null +++ b/frontend/src/i18n/locales/en-US.json @@ -0,0 +1,238 @@ +{ + "app": { + "title": "OCR Batch Processing System", + "subtitle": "Document Recognition and Conversion Platform" + }, + "nav": { + "upload": "Upload Files", + "processing": "Processing", + "results": "View Results", + "export": "Export", + "settings": "Settings", + "logout": "Logout", + "taskHistory": "Task History", + "adminDashboard": "Admin Dashboard" + }, + "auth": { + "login": "Login", + "username": "Username", + "password": "Password", + "loginButton": "Login", + "loginError": "Login failed. Please check your credentials.", + "welcomeBack": "Welcome Back", + "loginPrompt": "Sign in to access OCR services", + "loggingIn": "Signing in...", + "usernamePlaceholder": "Enter your username", + "passwordPlaceholder": "Enter your password", + "supportedFormats": "Supported formats: PDF, Images, Office documents" + }, + "upload": { + "title": "Upload Files", + "dragAndDrop": "Drag and drop files here, or click to select", + "dropFilesHere": "Drop files here to upload", + "invalidFiles": "Some file formats are not supported", + "supportedFormats": "Supported formats: PNG, JPG, JPEG, PDF, DOC, DOCX, PPT, PPTX", + "maxFileSize": "Maximum file size: 50MB", + "uploadButton": "Start Upload", + "uploading": "Uploading...", + "uploadSuccess": "Upload successful", + "uploadError": "Upload failed", + "fileCount": "{{count}} file(s) selected", + "clearAll": "Clear All", + "removeFile": "Remove", + "selectedFiles": "Selected Files" + }, + "processing": { + "title": "OCR Processing", + "status": "Status", + "progress": "Progress", + "currentFile": "Current File", + "filesProcessed": "Processed {{processed}} / {{total}} files", + "startProcessing": "Start Processing", + "processing": "Processing...", + "completed": "Completed", + "failed": "Failed", + "pending": "Pending", + "estimatedTime": "Estimated Time Remaining", + "settings": { + "title": "Processing Settings", + "language": "Recognition Language", + "threshold": "Confidence Threshold", + "layoutDetection": "Layout Detection" + }, + "layoutModel": { + "title": "Layout Detection Model", + "chinese": "Chinese Document Model", + "chineseDesc": "PP-DocLayout_plus-L (83.2% mAP) - For complex Chinese documents, supports 20 layout elements (Recommended)", + "default": "Standard Model", + "defaultDesc": "PubLayNet model (~94% mAP) - For English academic papers and reports", + "cdla": "CDLA Model", + "cdlaDesc": "CDLA layout analysis model (~86% mAP) - Specialized for Chinese document layout", + "recommended": "Recommended", + "note": "The layout model affects detection of document structure (tables, text blocks, images). Choose the appropriate model based on your document type." + }, + "tableDetection": { + "title": "Table Detection Mode", + "wired": "Bordered Tables", + "wiredDesc": "Detect tables with visible grid borders, suitable for formal documents", + "wireless": "Borderless Tables", + "wirelessDesc": "Detect tables without borders by analyzing text alignment", + "region": "Region Detection", + "regionDesc": "Auxiliary table region detection for improved cell recognition", + "note": "Multiple detection modes can be enabled simultaneously. The system will automatically integrate results. Adjust detection modes if table cell borders are incorrect." + }, + "preprocessing": { + "title": "Image Preprocessing", + "mode": { + "auto": "Auto Mode", + "autoDesc": "System automatically analyzes image quality and determines optimal preprocessing", + "manual": "Manual Mode", + "manualDesc": "Manually select preprocessing options and intensity for full control", + "disabled": "Disable Preprocessing", + "disabledDesc": "No preprocessing applied, use original image directly" + }, + "recommended": "Recommended", + "preview": "Preview Effect", + "manualConfig": "Manual Configuration", + "contrast": { + "label": "Contrast Enhancement", + "none": "None", + "histogram": "Histogram Equalization", + "clahe": "CLAHE Adaptive Equalization", + "document": "Scan Optimization (Background Correction + CLAHE)" + }, + "sharpen": "Edge Sharpening", + "strength": { + "label": "Intensity", + "subtle": "Subtle", + "normal": "Normal", + "strong": "Strong", + "maximum": "Maximum" + }, + "removeScanArtifacts": "Remove Scan Artifacts", + "removeScanArtifactsDesc": "Remove horizontal lines from scanning to prevent misdetection as table borders", + "advanced": "Advanced Options", + "binarize": "Binarization", + "binarizeWarning": "Not recommended", + "note": "Preprocessing only affects the layout detection stage to improve table and text block recognition. Original images are used for final OCR text extraction to ensure best quality.", + "previewPanel": { + "title": "Preprocessing Preview", + "loading": "Loading preview...", + "loadError": "Failed to load preview", + "refresh": "Refresh Preview", + "original": "Original Image", + "preprocessed": "Preprocessed", + "fullscreen": "Fullscreen View", + "qualityAnalysis": "Image Quality Analysis", + "contrast": "Contrast", + "sharpness": "Sharpness", + "qualityLow": "Low", + "qualityMedium": "Medium", + "qualityHigh": "High", + "qualityBlurry": "Blurry", + "qualityNormal": "Normal", + "qualitySharp": "Sharp", + "autoDetectedConfig": "Auto-detected Settings", + "contrastEnhancement": "Contrast Enhancement", + "sharpenEnabled": "Enabled", + "sharpenDisabled": "Disabled" + } + } + }, + "results": { + "title": "OCR Results", + "filename": "Filename", + "status": "Status", + "confidence": "Confidence", + "processingTime": "Processing Time", + "actions": "Actions", + "viewMarkdown": "View Markdown", + "viewJSON": "View JSON", + "downloadPDF": "Download PDF", + "preview": "Preview", + "noResults": "No results yet", + "textBlocks": "Text Blocks", + "layoutInfo": "Layout Info" + }, + "export": { + "title": "Export Results", + "format": "Export Format", + "formats": { + "txt": "Plain Text (.txt)", + "json": "JSON (.json)", + "excel": "Excel (.xlsx)", + "markdown": "Markdown (.md)", + "pdf": "PDF (.pdf)" + }, + "options": { + "title": "Export Options", + "confidenceThreshold": "Confidence Threshold", + "includeMetadata": "Include Metadata", + "filenamePattern": "Filename Pattern", + "cssTemplate": "CSS Template" + }, + "rules": { + "title": "Export Rules", + "selectRule": "Select Rule", + "saveRule": "Save Rule", + "newRule": "New Rule", + "ruleName": "Rule Name", + "deleteRule": "Delete Rule" + }, + "cssTemplates": { + "default": "Default", + "academic": "Academic", + "business": "Business", + "report": "Report" + }, + "exportButton": "Export", + "exporting": "Exporting...", + "exportSuccess": "Export successful", + "exportError": "Export failed" + }, + "settings": { + "title": "Settings", + "exportRules": "Export Rules Management", + "language": "Language", + "theme": "Theme", + "about": "About" + }, + "common": { + "confirm": "Confirm", + "cancel": "Cancel", + "save": "Save", + "delete": "Delete", + "edit": "Edit", + "close": "Close", + "loading": "Loading...", + "error": "Error", + "success": "Success", + "warning": "Warning", + "info": "Info", + "search": "Search", + "filter": "Filter", + "sort": "Sort", + "refresh": "Refresh", + "back": "Back", + "next": "Next", + "previous": "Previous", + "submit": "Submit" + }, + "errors": { + "networkError": "Network error. Please try again later.", + "unauthorized": "Unauthorized. Please login again.", + "notFound": "Resource not found", + "serverError": "Server error", + "validationError": "Validation error", + "fileTooBig": "File too large", + "unsupportedFormat": "Unsupported format", + "uploadFailed": "Upload failed", + "processingFailed": "Processing failed", + "exportFailed": "Export failed" + }, + "translation": { + "title": "Translation", + "comingSoon": "Coming Soon", + "description": "Document translation feature is under development" + } +} diff --git a/frontend/src/i18n/locales/zh-TW.json b/frontend/src/i18n/locales/zh-TW.json index c813e8c..4c27486 100644 --- a/frontend/src/i18n/locales/zh-TW.json +++ b/frontend/src/i18n/locales/zh-TW.json @@ -9,7 +9,9 @@ "results": "結果檢視", "export": "匯出", "settings": "設定", - "logout": "登出" + "logout": "登出", + "taskHistory": "任務歷史", + "adminDashboard": "管理員儀表板" }, "auth": { "login": "登入", @@ -17,7 +19,12 @@ "password": "密碼", "loginButton": "登入", "loginError": "登入失敗,請檢查帳號密碼", - "welcomeBack": "歡迎回來" + "welcomeBack": "歡迎回來", + "loginPrompt": "登入以使用 OCR 服務", + "loggingIn": "登入中...", + "usernamePlaceholder": "輸入您的使用者名稱", + "passwordPlaceholder": "輸入您的密碼", + "supportedFormats": "支援格式:PDF、圖片、Office 文件" }, "upload": { "title": "上傳檔案", diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 773ae9b..6d40831 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -3,7 +3,8 @@ import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useAuthStore } from '@/store/authStore' import { apiClientV2 } from '@/services/apiV2' -import { Lock, User, LayoutDashboard, AlertCircle, Loader2, Sparkles, Zap, Shield } from 'lucide-react' +import { Lock, User, LayoutDashboard, AlertCircle, Loader2 } from 'lucide-react' +import LanguageSwitcher from '@/components/LanguageSwitcher' export default function LoginPage() { const { t } = useTranslation() @@ -20,10 +21,8 @@ export default function LoginPage() { setLoading(true) try { - // Use V2 API with external authentication const response = await apiClientV2.login({ username, password }) - // Store user info from V2 API response setUser({ id: response.user.id, username: response.user.email, @@ -47,196 +46,114 @@ export default function LoginPage() { } return ( -
- {/* Full-screen Animated Background */} -
- {/* Animated overlay */} -
- - {/* Floating orbs */} -
-
-
- - {/* Grid pattern */} -
-
-
+
+ {/* Top bar with language switcher */} +
+
- {/* Content Container */} -
-
- - {/* Left Side - Branding */} -
- {/* Logo */} -
-
- -
-
-

Tool_OCR

-

智能 OCR 處理平台

-
-
- - {/* Features - Only show on larger screens */} -
-

為什麼選擇我們?

- -
-
-
- -
-
-

高精度識別

-

AI 驅動的 OCR 引擎,識別準確率高達 99%

-
-
- -
-
- -
-
-

閃電般快速

-

批量處理數百份文件,大幅提升工作效率

-
-
- -
-
- -
-
-

安全可靠

-

企業級加密,確保您的資料絕對安全

-
-
-
-
- - {/* Stats */} -
-
-
99%
-
準確率
-
-
-
10+
-
支援格式
-
-
-
24/7
-
全天候
-
+ {/* Centered login form */} +
+
+ {/* Logo and title */} +
+
+
+

{t('app.title')}

+

{t('app.subtitle')}

- {/* Right Side - Login Form */} -
-
-
-

歡迎回來

-

登入以開始使用 OCR 服務

+ {/* Login card */} +
+
+

{t('auth.welcomeBack')}

+

{t('auth.loginPrompt')}

+
+ +
+ {/* Username */} +
+ +
+
+ +
+ setUsername(e.target.value)} + className="w-full pl-10 pr-4 py-2.5 bg-background border border-border rounded-lg + text-foreground placeholder-muted-foreground + focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary + transition-colors" + placeholder={t('auth.usernamePlaceholder')} + required + /> +
- - {/* Username */} -
- -
-
- -
- setUsername(e.target.value)} - className="w-full pl-11 pr-4 py-3 bg-gray-50 border-2 border-gray-200 rounded-xl - text-gray-900 placeholder-gray-400 - focus:outline-none focus:ring-4 focus:ring-blue-500/20 focus:border-blue-500 - hover:border-gray-300 - transition-all duration-200" - placeholder="輸入您的用戶名" - required - /> + {/* Password */} +
+ +
+
+
+ setPassword(e.target.value)} + className="w-full pl-10 pr-4 py-2.5 bg-background border border-border rounded-lg + text-foreground placeholder-muted-foreground + focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary + transition-colors" + placeholder={t('auth.passwordPlaceholder')} + required + />
+
- {/* Password */} -
- -
-
- -
- setPassword(e.target.value)} - className="w-full pl-11 pr-4 py-3 bg-gray-50 border-2 border-gray-200 rounded-xl - text-gray-900 placeholder-gray-400 - focus:outline-none focus:ring-4 focus:ring-blue-500/20 focus:border-blue-500 - hover:border-gray-300 - transition-all duration-200" - placeholder="輸入您的密碼" - required - /> -
+ {/* Error message */} + {error && ( +
+ +

{error}

+ )} - {/* Error */} - {error && ( -
- -

{error}

-
- )} - - {/* Submit Button */} - - - - {/* Footer */} -
-

- Powered by AI Technology -

-
-
+ ) : ( + t('auth.loginButton') + )} + +
+ + {/* Supported formats info */} +

+ {t('auth.supportedFormats')} +

diff --git a/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/proposal.md b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/proposal.md new file mode 100644 index 0000000..f030b8b --- /dev/null +++ b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/proposal.md @@ -0,0 +1,38 @@ +# Change: 前端 UX 簡化與 i18n 英文支援 + +## Why + +目前登入頁面設計過於花俏(漸層動畫、浮動光球、脈衝效果),與內部頁面的專業簡約風格不一致。此外,頁面包含不實宣傳文案(如「99% 準確率」、「企業級加密」等未經證實的聲明)。系統目前僅支援繁體中文,缺乏多語言支援。 + +## What Changes + +### 1. LoginPage 簡化 +- 移除花俏動畫效果(浮動光球、網格圖案、脈衝動畫) +- 移除漸層背景,改用簡潔單色背景 +- 移除不實宣傳區塊(「為什麼選擇我們」、統計數據卡片) +- 統一登入頁與內部頁面視覺風格 + +### 2. 文案修正 +- 移除誇大宣稱(「99% 準確率」、「閃電般快速」、「企業級加密」) +- 改用務實功能描述 + +### 3. i18n 擴充 +- 新增英文 (en-US) 翻譯檔案 +- 新增語言切換功能元件 +- 儲存使用者語言偏好至 localStorage +- 將語言切換器整合至 Layout 頂部欄 + +### 4. 整體風格統一 +- 確保所有頁面使用一致的設計語言 +- 遵循專業簡約風格準則 + +## Impact + +- Affected specs: frontend-ui (新增) +- Affected code: + - `frontend/src/pages/LoginPage.tsx` - 重新設計 + - `frontend/src/components/Layout.tsx` - 新增語言切換器 + - `frontend/src/i18n/index.ts` - 擴充多語言設定 + - `frontend/src/i18n/locales/en-US.json` - 新增英文翻譯 + - `frontend/src/i18n/locales/zh-TW.json` - 補充缺少的翻譯鍵 + - `frontend/src/components/LanguageSwitcher.tsx` - 新增元件 diff --git a/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/specs/frontend-ui/spec.md b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/specs/frontend-ui/spec.md new file mode 100644 index 0000000..c3b6bfb --- /dev/null +++ b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/specs/frontend-ui/spec.md @@ -0,0 +1,89 @@ +# Frontend UI Specification + +## ADDED Requirements + +### Requirement: Minimal Login Page Design + +The login page SHALL use a professional minimal design style that is consistent with the rest of the application. + +The login page SHALL NOT include: +- Animated gradient backgrounds +- Floating decorative elements (orbs, particles) +- Pulsing or floating animations +- Marketing claims or statistics +- Feature promotion sections + +The login page SHALL include: +- Centered login form with clean white card +- Application logo and name +- Username and password input fields +- Login button with loading state +- Error message display area +- Simple solid color background + +#### Scenario: Login page renders with minimal design +- **WHEN** user navigates to the login page +- **THEN** the page displays a centered login form +- **AND** no animated decorative elements are visible +- **AND** no marketing content is displayed + +#### Scenario: Login form visual consistency +- **WHEN** comparing login page to internal pages +- **THEN** the visual style (colors, typography, spacing) is consistent + +--- + +### Requirement: Multi-language Support + +The application SHALL support multiple languages with user-selectable language preference. + +Supported languages: +- Traditional Chinese (zh-TW) - Default +- English (en-US) + +The language selection SHALL be persisted in localStorage and restored on page reload. + +#### Scenario: Language switcher available +- **WHEN** user is logged in and viewing any page +- **THEN** a language switcher component is visible in the top navigation bar + +#### Scenario: Switch to English +- **WHEN** user selects English from the language switcher +- **THEN** all UI text immediately changes to English +- **AND** the preference is saved to localStorage + +#### Scenario: Switch to Traditional Chinese +- **WHEN** user selects Traditional Chinese from the language switcher +- **THEN** all UI text immediately changes to Traditional Chinese +- **AND** the preference is saved to localStorage + +#### Scenario: Language preference persistence +- **WHEN** user has previously selected a language preference +- **AND** user reloads the page or returns later +- **THEN** the application displays in the previously selected language + +--- + +### Requirement: Accurate Product Description + +All user-facing text SHALL accurately describe the product capabilities without exaggeration. + +The application SHALL NOT display: +- Unverified accuracy percentages (e.g., "99% accuracy") +- Superlative marketing claims (e.g., "lightning fast", "enterprise-grade") +- Unsubstantiated statistics +- Comparative claims without evidence + +The application MAY display: +- Factual feature descriptions +- Supported file formats +- Authentication method information + +#### Scenario: Login page displays factual information +- **WHEN** user views the login page +- **THEN** only factual product information is displayed +- **AND** no unverified claims are present + +#### Scenario: Feature descriptions are accurate +- **WHEN** any page describes product features +- **THEN** the descriptions are factual and verifiable diff --git a/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/tasks.md b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/tasks.md new file mode 100644 index 0000000..1336020 --- /dev/null +++ b/openspec/changes/archive/2025-12-12-refactor-frontend-ux-i18n/tasks.md @@ -0,0 +1,29 @@ +# Tasks: 前端 UX 簡化與 i18n 英文支援 + +## 1. LoginPage 簡化 + +- [x] 1.1 移除動畫背景元素(浮動光球、網格圖案、脈衝效果) +- [x] 1.2 替換漸層背景為簡潔單色背景 +- [x] 1.3 移除左側宣傳區塊(「為什麼選擇我們」、功能特色、統計數據) +- [x] 1.4 重新設計登入表單區塊,採用居中簡約版面 +- [x] 1.5 移除不必要的動畫 class(animate-float, animate-slide-in-left 等) + +## 2. i18n 英文支援 + +- [x] 2.1 建立 `frontend/src/i18n/locales/en-US.json` 英文翻譯檔 +- [x] 2.2 更新 `frontend/src/i18n/index.ts` 支援多語言切換 +- [x] 2.3 補充 `zh-TW.json` 缺少的翻譯鍵(登入頁相關) + +## 3. 語言切換功能 + +- [x] 3.1 建立 `frontend/src/components/LanguageSwitcher.tsx` 元件 +- [x] 3.2 整合語言切換器至 `Layout.tsx` 頂部欄 +- [x] 3.3 實作語言偏好 localStorage 持久化 +- [x] 3.4 確保語言切換即時生效(無需重新載入頁面) + +## 4. 測試與驗證 + +- [x] 4.1 驗證 LoginPage 在不同螢幕尺寸的顯示效果 +- [x] 4.2 驗證中英文切換功能正常運作 +- [x] 4.3 驗證語言偏好在頁面重新載入後保持 +- [x] 4.4 檢查所有頁面的翻譯完整性 diff --git a/openspec/specs/frontend-ui/spec.md b/openspec/specs/frontend-ui/spec.md new file mode 100644 index 0000000..8c35d36 --- /dev/null +++ b/openspec/specs/frontend-ui/spec.md @@ -0,0 +1,91 @@ +# frontend-ui Specification + +## Purpose +TBD - created by archiving change refactor-frontend-ux-i18n. Update Purpose after archive. +## Requirements +### Requirement: Minimal Login Page Design + +The login page SHALL use a professional minimal design style that is consistent with the rest of the application. + +The login page SHALL NOT include: +- Animated gradient backgrounds +- Floating decorative elements (orbs, particles) +- Pulsing or floating animations +- Marketing claims or statistics +- Feature promotion sections + +The login page SHALL include: +- Centered login form with clean white card +- Application logo and name +- Username and password input fields +- Login button with loading state +- Error message display area +- Simple solid color background + +#### Scenario: Login page renders with minimal design +- **WHEN** user navigates to the login page +- **THEN** the page displays a centered login form +- **AND** no animated decorative elements are visible +- **AND** no marketing content is displayed + +#### Scenario: Login form visual consistency +- **WHEN** comparing login page to internal pages +- **THEN** the visual style (colors, typography, spacing) is consistent + +--- + +### Requirement: Multi-language Support + +The application SHALL support multiple languages with user-selectable language preference. + +Supported languages: +- Traditional Chinese (zh-TW) - Default +- English (en-US) + +The language selection SHALL be persisted in localStorage and restored on page reload. + +#### Scenario: Language switcher available +- **WHEN** user is logged in and viewing any page +- **THEN** a language switcher component is visible in the top navigation bar + +#### Scenario: Switch to English +- **WHEN** user selects English from the language switcher +- **THEN** all UI text immediately changes to English +- **AND** the preference is saved to localStorage + +#### Scenario: Switch to Traditional Chinese +- **WHEN** user selects Traditional Chinese from the language switcher +- **THEN** all UI text immediately changes to Traditional Chinese +- **AND** the preference is saved to localStorage + +#### Scenario: Language preference persistence +- **WHEN** user has previously selected a language preference +- **AND** user reloads the page or returns later +- **THEN** the application displays in the previously selected language + +--- + +### Requirement: Accurate Product Description + +All user-facing text SHALL accurately describe the product capabilities without exaggeration. + +The application SHALL NOT display: +- Unverified accuracy percentages (e.g., "99% accuracy") +- Superlative marketing claims (e.g., "lightning fast", "enterprise-grade") +- Unsubstantiated statistics +- Comparative claims without evidence + +The application MAY display: +- Factual feature descriptions +- Supported file formats +- Authentication method information + +#### Scenario: Login page displays factual information +- **WHEN** user views the login page +- **THEN** only factual product information is displayed +- **AND** no unverified claims are present + +#### Scenario: Feature descriptions are accurate +- **WHEN** any page describes product features +- **THEN** the descriptions are factual and verifiable +