feat: complete the 1.5.2 language set (es/fr/de/ja/ko) and fix the reported version

The dictionary layer shipped with en/zh only, so the five other translations
were stranded outside the release while the notes described a bilingual UI.
Register them: seven languages, 1001 keys each, all typed against `Dict` so a
missing key fails the build instead of rendering the raw key.

Also align `__version__`, which had stayed at 1.4.1 through the 1.5.0 and 1.5.1
releases, leaving /api/health and the OpenAPI schema reporting a stale version.
The bat scripts now emit English so non-Chinese locales render them correctly.

Docs: docs/changelogs/2026-09-16-multilingual-ui.md
This commit is contained in:
Benjiyaya
2026-09-16 04:00:14 +08:00
parent fc7611ce7d
commit a3588a2024
15 changed files with 5463 additions and 64 deletions
+1 -1
View File
@@ -4,4 +4,4 @@
# reads this; pyproject.toml is kept in sync for the build (hatchling dynamic
# version reads this file). PR #47: hard-coded literals drifted twice
# (1.3.2 shipped reporting 1.2.1; 1.4.1's /api/health still said 1.4.0).
__version__ = "1.4.1"
__version__ = "1.5.2"
@@ -9,7 +9,12 @@
aria-label={t('common.language')}
onchange={(e) => setLanguage(e.currentTarget.value as Language)}
>
<option value="de">Deutsch</option>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
<option value="zh">中文</option>
</select>
+15 -3
View File
@@ -1,17 +1,29 @@
import { de } from './i18n/de';
import { en } from './i18n/en';
import { es } from './i18n/es';
import { fr } from './i18n/fr';
import { ja } from './i18n/ja';
import { ko } from './i18n/ko';
import { zh } from './i18n/zh';
export type Language = 'en' | 'zh';
export type Language = 'en' | 'zh' | 'es' | 'fr' | 'de' | 'ja' | 'ko';
export type Dict = typeof en;
const dictionaries: Record<Language, Record<string, string>> = { en, zh };
const dictionaries: Record<Language, Record<string, string>> = { en, zh, es, fr, de, ja, ko };
const STORAGE_KEY = 'calliope-lang';
function isLanguage(value: string | null): value is Language {
return value !== null && Object.hasOwn(dictionaries, value);
}
function initialLanguage(): Language {
if (typeof localStorage === 'undefined') return 'en';
return localStorage.getItem(STORAGE_KEY) === 'zh' ? 'zh' : 'en';
// Validate against the registered dictionaries — a stored value from a
// language this build no longer ships must not blank the UI.
const stored = localStorage.getItem(STORAGE_KEY);
return isLanguage(stored) ? stored : 'en';
}
export const language = $state<{ current: Language }>({ current: initialLanguage() });
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,35 +0,0 @@
# Calliope 1.5.2 — bilingual UI (English / 中文) and one-command local start
Every user-facing string used to be hardcoded English, spread across ~60
components — so a Chinese-speaking user saw an English UI no matter how the app
was configured, and there was no single place to change a label. This release
routes the whole interface through a dictionary layer with a language switcher
in the header.
## What changed
- **Full en/zh dictionary** — 1001 keys, mirrored 1:1 between `en.ts` and
`zh.ts`. Both are typed against `Dict` (`typeof en`), so the compiler rejects
a translation that is missing a key.
- **Every component wired through `t()`** — nav rail, canvas, projects, story,
assets, script, queue, the video workspace, Build Scene, settings, agent chat,
toasts, and the error paths. No hardcoded English copy remains in the UI.
- **Language switcher in the header** — English / 中文. The choice is stored in
`localStorage` (`calliope-lang`) and applied on reload; a missing or
unrecognized value falls back to English.
- **Placeholder interpolation** — `t('key', { name: … })` substitutes `{name}`,
with a `count` shorthand that also fills `{n}`, the convention most
count-bearing strings use.
- **Genre / tone / duration options** moved into `formOptions.ts`, mapping the
English values the backend stores onto dictionary keys — so stored project
data keeps working regardless of the display language.
- **Local start/stop scripts** — `setup.bat` (idempotent first-time install),
`start.bat` (two visible windows), `start-bg.bat` (background, output to
`logs/`), and `stop.bat`.
## Upgrade
No migration and no new dependencies. `git pull`, then reload the frontend — an
`npm install` in `calliope-web/` is only needed if you are coming from an older
release. The UI defaults to English; switch to 中文 with the dropdown in the
header.
@@ -0,0 +1,37 @@
# Calliope 1.5.2 — seven-language UI (en/zh/es/fr/de/ja/ko) and local start scripts
Every user-facing string used to be hardcoded English, spread across dozens of
components — so a non-English user saw an English UI no matter how the app was
configured, and there was no single place to change a label. The interface now
resolves through a dictionary layer, with a language switcher in the header.
## What changed
- **Seven languages** — English, 中文, Español, Français, Deutsch, 日本語,
한국어. Each dictionary carries the full 1001 keys and is typed against `Dict`
(`typeof en`), so a translation that is missing a key fails the build rather
than silently rendering the key.
- **Language switcher in the header** — the choice is stored in `localStorage`
(`calliope-lang`) and applied on reload; a missing or unrecognized stored
value falls back to English instead of blanking the UI.
- **Every component wired through `t()`** — nav rail, canvas, projects, story,
assets, script, queue, the video workspace, Build Scene, settings, agent chat,
toasts, and the error paths. No hardcoded English copy remains in the UI.
- **Placeholder interpolation** — `t('key', { name: … })` substitutes `{name}`,
with a `count` shorthand that also fills `{n}`, the convention most
count-bearing strings use.
- **Genre / tone / duration options** moved into `formOptions.ts`, mapping the
English values the backend stores onto dictionary keys — so stored project
data keeps working regardless of the display language.
- **Backend version reports correctly** — `/api/health` and the OpenAPI schema
read `__version__`, which had been stuck at `1.4.1` while 1.5.0 and 1.5.1
shipped. It now matches the frontend at `1.5.2`.
- **Local start/stop scripts** — `setup.bat` (idempotent first-time install),
`start.bat` (two visible windows), `start-bg.bat` (background, output to
`logs/`), and `stop.bat`, all with English output so non-Chinese locales
render them without mojibake.
## Upgrade
No migration and no new dependencies. `git pull`, then reload the frontend. The
UI defaults to English; pick another language from the dropdown in the header.
+1 -1
View File
@@ -2,7 +2,7 @@
Dated notes for GitHub releases. Newest first.
- [2026-09-16 bilingual UI](./2026-09-16-bilingual-ui.md) — en/zh dictionary across every component; header language switcher; local start scripts (1.5.2)
- [2026-09-16 multilingual UI](./2026-09-16-multilingual-ui.md) — seven-language UI (en/zh/es/fr/de/ja/ko); header language switcher; correct backend version; local start scripts (1.5.2)
- [2026-09-13 clip shot brief](./2026-09-13-clip-shot-brief.md) — per-clip brief in the Video composer; two-column Video stage (1.5.1)
- [2026-09-10 Build Scene + scene → clips](./2026-09-10-build-scene-clips.md) — 3D blockout composer; vision/doc input; 1 scene : N shot clips; faithful scripts (1.5.0)
- [2026-09-07 chunking + cards](./2026-09-07-chunking-cards.md) — Story/script generate in chunks; ask_user cards appear (1.4.1)
+8 -7
View File
@@ -1,34 +1,35 @@
@echo off
chcp 936 >nul
setlocal
set ROOT=%~dp0
set BACKEND=%ROOT%calliope-backend
set WEB=%ROOT%calliope-web
echo ============================================
echo Calliope First-time setup / Calliope 首次安装(幂等,可重复运行)
echo Calliope first-time setup - idempotent, safe to re-run
echo ============================================
if not exist "%BACKEND%\.venv\Scripts\python.exe" (
echo [1/2] Creating venv and installing backend deps / 创建虚拟环境并安装后端依赖...
echo [1/2] Creating venv and installing backend deps...
cd /d "%BACKEND%"
python -m venv .venv
call .venv\Scripts\activate.bat
.venv\Scripts\python -m pip install --upgrade pip
.venv\Scripts\pip install -e ".[dev]"
) else (
echo [1/2] Backend deps already installed - skipping / 后端依赖已安装,跳过。
echo [1/2] Backend deps already installed - skipping
)
if not exist "%WEB%\node_modules" (
echo [2/2] Installing frontend deps, running npm install... / 安装前端依赖 npm install...
echo [2/2] Installing frontend deps, running npm install...
cd /d "%WEB%"
call npm install
) else (
echo [2/2] Frontend deps already installed - skipping / 前端依赖已安装,跳过。
echo [2/2] Frontend deps already installed - skipping
)
echo.
echo Setup complete / 安装完成。Copy calliope_config.example.json to calliope_config.json before first launch to configure LLM/ComfyUI, or configure in the in-app Settings page / 首次启动前可复制 calliope_config.example.json 为 calliope_config.json 配置 LLM/ComfyUI,也可以在应用内 Settings 页面配置。
echo Setup complete.
echo Before the first launch, copy calliope_config.example.json to calliope_config.json
echo to configure LLM/ComfyUI, or configure them on the in-app Settings page.
echo.
pause
+8 -7
View File
@@ -1,29 +1,30 @@
@echo off
chcp 936 >nul
setlocal
set ROOT=%~dp0
set BACKEND=%ROOT%calliope-backend
set WEB=%ROOT%calliope-web
if not exist "%BACKEND%\.venv\Scripts\python.exe" (
echo [Error/错误] Backend not installed - run setup.bat first / 后端未安装,请先运行 setup.bat
echo [Error] Backend not installed - run setup.bat first
pause
exit /b 1
)
if not exist "%WEB%\node_modules" (
echo [Error/错误] Frontend not installed - run setup.bat first / 前端未安装,请先运行 setup.bat
echo [Error] Frontend not installed - run setup.bat first
pause
exit /b 1
)
if not exist "%ROOT%logs" mkdir "%ROOT%logs"
echo Starting backend in background / 后台启动后端... Log/日志: logs\backend.log
echo Starting backend in background... Log: logs\backend.log
powershell -NoProfile -Command "$p = Start-Process -FilePath '%ROOT%calliope-backend\.venv\Scripts\python.exe' -ArgumentList '-m','calliope.main','--host','127.0.0.1','--port','8247' -WorkingDirectory '%ROOT%calliope-backend' -RedirectStandardOutput '%ROOT%logs\backend.log' -RedirectStandardError '%ROOT%logs\backend.err.log' -PassThru -WindowStyle Hidden; Write-Host ('Backend PID -> ' + $p.Id)"
echo Starting frontend in background / 后台启动前端... Log/日志: logs\web.log
echo Starting frontend in background... Log: logs\web.log
powershell -NoProfile -Command "$p = Start-Process -FilePath 'npm.cmd' -ArgumentList 'run','dev' -WorkingDirectory '%ROOT%calliope-web' -RedirectStandardOutput '%ROOT%logs\web.log' -RedirectStandardError '%ROOT%logs\web.err.log' -PassThru -WindowStyle Hidden; Write-Host ('Web npm PID -> ' + $p.Id)"
echo.
echo Background services started / 后台服务已启动:Backend/后端 http://127.0.0.1:8247 Frontend/前端 http://127.0.0.1:5173
echo Run stop.bat to stop them / 用 stop.bat 停止
echo Background services started:
echo Backend: http://127.0.0.1:8247
echo Frontend: http://127.0.0.1:5173
echo Run stop.bat to stop them.
+6 -7
View File
@@ -1,25 +1,24 @@
@echo off
chcp 936 >nul
setlocal
set ROOT=%~dp0
set BACKEND=%ROOT%calliope-backend
set WEB=%ROOT%calliope-web
if not exist "%BACKEND%\.venv\Scripts\python.exe" (
echo [Error/错误] Backend not installed - run setup.bat first / 后端未安装,请先运行 setup.bat
echo [Error] Backend not installed - run setup.bat first
pause
exit /b 1
)
if not exist "%WEB%\node_modules" (
echo [Error/错误] Frontend not installed - run setup.bat first / 前端未安装,请先运行 setup.bat
echo [Error] Frontend not installed - run setup.bat first
pause
exit /b 1
)
echo Opening two windows / 打开两个窗口:
echo Backend/后端 http://127.0.0.1:8247
echo Frontend/前端 http://127.0.0.1:5173
echo Close a window to stop that service / 关闭窗口即停止对应服务
echo Opening two windows
echo Backend: http://127.0.0.1:8247
echo Frontend: http://127.0.0.1:5173
echo Close a window to stop that service
start "Calliope Backend" /D "%BACKEND%" cmd /k ".venv\Scripts\python -m calliope.main --host 127.0.0.1 --port 8247"
start "Calliope Web" /D "%WEB%" cmd /k "npm run dev"
+2 -3
View File
@@ -1,13 +1,12 @@
@echo off
chcp 936 >nul
setlocal
set ROOT=%~dp0
echo Stopping Calliope backend and frontend processes / 正在停止 Calliope 后端和前端进程...
echo Stopping Calliope backend and frontend processes...
powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object { $_.Name -match '^(python|node)(\.exe)?$' -and $_.CommandLine -match 'calliope' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue; Write-Host ('Killed ' + $_.Name + ' PID ' + $_.ProcessId) }"
echo.
echo Done. If leftover windows remain, close them manually / 已停止。若还有残留窗口,可直接关闭对应 cmd 窗口。
echo Done. If leftover windows remain, close them manually.
echo.
pause