fix: added missing i18n labels

This commit is contained in:
Xiaohan-Tian
2026-06-12 12:03:32 -07:00
parent 3ba8f81c87
commit ef7ff08f4c
6 changed files with 69 additions and 4 deletions
+57 -2
View File
@@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render } from '@testing-library/react'; import { fireEvent, render, screen } from '@testing-library/react';
import TrackInfoItem from './TrackInfoItem'; import TrackInfoItem from './TrackInfoItem';
import { KGAudioTrack } from '../../core/track/KGAudioTrack'; import { KGAudioTrack } from '../../core/track/KGAudioTrack';
import { showConfirm } from '../../util/dialogUtil';
import { translate } from '../../i18n/translate';
const storeState = { const storeState = {
selectedTrackId: null as string | null, selectedTrackId: null as string | null,
@@ -24,8 +26,31 @@ vi.mock('../../stores/projectStore', () => ({
), ),
})); }));
vi.mock('../../i18n/useI18n', async () => {
const { translate } = await import('../../i18n/translate');
return {
useI18n: () => ({
t: (key: string, params?: Record<string, string | number>) => translate(key, params, 'zh_cn'),
}),
};
});
vi.mock('../common/KGDropdown', () => ({ vi.mock('../common/KGDropdown', () => ({
default: () => null, default: ({ options, isOpen, onChange }: { options: Array<string | { label: string; value: string }>; isOpen?: boolean; onChange: (value: string) => void }) => (
isOpen ? (
<div>
{options.map((option) => {
const value = typeof option === 'string' ? option : option.value;
const label = typeof option === 'string' ? option : option.label;
return (
<button key={value} type="button" onClick={() => onChange(value)}>
{label}
</button>
);
})}
</div>
) : null
),
})); }));
vi.mock('../common/FileImportModal', () => ({ vi.mock('../common/FileImportModal', () => ({
@@ -49,6 +74,7 @@ describe('TrackInfoItem audio import', () => {
storeState.toggleInstrumentSelectionForTrack.mockReset(); storeState.toggleInstrumentSelectionForTrack.mockReset();
storeState.importAudioToTrack.mockReset(); storeState.importAudioToTrack.mockReset();
storeState.setTrackAutomationView.mockReset(); storeState.setTrackAutomationView.mockReset();
vi.mocked(showConfirm).mockReset();
}); });
it('advertises m4a support in the track audio import modal', () => { it('advertises m4a support in the track audio import modal', () => {
@@ -72,4 +98,33 @@ describe('TrackInfoItem audio import', () => {
expect(fileImportModalProps?.acceptedTypes).toEqual(['.wav', '.mp3', '.ogg', '.flac', '.aac', '.m4a']); expect(fileImportModalProps?.acceptedTypes).toEqual(['.wav', '.mp3', '.ogg', '.flac', '.aac', '.m4a']);
}); });
it('uses the localized delete-track confirmation message', () => {
const audioTrack = new KGAudioTrack('钢琴', 1);
audioTrack.setTrackIndex(0);
storeState.tracks = [audioTrack];
vi.mocked(showConfirm).mockResolvedValue(false);
render(
<TrackInfoItem
track={audioTrack}
index={0}
isDragging={false}
isDragOver={false}
onTrackNameEdit={vi.fn()}
onDragStart={vi.fn()}
onDragOver={vi.fn()}
onDrop={vi.fn()}
onDragEnd={vi.fn()}
/>
);
fireEvent.click(screen.getByRole('button', { name: '更多操作' }));
fireEvent.click(screen.getByRole('button', { name: '删除轨道' }));
expect(showConfirm).toHaveBeenCalledWith(
translate('track.controls.settings.deleteTrackConfirm', { name: '钢琴' }, 'zh_cn')
);
});
}); });
+4 -2
View File
@@ -360,7 +360,9 @@ const TrackInfoItem: React.FC<TrackInfoItemProps> = ({
// Handle settings action // Handle settings action
const handleSettingsAction = async (action: string) => { const handleSettingsAction = async (action: string) => {
if (action === 'Delete Track') { if (action === 'Delete Track') {
const confirmed = await showConfirm(`Are you sure you want to delete track "${track.getName()}"?`); const confirmed = await showConfirm(
t('track.controls.settings.deleteTrackConfirm', { name: track.getName() })
);
if (confirmed) { if (confirmed) {
try { try {
if (DEBUG_MODE.TRACK_INFO) { if (DEBUG_MODE.TRACK_INFO) {
@@ -379,7 +381,7 @@ const TrackInfoItem: React.FC<TrackInfoItemProps> = ({
setShowSettingsDropdown(false); setShowSettingsDropdown(false);
} catch (error) { } catch (error) {
console.error('Failed to delete track:', error); console.error('Failed to delete track:', error);
await showAlert('Failed to delete track. Please try again.'); await showAlert(t('track.controls.settings.deleteTrackError'));
} }
} }
} }
+2
View File
@@ -539,6 +539,8 @@ export const enUsMessages: TranslationMessages = {
'track.controls.automation.pan': 'Pan', 'track.controls.automation.pan': 'Pan',
'track.controls.moreActions': 'More actions', 'track.controls.moreActions': 'More actions',
'track.controls.settings.deleteTrack': 'Delete Track', 'track.controls.settings.deleteTrack': 'Delete Track',
'track.controls.settings.deleteTrackConfirm': 'Are you sure you want to delete track "{name}"?',
'track.controls.settings.deleteTrackError': 'Failed to delete track. Please try again.',
'toolbar.keySignatureChooser': 'Choose key signature, current {value}', 'toolbar.keySignatureChooser': 'Choose key signature, current {value}',
'toolbar.export.label': 'Export', 'toolbar.export.label': 'Export',
'toolbar.importProject.title': 'Import Project', 'toolbar.importProject.title': 'Import Project',
+2
View File
@@ -423,6 +423,8 @@ export const frFrMessages: TranslationMessages = {
'track.controls.automation.pan': 'Panoramique', 'track.controls.automation.pan': 'Panoramique',
'track.controls.moreActions': 'Autres actions', 'track.controls.moreActions': 'Autres actions',
'track.controls.settings.deleteTrack': 'Supprimer la piste', 'track.controls.settings.deleteTrack': 'Supprimer la piste',
'track.controls.settings.deleteTrackConfirm': 'Voulez-vous vraiment supprimer la piste « {name} » ?',
'track.controls.settings.deleteTrackError': 'Impossible de supprimer la piste. Veuillez réessayer.',
'toolbar.keySignatureChooser': 'Choisir l\'armure, actuelle : {value}', 'toolbar.keySignatureChooser': 'Choisir l\'armure, actuelle : {value}',
'toolbar.export.label': 'Exporter', 'toolbar.export.label': 'Exporter',
'toolbar.importProject.title': 'Importer un projet', 'toolbar.importProject.title': 'Importer un projet',
+2
View File
@@ -537,6 +537,8 @@ export const zhCnMessages: TranslationMessages = {
'track.controls.automation.pan': '声像', 'track.controls.automation.pan': '声像',
'track.controls.moreActions': '更多操作', 'track.controls.moreActions': '更多操作',
'track.controls.settings.deleteTrack': '删除轨道', 'track.controls.settings.deleteTrack': '删除轨道',
'track.controls.settings.deleteTrackConfirm': '确定要删除轨道“{name}”吗?',
'track.controls.settings.deleteTrackError': '删除轨道失败。请重试。',
'toolbar.keySignatureChooser': '选择调号,当前为 {value}', 'toolbar.keySignatureChooser': '选择调号,当前为 {value}',
'toolbar.export.label': '导出', 'toolbar.export.label': '导出',
'toolbar.importProject.title': '导入项目', 'toolbar.importProject.title': '导入项目',
+2
View File
@@ -537,6 +537,8 @@ export const zhHkMessages: TranslationMessages = {
'track.controls.automation.pan': '聲像', 'track.controls.automation.pan': '聲像',
'track.controls.moreActions': '更多操作', 'track.controls.moreActions': '更多操作',
'track.controls.settings.deleteTrack': '刪除音軌', 'track.controls.settings.deleteTrack': '刪除音軌',
'track.controls.settings.deleteTrackConfirm': '確定要刪除音軌「{name}」嗎?',
'track.controls.settings.deleteTrackError': '刪除音軌失敗。請再試一次。',
'toolbar.keySignatureChooser': '選擇調號,當前為 {value}', 'toolbar.keySignatureChooser': '選擇調號,當前為 {value}',
'toolbar.export.label': '匯出', 'toolbar.export.label': '匯出',
'toolbar.importProject.title': '匯入專案', 'toolbar.importProject.title': '匯入專案',