fix(i18n): translate automation cadence labels (#11068)

The cadence picker now resolves Hourly, Daily, Weekdays, Weekly, and Custom cron through the renderer i18n catalog, with corrected zh/ko/es translations.

Supersedes #10044 (thanks @innocarpe) and #10045 (thanks @fsdwen).

Fixes #10043
This commit is contained in:
Neil 2026-07-28 02:22:35 -07:00 committed by GitHub
parent dca0db38c4
commit 16dcf865ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 75 additions and 14 deletions

View File

@ -1,6 +1,6 @@
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { describe, expect, it } from 'vitest'
import { afterEach, describe, expect, it } from 'vitest'
import type { AutomationDraft } from './AutomationEditorDialog'
import {
AutomationCustomCronPanel,
@ -9,9 +9,11 @@ import {
} from './AutomationCustomCronPanel'
import {
AUTOMATION_SCHEDULE_PRESET_OPTIONS,
getAutomationSchedulePresetLabel,
getSchedulePresetDraft
} from './AutomationSchedulePicker'
import { isValidAutomationCronSchedule } from '../../../../shared/automation-schedules'
import { i18n } from '@/i18n/i18n'
const BASE_DRAFT: AutomationDraft = {
name: '',
@ -33,8 +35,34 @@ const BASE_DRAFT: AutomationDraft = {
}
describe('AutomationSchedulePicker', () => {
it('offers custom cron as a selectable cadence', () => {
expect(AUTOMATION_SCHEDULE_PRESET_OPTIONS).toContainEqual(['custom', 'Custom cron'])
// Reset here, not after the assertion: a failed expect would otherwise leak the locale.
afterEach(async () => {
await i18n.changeLanguage('en')
})
it('provides an i18n key for every selectable cadence (#10043)', () => {
expect(AUTOMATION_SCHEDULE_PRESET_OPTIONS).toContainEqual([
'custom',
'Custom cron',
'auto.components.automations.AutomationSchedulePicker.ddba78647e'
])
for (const [value, fallbackLabel, labelKey] of AUTOMATION_SCHEDULE_PRESET_OPTIONS) {
expect(value).not.toBe('')
expect(fallbackLabel).not.toBe('')
expect(labelKey).toMatch(
/^auto\.components\.automations\.AutomationSchedulePicker\.[0-9a-f]{10}$/
)
}
})
it.each([
['zh', ['每小时', '每天', '工作日', '每周', '自定义 cron']],
['ja', ['毎時', '毎日', '平日', '毎週', 'カスタム cron']],
['ko', ['매시간', '매일', '평일', '매주', '사용자 지정 cron']],
['es', ['Cada hora', 'Diario', 'Días laborables', 'Semanal', 'Cron personalizado']]
])('translates every cadence option in %s', async (locale, labels) => {
await i18n.changeLanguage(locale)
expect(AUTOMATION_SCHEDULE_PRESET_OPTIONS.map(getAutomationSchedulePresetLabel)).toEqual(labels)
})
it('seeds custom cron from the current simple schedule', () => {

View File

@ -25,12 +25,20 @@ import { translate } from '@/i18n/i18n'
const FIELD_CONTROL_CLASS = 'border-input bg-input/30 shadow-xs dark:bg-input/30'
export const AUTOMATION_SCHEDULE_PRESET_OPTIONS = [
['hourly', 'Hourly'],
['daily', 'Daily'],
['weekdays', 'Weekdays'],
['weekly', 'Weekly'],
['custom', 'Custom cron']
] as const satisfies readonly [AutomationSchedulePreset, string][]
['hourly', 'Hourly', 'auto.components.automations.AutomationSchedulePicker.55b2ef82a4'],
['daily', 'Daily', 'auto.components.automations.AutomationSchedulePicker.f0202f3a89'],
['weekdays', 'Weekdays', 'auto.components.automations.AutomationSchedulePicker.57e83307d0'],
['weekly', 'Weekly', 'auto.components.automations.AutomationSchedulePicker.837d902bba'],
['custom', 'Custom cron', 'auto.components.automations.AutomationSchedulePicker.ddba78647e']
] as const satisfies readonly (readonly [AutomationSchedulePreset, string, string])[]
export function getAutomationSchedulePresetLabel([, fallbackLabel, labelKey]: readonly [
AutomationSchedulePreset,
string,
string
]): string {
return translate(labelKey, fallbackLabel)
}
const DAY_OPTIONS = [
['0', 'Sunday'],
@ -191,9 +199,9 @@ export function AutomationSchedulePicker({
<SelectValue />
</SelectTrigger>
<SelectContent>
{AUTOMATION_SCHEDULE_PRESET_OPTIONS.map(([value, presetLabel]) => (
{AUTOMATION_SCHEDULE_PRESET_OPTIONS.map(([value, fallbackLabel, labelKey]) => (
<SelectItem key={value} value={value}>
{presetLabel}
{getAutomationSchedulePresetLabel([value, fallbackLabel, labelKey])}
</SelectItem>
))}
</SelectContent>

View File

@ -13359,6 +13359,11 @@
"d90981f766": "Time",
"6b914c5fbb": "Day",
"233b8c94b6": "Cadence",
"55b2ef82a4": "Hourly",
"f0202f3a89": "Daily",
"57e83307d0": "Weekdays",
"837d902bba": "Weekly",
"ddba78647e": "Custom cron",
"b08ccb4d06": "hourly",
"8cc026fd73": "weekly",
"c3e39e17cf": "custom"

View File

@ -13336,9 +13336,14 @@
"d90981f766": "Tiempo",
"6b914c5fbb": "Día",
"233b8c94b6": "Cadencia",
"55b2ef82a4": "Cada hora",
"f0202f3a89": "Diario",
"57e83307d0": "Días laborables",
"837d902bba": "Semanal",
"ddba78647e": "Cron personalizado",
"b08ccb4d06": "cada hora",
"8cc026fd73": "semanalmente",
"c3e39e17cf": "costumbre"
"c3e39e17cf": "personalizado"
},
"AutomationSessionField": {
"f3c76dce51": "Reutilizar",

View File

@ -13336,6 +13336,11 @@
"d90981f766": "時間",
"6b914c5fbb": "日",
"233b8c94b6": "ケイデンス",
"55b2ef82a4": "毎時",
"f0202f3a89": "毎日",
"57e83307d0": "平日",
"837d902bba": "毎週",
"ddba78647e": "カスタム cron",
"b08ccb4d06": "毎時",
"8cc026fd73": "毎週",
"c3e39e17cf": "カスタム"

View File

@ -13336,9 +13336,14 @@
"d90981f766": "시간",
"6b914c5fbb": "요일",
"233b8c94b6": "반복 주기",
"55b2ef82a4": "매시간",
"f0202f3a89": "매일",
"57e83307d0": "평일",
"837d902bba": "매주",
"ddba78647e": "사용자 지정 cron",
"b08ccb4d06": "매시간",
"8cc026fd73": "주간",
"c3e39e17cf": "custom"
"c3e39e17cf": "사용자 지정"
},
"AutomationSessionField": {
"f3c76dce51": "재사용",

View File

@ -13336,9 +13336,14 @@
"d90981f766": "时间",
"6b914c5fbb": "天",
"233b8c94b6": "节奏",
"55b2ef82a4": "每小时",
"f0202f3a89": "每天",
"57e83307d0": "工作日",
"837d902bba": "每周",
"ddba78647e": "自定义 cron",
"b08ccb4d06": "每小时",
"8cc026fd73": "每周",
"c3e39e17cf": "风俗"
"c3e39e17cf": "自定义"
},
"AutomationSessionField": {
"f3c76dce51": "重复利用",