feat(update): 下载进度到 100% 后由用户点击「重启应用更新」

- 取消 macOS 下载完成后自动安装/退出,Win/Mac 统一交互
- 进度弹窗在 100% 显示就绪提示,主按钮改为「重启应用更新」
- 关于页安装入口同步文案;点击后才执行安装脚本并重启
- 补充多语言与前端回归测试
This commit is contained in:
Syngnat
2026-07-09 13:38:07 +08:00
parent d31bb978f2
commit cdfbdd5dd5
9 changed files with 192 additions and 66 deletions

View File

@@ -4201,8 +4201,8 @@ function App() {
</Button>
) : null,
isLatestUpdateDownloaded ? (
<Button key="install-direct" type="primary" icon={<DownloadOutlined />} onClick={handleInstallFromProgress}>
{t('app.about.action.install_update')}
<Button key="restart-to-update" type="primary" icon={<DownloadOutlined />} onClick={handleInstallFromProgress}>
{t('app.about.action.restart_to_update')}
</Button>
) : null,
].filter(Boolean);
@@ -7961,8 +7961,8 @@ function App() {
<Button key="open-install-directory" onClick={openDownloadedUpdateDirectory}>
{t('app.about.action.open_install_directory')}
</Button>,
<Button key="install" type="primary" onClick={handleInstallFromProgress}>
{t('app.about.action.install_update')}
<Button key="restart" type="primary" onClick={handleInstallFromProgress}>
{t('app.about.action.restart_to_update')}
</Button>
] : (updateDownloadProgress.status === 'error' ? [
<Button key="close" onClick={hideUpdateDownloadProgress}>{t('common.close')}</Button>
@@ -7974,10 +7974,20 @@ function App() {
status={updateDownloadProgress.status === 'error' ? 'exception' : (updateDownloadProgress.status === 'done' ? 'success' : 'active')}
/>
<div style={{ fontSize: 12, color: darkMode ? 'rgba(255,255,255,0.5)' : 'rgba(16,24,40,0.55)' }}>
{`${formatBytes(updateDownloadProgress.downloaded)} / ${formatBytes(updateDownloadProgress.total)}`}
{updateDownloadProgress.status === 'done'
? t('app.about.download_progress.complete_hint')
: `${formatBytes(updateDownloadProgress.downloaded)} / ${formatBytes(updateDownloadProgress.total)}`}
</div>
{updateDownloadProgress.message ? (
<div style={{ fontSize: 12, color: '#ff4d4f' }}>{updateDownloadProgress.message}</div>
<div style={{
fontSize: 12,
color: updateDownloadProgress.status === 'error'
? '#ff4d4f'
: (darkMode ? 'rgba(255,255,255,0.65)' : 'rgba(16,24,40,0.65)'),
}}
>
{updateDownloadProgress.message}
</div>
) : null}
</div>
</Modal>

View File

@@ -161,7 +161,7 @@ describe('useAppUpdateManager', () => {
expect(hook?.lastUpdateInfo?.downloaded).toBe(true);
});
it('auto-installs a macOS update immediately after download when the backend reports auto relaunch support', async () => {
it('keeps download at 100% ready-to-restart without auto-installing after download completes', async () => {
backendApp.CheckForUpdates.mockResolvedValue({
success: true,
data: {
@@ -193,8 +193,39 @@ describe('useAppUpdateManager', () => {
});
expect(backendApp.DownloadUpdate).toHaveBeenCalledTimes(1);
expect(backendApp.InstallUpdateAndRestart).toHaveBeenCalledTimes(1);
// 下载完成后不自动安装;用户需点击「重启应用更新」
expect(backendApp.InstallUpdateAndRestart).not.toHaveBeenCalled();
expect(backendApp.OpenDownloadedUpdateDirectory).not.toHaveBeenCalled();
expect(hook?.updateDownloadProgress.status).toBe('done');
expect(hook?.updateDownloadProgress.percent).toBe(100);
expect(hook?.updateDownloadProgress.open).toBe(true);
expect(hook?.lastUpdateInfo?.downloaded).toBe(true);
});
it('installs and restarts only after the user confirms restart-to-update', async () => {
backendApp.CheckForUpdates.mockResolvedValue({
success: true,
data: {
hasUpdate: true,
currentVersion: '0.8.1',
latestVersion: '0.8.2',
downloaded: true,
assetSize: 2048,
},
});
backendApp.InstallUpdateAndRestart.mockResolvedValue({ success: true });
renderHook();
await act(async () => {
await hook?.checkForUpdates(false);
});
await act(async () => {
await hook?.handleInstallFromProgress();
});
expect(backendApp.InstallUpdateAndRestart).toHaveBeenCalledTimes(1);
});
it('switches update channel and re-checks against the selected channel', async () => {

View File

@@ -129,11 +129,6 @@ const normalizeAboutInfo = (value: unknown): AboutInfo => {
};
};
const shouldAutoInstallDownloadedUpdate = (resultData: UpdateDownloadResultData | null | undefined): boolean => {
const platform = String(resultData?.platform || '').trim().toLowerCase();
return platform === 'darwin' && resultData?.autoRelaunch !== false;
};
export const useAppUpdateManager = ({
runtimeBuildType,
t,
@@ -191,7 +186,7 @@ export const useAppUpdateManager = ({
const localDownloaded = updateDownloadedVersionRef.current === buildUpdateKey(info);
const hasDownloaded = Boolean(info.downloaded) || localDownloaded;
return hasDownloaded
? t('app.about.update_status.new_version_downloaded', { version: info.latestVersion })
? t('app.about.update_status.new_version_ready_restart', { version: info.latestVersion })
: t('app.about.update_status.new_version_not_downloaded', { version: info.latestVersion });
}
return t('app.about.update_status.latest', { version: info.currentVersion || t('common.unknown') });
@@ -273,27 +268,22 @@ export const useAppUpdateManager = ({
downloadPath: resultData?.downloadPath || prev.downloadPath || info.downloadPath,
};
});
if (resultData?.downloadPath) {
void message.success({ content: t('app.about.message.download_completed_with_path', { path: resultData.downloadPath }), duration: 5 });
} else {
void message.success({ content: t('app.about.message.download_completed'), duration: 2 });
}
// 与 Terminus/Codex 一致:下载到 100% 后停留在就绪态,由用户点击「重启应用更新」
setUpdateDownloadProgress((prev) => ({
...prev,
open: true,
status: 'done',
percent: 100,
downloaded: prev.total > 0 ? prev.total : (info.assetSize || prev.downloaded),
message: t('app.about.download_progress.ready_to_restart'),
}));
void message.success({
content: resultData?.downloadPath
? t('app.about.message.download_ready_restart_with_path', { path: resultData.downloadPath })
: t('app.about.message.download_ready_restart'),
duration: 4,
});
setAboutUpdateStatus(formatAboutUpdateStatus({ ...info, channel: normalizeUpdateChannel(info.channel), downloaded: true }));
if (shouldAutoInstallDownloadedUpdate(resultData)) {
let installRes: any = null;
try {
installRes = await (window as any).go?.app?.App?.InstallUpdateAndRestart?.();
} catch (error: any) {
installRes = { success: false, message: error?.message || t('common.unknown') };
}
if (!installRes?.success) {
void message.error(t('app.about.message.install_failed_with_error', { error: installRes?.message || t('common.unknown') }));
return;
}
updateInstallTriggeredVersionRef.current = targetKey || null;
setUpdateDownloadProgress((prev) => ({ ...prev, open: false }));
}
} else {
setUpdateDownloadProgress((prev) => ({
...prev,
@@ -335,14 +325,40 @@ export const useAppUpdateManager = ({
if (!canInstall) {
return;
}
const res = await (window as any).go.app.App.InstallUpdateAndRestart();
// 点击后进入「正在应用并重启」态,再拉起安装脚本并退出
setUpdateDownloadProgress((prev) => ({
...prev,
open: true,
status: 'downloading',
percent: 100,
message: t('app.about.download_progress.applying_restart'),
}));
let res: any = null;
try {
res = await (window as any).go?.app?.App?.InstallUpdateAndRestart?.();
} catch (error: any) {
res = { success: false, message: error?.message || t('common.unknown') };
}
if (!res?.success) {
setUpdateDownloadProgress((prev) => ({
...prev,
open: true,
status: 'error',
message: res?.message || t('common.unknown'),
}));
void message.error(t('app.about.message.install_failed_with_error', { error: res?.message || t('common.unknown') }));
return;
}
updateInstallTriggeredVersionRef.current = lastUpdateKey || null;
hideUpdateDownloadProgress();
}, [hideUpdateDownloadProgress, lastUpdateInfo, lastUpdateKey, t, updateDownloadProgress.status]);
// 后端会 Quit此处保持弹窗文案避免用户误以为失败
setUpdateDownloadProgress((prev) => ({
...prev,
open: true,
status: 'done',
percent: 100,
message: t('app.about.download_progress.restarting'),
}));
}, [lastUpdateInfo, lastUpdateKey, t, updateDownloadProgress.status]);
const openDownloadedUpdateDirectory = useCallback(async () => {
const backendApp = (window as any).go?.app?.App;
@@ -620,16 +636,31 @@ export const useAppUpdateManager = ({
? event.percent
: (total > 0 ? (downloaded / total) * 100 : 0);
const percent = Math.max(0, Math.min(100, percentRaw));
setUpdateDownloadProgress((prev) => ({
open: prev.open,
version: prev.version,
key: prev.key,
status: nextStatus,
percent,
downloaded,
total,
message: String(event.message || ''),
}));
setUpdateDownloadProgress((prev) => {
// 用户已点「重启应用更新」时,不让 downloading 事件把 100% 就绪态打回中间态文案
if (updateInstallTriggeredVersionRef.current && prev.key && updateInstallTriggeredVersionRef.current === prev.key) {
return prev;
}
const eventMessage = String(event.message || '');
let message = eventMessage;
if (!message) {
if (nextStatus === 'done') {
message = t('app.about.download_progress.ready_to_restart');
} else if (nextStatus === 'start' || nextStatus === 'downloading') {
message = t('app.about.download_progress.downloading');
}
}
return {
open: prev.open || nextStatus === 'start' || nextStatus === 'downloading' || nextStatus === 'done' || nextStatus === 'error',
version: prev.version,
key: prev.key,
status: nextStatus,
percent: nextStatus === 'done' ? 100 : percent,
downloaded: nextStatus === 'done' && total > 0 ? total : downloaded,
total: total > 0 ? total : prev.total,
message,
};
});
});
} catch (e) {
console.warn('Wails API: EventsOn unavailable', e);
@@ -637,7 +668,7 @@ export const useAppUpdateManager = ({
return () => {
if (offDownloadProgress) offDownloadProgress();
};
}, []);
}, [t]);
return {
aboutDisplayVersion,

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "Downloadfortschritt",
"app.about.action.download_update": "Update herunterladen",
"app.about.action.hide_to_background": "Im Hintergrund ausblenden",
"app.about.action.install_update": "Update installieren",
"app.about.action.install_update": "Zum Aktualisieren neu starten",
"app.about.action.mute_this_version": "Diesmal nicht erinnern",
"app.about.action.open_install_directory": "Installationsordner öffnen",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "Updateprüfung fehlgeschlagen: {{error}}",
"app.about.update_status.checking": "Suche nach Updates...",
"app.about.update_status.latest": "Sie verwenden die neueste Version ({{version}})",
"app.about.update_status.new_version_downloaded": "Neue Version {{version}} gefunden (heruntergeladen; öffnen Sie den Downloadfortschritt zur Installation)",
"app.about.update_status.new_version_downloaded": "Neue Version {{version}} heruntergeladen. Neu starten zum Aktualisieren.",
"app.about.update_status.new_version_not_downloaded": "Neue Version {{version}} gefunden (nicht heruntergeladen)",
"app.about.update_status.not_checked": "Nicht geprüft",
"app.about.version.current": "Aktuelle Version",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "Öffnet als ziehbar/skalierbar schwebendes Fenster.",
"ai_settings.open_mode.message.dock": "Standard auf Seitenleiste gesetzt",
"ai_settings.open_mode.message.detached": "Standard auf schwebendes Fenster gesetzt",
"ai_settings.context.section_title": "Kontextstufe"
"ai_settings.context.section_title": "Kontextstufe",
"app.about.action.restart_to_update": "Zum Aktualisieren neu starten",
"app.about.download_progress.ready_to_restart": "Download abgeschlossen (100%). Klicken Sie auf „Zum Aktualisieren neu starten“.",
"app.about.download_progress.downloading": "Update wird heruntergeladen…",
"app.about.download_progress.applying_restart": "Update wird angewendet und neu gestartet…",
"app.about.download_progress.restarting": "Neustart…",
"app.about.download_progress.complete_hint": "Update-Paket bereit (100%)",
"app.about.message.download_ready_restart": "Update heruntergeladen. Klicken Sie auf „Zum Aktualisieren neu starten“.",
"app.about.message.download_ready_restart_with_path": "Update heruntergeladen. Klicken Sie auf „Zum Aktualisieren neu starten“. Pfad: {{path}}",
"app.about.update_status.new_version_ready_restart": "Neue Version {{version}} bereit. Auf „Zum Aktualisieren neu starten“ klicken."
}

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "Download Progress",
"app.about.action.download_update": "Download Update",
"app.about.action.hide_to_background": "Hide to Background",
"app.about.action.install_update": "Install Update",
"app.about.action.install_update": "Restart to update",
"app.about.action.mute_this_version": "Do Not Remind This Time",
"app.about.action.open_install_directory": "Open Install Directory",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "Update check failed: {{error}}",
"app.about.update_status.checking": "Checking for updates...",
"app.about.update_status.latest": "You are on the latest version ({{version}})",
"app.about.update_status.new_version_downloaded": "New version {{version}} found (downloaded; open Download Progress to install)",
"app.about.update_status.new_version_downloaded": "New version {{version}} is downloaded. Restart to update.",
"app.about.update_status.new_version_not_downloaded": "New version {{version}} found (not downloaded)",
"app.about.update_status.not_checked": "Not checked",
"app.about.version.current": "Current Version",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "Opens as a draggable/resizable floating window for multi-monitor or larger chat space.",
"ai_settings.open_mode.message.dock": "Default open style set to sidebar",
"ai_settings.open_mode.message.detached": "Default open style set to floating window",
"ai_settings.context.section_title": "Context level"
"ai_settings.context.section_title": "Context level",
"app.about.action.restart_to_update": "Restart to update",
"app.about.download_progress.ready_to_restart": "Download complete (100%). Click “Restart to update” to finish installing.",
"app.about.download_progress.downloading": "Downloading update…",
"app.about.download_progress.applying_restart": "Applying update and restarting…",
"app.about.download_progress.restarting": "Restarting…",
"app.about.download_progress.complete_hint": "Update package ready (100%)",
"app.about.message.download_ready_restart": "Update downloaded. Click “Restart to update” when ready.",
"app.about.message.download_ready_restart_with_path": "Update downloaded. Click “Restart to update” when ready. Path: {{path}}",
"app.about.update_status.new_version_ready_restart": "New version {{version}} is ready. Click “Restart to update”."
}

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "ダウンロード状況",
"app.about.action.download_update": "更新をダウンロード",
"app.about.action.hide_to_background": "バックグラウンドに隠す",
"app.about.action.install_update": "更新をインストール",
"app.about.action.install_update": "再起動して更新",
"app.about.action.mute_this_version": "今回は通知しない",
"app.about.action.open_install_directory": "インストールディレクトリを開く",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "更新確認に失敗しました: {{error}}",
"app.about.update_status.checking": "更新を確認しています...",
"app.about.update_status.latest": "現在は最新バージョンです({{version}}",
"app.about.update_status.new_version_downloaded": "新しいバージョン {{version}} が見つかりました(ダウンロード済み。「ダウンロード状況」からインストールしてください)",
"app.about.update_status.new_version_downloaded": "新しいバージョン {{version}} をダウンロード済みです。再起動して更新できます。",
"app.about.update_status.new_version_not_downloaded": "新しいバージョン {{version}} が見つかりました(未ダウンロード)",
"app.about.update_status.not_checked": "未確認",
"app.about.version.current": "現在のバージョン",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "ドラッグ/リサイズ可能な独立ウィンドウで開きます。",
"ai_settings.open_mode.message.dock": "デフォルトをサイドバーに設定しました",
"ai_settings.open_mode.message.detached": "デフォルトを独立ウィンドウに設定しました",
"ai_settings.context.section_title": "コンテキストレベル"
"ai_settings.context.section_title": "コンテキストレベル",
"app.about.action.restart_to_update": "再起動して更新",
"app.about.download_progress.ready_to_restart": "ダウンロード完了100%)。「再起動して更新」をクリックしてください。",
"app.about.download_progress.downloading": "更新をダウンロード中…",
"app.about.download_progress.applying_restart": "更新を適用して再起動しています…",
"app.about.download_progress.restarting": "再起動中…",
"app.about.download_progress.complete_hint": "更新パッケージの準備完了100%",
"app.about.message.download_ready_restart": "更新のダウンロードが完了しました。「再起動して更新」をクリックしてください。",
"app.about.message.download_ready_restart_with_path": "更新のダウンロードが完了しました。「再起動して更新」をクリックしてください。パス: {{path}}",
"app.about.update_status.new_version_ready_restart": "新しいバージョン {{version}} の準備ができました。「再起動して更新」をクリックしてください。"
}

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "Ход загрузки",
"app.about.action.download_update": "Скачать обновление",
"app.about.action.hide_to_background": "Скрыть в фон",
"app.about.action.install_update": "Установить обновление",
"app.about.action.install_update": "Перезапустить для обновления",
"app.about.action.mute_this_version": "Не напоминать в этот раз",
"app.about.action.open_install_directory": "Открыть каталог установки",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "Проверка обновлений не удалась: {{error}}",
"app.about.update_status.checking": "Проверка обновлений...",
"app.about.update_status.latest": "У вас установлена последняя версия ({{version}})",
"app.about.update_status.new_version_downloaded": "Найдена новая версия {{version}} (загружена; откройте ход загрузки для установки)",
"app.about.update_status.new_version_downloaded": "Новая версия {{version}} загружена. Перезапустите для обновления.",
"app.about.update_status.new_version_not_downloaded": "Найдена новая версия {{version}} (не загружена)",
"app.about.update_status.not_checked": "Не проверялось",
"app.about.version.current": "Текущая версия",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "Открывается как перетаскиваемое/изменяемое отдельное окно.",
"ai_settings.open_mode.message.dock": "По умолчанию: боковая панель",
"ai_settings.open_mode.message.detached": "По умолчанию: отдельное окно",
"ai_settings.context.section_title": "Уровень контекста"
"ai_settings.context.section_title": "Уровень контекста",
"app.about.action.restart_to_update": "Перезапустить для обновления",
"app.about.download_progress.ready_to_restart": "Загрузка завершена (100%). Нажмите «Перезапустить для обновления».",
"app.about.download_progress.downloading": "Загрузка обновления…",
"app.about.download_progress.applying_restart": "Применение обновления и перезапуск…",
"app.about.download_progress.restarting": "Перезапуск…",
"app.about.download_progress.complete_hint": "Пакет обновления готов (100%)",
"app.about.message.download_ready_restart": "Обновление загружено. Нажмите «Перезапустить для обновления».",
"app.about.message.download_ready_restart_with_path": "Обновление загружено. Нажмите «Перезапустить для обновления». Путь: {{path}}",
"app.about.update_status.new_version_ready_restart": "Новая версия {{version}} готова. Нажмите «Перезапустить для обновления»."
}

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "下载进度",
"app.about.action.download_update": "下载更新",
"app.about.action.hide_to_background": "隐藏到后台",
"app.about.action.install_update": "安装更新",
"app.about.action.install_update": "重启应用更新",
"app.about.action.mute_this_version": "本次不再提示",
"app.about.action.open_install_directory": "打开安装目录",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "检查更新失败: {{error}}",
"app.about.update_status.checking": "正在检查更新...",
"app.about.update_status.latest": "当前已是最新版本({{version}}",
"app.about.update_status.new_version_downloaded": "发现新版本 {{version}}(已下载,请点击“下载进度”后安装",
"app.about.update_status.new_version_downloaded": "发现新版本 {{version}}(已下载,可重启应用更新",
"app.about.update_status.new_version_not_downloaded": "发现新版本 {{version}}(未下载)",
"app.about.update_status.not_checked": "未检查",
"app.about.version.current": "当前版本",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "以可拖拽缩放的浮动窗打开,适合多显示器或更大聊天区域。",
"ai_settings.open_mode.message.dock": "已设为默认侧栏打开",
"ai_settings.open_mode.message.detached": "已设为默认独立窗口打开",
"ai_settings.context.section_title": "上下文级别"
"ai_settings.context.section_title": "上下文级别",
"app.about.action.restart_to_update": "重启应用更新",
"app.about.download_progress.ready_to_restart": "下载完成100%)。点击「重启应用更新」即可完成安装。",
"app.about.download_progress.downloading": "正在下载更新…",
"app.about.download_progress.applying_restart": "正在应用更新并重启…",
"app.about.download_progress.restarting": "正在重启应用…",
"app.about.download_progress.complete_hint": "更新包已就绪100%",
"app.about.message.download_ready_restart": "更新下载完成,可点击「重启应用更新」",
"app.about.message.download_ready_restart_with_path": "更新下载完成,可点击「重启应用更新」。路径:{{path}}",
"app.about.update_status.new_version_ready_restart": "发现新版本 {{version}}(已下载,点击「重启应用更新」)"
}

View File

@@ -2417,7 +2417,7 @@
"app.about.action.download_progress": "下載进度",
"app.about.action.download_update": "下載更新",
"app.about.action.hide_to_background": "隱藏到背景",
"app.about.action.install_update": "安裝更新",
"app.about.action.install_update": "重新啟動應用更新",
"app.about.action.mute_this_version": "本次不再提示",
"app.about.action.open_install_directory": "開啟安裝目錄",
"app.about.community.ai_book": "AI全书",
@@ -2459,7 +2459,7 @@
"app.about.update_status.check_failed": "檢查更新失敗: {{error}}",
"app.about.update_status.checking": "正在檢查更新...",
"app.about.update_status.latest": "目前已是最新版本({{version}}",
"app.about.update_status.new_version_downloaded": "發現新版本 {{version}}(已下載,請點擊「下載進度」後安裝",
"app.about.update_status.new_version_downloaded": "發現新版本 {{version}}(已下載,可重新啟動應用更新",
"app.about.update_status.new_version_not_downloaded": "發現新版本 {{version}}(未下載)",
"app.about.update_status.not_checked": "尚未檢查",
"app.about.version.current": "目前版本",
@@ -8032,5 +8032,14 @@
"ai_settings.open_mode.detached.desc": "以可拖曳縮放的浮動窗開啟,適合多顯示器或更大聊天區域。",
"ai_settings.open_mode.message.dock": "已設為預設側欄開啟",
"ai_settings.open_mode.message.detached": "已設為預設獨立視窗開啟",
"ai_settings.context.section_title": "上下文層級"
"ai_settings.context.section_title": "上下文層級",
"app.about.action.restart_to_update": "重新啟動應用更新",
"app.about.download_progress.ready_to_restart": "下載完成100%)。點選「重新啟動應用更新」即可完成安裝。",
"app.about.download_progress.downloading": "正在下載更新…",
"app.about.download_progress.applying_restart": "正在套用更新並重新啟動…",
"app.about.download_progress.restarting": "正在重新啟動應用…",
"app.about.download_progress.complete_hint": "更新包已就緒100%",
"app.about.message.download_ready_restart": "更新下載完成,可點選「重新啟動應用更新」",
"app.about.message.download_ready_restart_with_path": "更新下載完成,可點選「重新啟動應用更新」。路徑:{{path}}",
"app.about.update_status.new_version_ready_restart": "發現新版本 {{version}}(已下載,點選「重新啟動應用更新」)"
}