feat: add bilingual release notes

This commit is contained in:
lofyer
2026-08-11 20:59:26 +08:00
parent 6942bef567
commit 44d30b428d
26 changed files with 1344 additions and 42 deletions
+5
View File
@@ -65,6 +65,7 @@ import type {
ApplicationSettingsUpdate,
VersionCheckResult
} from './application-settings-contracts'
import type { ReleaseNotesSnapshot } from './release-notes-contracts'
import type {
SpeechModelSnapshot,
SpeechTranscriptionInput,
@@ -1049,6 +1050,10 @@ export type DesktopApi = {
listener: (result: VersionCheckResult) => void
) => () => void
}
releaseNotes?: {
getPending: () => Promise<ReleaseNotesSnapshot>
acknowledge: (version: string) => Promise<void>
}
speechModels?: {
getSnapshot: () => Promise<SpeechModelSnapshot>
install: (modelId: string) => Promise<SpeechModelSnapshot>
+2
View File
@@ -43,6 +43,8 @@ export const ipcChannels = {
versionCheck: 'application:update:check',
versionOpenReleasePage: 'application:update:open-release-page',
versionCheckResult: 'application:update:result',
releaseNotesGetPending: 'application:release-notes:get-pending',
releaseNotesAcknowledge: 'application:release-notes:acknowledge',
speechModelsGet: 'settings:speech-models:get',
speechModelsInstall: 'settings:speech-models:install',
speechModelsCancel: 'settings:speech-models:cancel',
+77
View File
@@ -0,0 +1,77 @@
import { z } from 'zod'
export const releaseVersionSchema = z
.string()
.regex(
/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/,
'Release version must be a stable semantic version'
)
const localizedReleaseNotesSchema = z
.object({
features: z.array(z.string().trim().min(1).max(240)).max(20),
fixes: z.array(z.string().trim().min(1).max(240)).max(20)
})
.strict()
.refine(
(notes) => notes.features.length > 0 || notes.fixes.length > 0,
'Release notes must contain at least one item'
)
export const releaseNoteSchema = z
.object({
version: releaseVersionSchema,
releasedAt: z.iso.date(),
notes: z
.object({
'zh-CN': localizedReleaseNotesSchema,
'en-US': localizedReleaseNotesSchema
})
.strict()
})
.strict()
export const releaseNotesFileSchema = z
.object({
formatVersion: z.literal(1),
releases: z.array(releaseNoteSchema).min(1).max(100)
})
.strict()
.superRefine((value, context) => {
const versions = new Set<string>()
for (const [index, release] of value.releases.entries()) {
if (versions.has(release.version)) {
context.addIssue({
code: 'custom',
message: `Duplicate release version: ${release.version}`,
path: ['releases', index, 'version']
})
}
versions.add(release.version)
if (
release.notes['zh-CN'].features.length !==
release.notes['en-US'].features.length ||
release.notes['zh-CN'].fixes.length !==
release.notes['en-US'].fixes.length
) {
context.addIssue({
code: 'custom',
message: 'Localized release-note sections must have matching counts',
path: ['releases', index, 'notes']
})
}
}
})
export const releaseNotesAcknowledgeSchema = z
.object({
version: releaseVersionSchema
})
.strict()
export type ReleaseNote = z.infer<typeof releaseNoteSchema>
export type ReleaseNotesSnapshot = {
currentVersion: string
releases: ReleaseNote[]
}