diff --git a/src/components/VoiceDownloadAll.astro b/src/components/VoiceDownloadAll.astro index 3d806ff..c36a2a2 100644 --- a/src/components/VoiceDownloadAll.astro +++ b/src/components/VoiceDownloadAll.astro @@ -24,6 +24,11 @@ const ui = t(lang); // the SmartScreen walkthrough is a section further down it. const unsignedHref = `${localizedPath('/voice/download/', lang)}#windows`; +// The changelog is where the version number leads: a reader who wants to +// know what they are about to install wants the release notes, not the +// number on its own. +const changelogHref = localizedPath('/voice/changelog/', lang); + const [mac, linuxX64, linuxArm, winX64, winArm] = await Promise.all([ getDownload('mac'), getDownload('linux-x64'), @@ -39,6 +44,33 @@ const groups = buildGroups( ); --- +{/* The version, once, above the whole grid — the page states five + targets and this states the release they all come from. + + Keyed to `mac` and to nothing else, deliberately. The printed value and + the browser-side correction have to name the SAME target or they can + disagree the first time a release skips one, and `mac` is the target + that has never been null: it is in the offline FALLBACK table, and the + App Store build is cut from every release. So the SSR value, the + `data-dl-version` the refresh writes into, and the `data-dl-row` that + withdraws the whole line if the platform ever reports mac unpublished + are one key. No new script and no second fetch — `VoiceDownloadScripts` + below already does both for the rows. + + The store rows are the reason this is a page-level line rather than a + per-row one: Apple and Microsoft resolve their own builds and report no + version back here, so half the grid could never carry one. */} +

+ {ui.dlLatestRelease} v{mac?.version} · {ui.subChangelog} → +

+ {/* Three equal columns that stack on a phone. `items-start` so a column with fewer rows doesn't stretch its card to match the tallest. */}
diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index 7e38d21..44714f4 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -261,6 +261,19 @@ export interface UIStrings { * label has to promise the whole set rather than "more platforms". */ dlAllDownloads: string; + /** + * Precedes the version number above the download grid, e.g. "Latest + * WaveKat Voice release v0.0.52". A label, not a sentence — the version + * and the changelog link follow it. + * + * It names the product on purpose, even though the

two lines above + * already does. A passage extractor lifts this

on its own, and + * "Latest release v0.0.52" alone states a version of nothing; with the + * entity in it the line is a fact that survives being quoted. The + * product name is never translated (CLAUDE.md), so only the words + * around it change per locale. + */ + dlLatestRelease: string; talkHeading: string; talkBody: string; talkButton: string; @@ -334,6 +347,7 @@ const strings: Record = { "The direct Windows downloads aren't code-signed, so Windows warns on first launch. The Microsoft Store version is signed.", dlWindowsUnsignedLink: 'How to get past it', dlAllDownloads: 'All downloads and installers', + dlLatestRelease: 'Latest WaveKat Voice release', talkHeading: 'Talk to us', talkBody: 'Questions, feedback, or a device you wish we supported? Email is the best way to reach us — we read every message and reply as soon as we can.', @@ -388,6 +402,7 @@ const strings: Record = { '直接下载的 Windows 版尚未进行代码签名,首次启动时系统会弹出提醒;Microsoft Store 版本已签名。', dlWindowsUnsignedLink: '如何继续安装', dlAllDownloads: '所有下载与安装程序', + dlLatestRelease: 'WaveKat Voice 最新版本', talkHeading: '联系我们', talkBody: '有疑问、建议,或希望我们支持某种设备?邮件是联系我们的最佳方式——我们会阅读每一条消息,并尽快回复。', diff --git a/src/lib/ui/de.ts b/src/lib/ui/de.ts index 5e37a28..a1bfc0e 100644 --- a/src/lib/ui/de.ts +++ b/src/lib/ui/de.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { 'Die direkten Windows-Downloads sind nicht signiert, deshalb warnt Windows beim ersten Start. Die Version aus dem Microsoft Store ist signiert.', dlWindowsUnsignedLink: 'So kommen Sie daran vorbei', dlAllDownloads: 'Alle Downloads und Installer', + dlLatestRelease: 'Neueste Version von WaveKat Voice', talkHeading: 'Kontakt', talkBody: 'Fragen, Feedback oder ein Gerät, das Sie sich von uns wünschen? Am besten erreichen Sie uns per E-Mail — wir lesen jede Nachricht und antworten, so schnell wir können.', diff --git a/src/lib/ui/es.ts b/src/lib/ui/es.ts index 5bfd4ab..7da4254 100644 --- a/src/lib/ui/es.ts +++ b/src/lib/ui/es.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { 'Las descargas directas para Windows no están firmadas, así que Windows avisa al abrirlas por primera vez. La versión de Microsoft Store sí está firmada.', dlWindowsUnsignedLink: 'Cómo continuar', dlAllDownloads: 'Todas las descargas e instaladores', + dlLatestRelease: 'Última versión de WaveKat Voice', talkHeading: 'Contacto', talkBody: '¿Preguntas, comentarios o un dispositivo que le gustaría que admitiéramos? El correo electrónico es la mejor forma de contactarnos: leemos cada mensaje y respondemos en cuanto podemos.', diff --git a/src/lib/ui/fr.ts b/src/lib/ui/fr.ts index e1c3248..8574e5c 100644 --- a/src/lib/ui/fr.ts +++ b/src/lib/ui/fr.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { "Les téléchargements directs pour Windows ne sont pas signés : Windows affiche un avertissement au premier lancement. La version du Microsoft Store, elle, est signée.", dlWindowsUnsignedLink: 'Comment passer outre', dlAllDownloads: 'Tous les téléchargements et installateurs', + dlLatestRelease: 'Dernière version de WaveKat Voice', talkHeading: 'Nous contacter', talkBody: 'Une question, un retour, ou un appareil que vous aimeriez nous voir prendre en charge ? L’e-mail est le meilleur moyen de nous joindre — nous lisons chaque message et répondons dès que possible.', diff --git a/src/lib/ui/it.ts b/src/lib/ui/it.ts index e7dfb58..aec2da3 100644 --- a/src/lib/ui/it.ts +++ b/src/lib/ui/it.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { 'I download diretti per Windows non sono firmati, quindi Windows avvisa al primo avvio. La versione di Microsoft Store è firmata.', dlWindowsUnsignedLink: 'Come procedere', dlAllDownloads: 'Tutti i download e gli installer', + dlLatestRelease: 'Ultima versione di WaveKat Voice', talkHeading: 'Contattaci', talkBody: 'Domande, suggerimenti o un dispositivo che vorresti vedere supportato? L’email è il modo migliore per raggiungerci: leggiamo ogni messaggio e rispondiamo il prima possibile.', diff --git a/src/lib/ui/ja.ts b/src/lib/ui/ja.ts index dca7e5c..f241e31 100644 --- a/src/lib/ui/ja.ts +++ b/src/lib/ui/ja.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { '直接ダウンロードした Windows 版はコード署名されていないため、初回起動時に警告が表示されます。Microsoft Store 版は署名済みです。', dlWindowsUnsignedLink: '進める方法', dlAllDownloads: 'すべてのダウンロードとインストーラー', + dlLatestRelease: 'WaveKat Voice の最新バージョン', talkHeading: 'お問い合わせ', talkBody: diff --git a/src/lib/ui/ko.ts b/src/lib/ui/ko.ts index 5951dc3..35d233f 100644 --- a/src/lib/ui/ko.ts +++ b/src/lib/ui/ko.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { '직접 내려받은 Windows 빌드는 코드 서명이 되어 있지 않아 첫 실행 시 경고가 표시됩니다. Microsoft Store 버전은 서명되어 있습니다.', dlWindowsUnsignedLink: '넘어가는 방법', dlAllDownloads: '모든 다운로드 및 설치 파일', + dlLatestRelease: 'WaveKat Voice 최신 버전', talkHeading: '문의하기', talkBody: '궁금한 점이나 의견이 있으신가요? 지원했으면 하는 기기가 있으신가요? 이메일이 저희에게 연락하는 가장 좋은 방법입니다. 모든 메시지를 읽고 가능한 한 빨리 답변드립니다.', diff --git a/src/lib/ui/zh-hant.ts b/src/lib/ui/zh-hant.ts index 993e2fb..3c3604b 100644 --- a/src/lib/ui/zh-hant.ts +++ b/src/lib/ui/zh-hant.ts @@ -34,6 +34,7 @@ export const ui: UIStrings = { '直接下載的 Windows 版尚未進行程式碼簽章,首次啟動時系統會跳出提醒;Microsoft Store 版本已簽章。', dlWindowsUnsignedLink: '如何繼續安裝', dlAllDownloads: '所有下載與安裝程式', + dlLatestRelease: 'WaveKat Voice 最新版本', talkHeading: '聯絡我們', talkBody: '有疑問、建議,或希望我們支援某款裝置?電子郵件是聯絡我們的最佳方式——我們會閱讀每一則訊息,並盡快回覆。',