diff --git a/CHANGELOG.md b/CHANGELOG.md index eea696893..12fb2cf1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ - Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace. - 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함. +### Changed + +- Localize Workspace export, stem-player, loop, solo, mute, and transcription controls in English and Korean, including safe literal placeholder interpolation and an accessible localized role fallback. + +### Fixed + +- Update Undici to 7.29.0 in the root npm lock to remediate the current high-severity advisory set without introducing nested workspace-lock drift. + ## [0.1.3] - 2026-04-29 ### Fixed diff --git a/apps/desktop/package.json b/apps/desktop/package.json index e7685d6f0..647047e31 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -20,7 +20,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.24.0", - "pdfjs-dist": "6.1.200", + "pdfjs-dist": "^6.2.108", "react": "^19.2.4", "react-dom": "^19.2.7", "sonner": "^2.0.7", diff --git a/apps/desktop/src/features/workspace/Workspace.test.tsx b/apps/desktop/src/features/workspace/Workspace.test.tsx index a3da5ffe6..55cfa6a9b 100644 --- a/apps/desktop/src/features/workspace/Workspace.test.tsx +++ b/apps/desktop/src/features/workspace/Workspace.test.tsx @@ -86,6 +86,7 @@ describe("Workspace", () => { }); it("enables bass transcription from selected role metadata rather than role id text", () => { + setNavigatorLanguage("en-US"); const song = createDemoRehearsalSong(); song.sections[0]!.roles[0] = { ...song.sections[0]!.roles[0]!, @@ -96,11 +97,30 @@ describe("Workspace", () => { render(); fireEvent.click(screen.getByRole("tab", { name: "Bass Guitar" })); - const transcribeButton = screen.getByRole("button", { name: "Transcribe Bass" }) as HTMLButtonElement; + const transcribeButton = screen.getByRole("button", { name: /Transcribe Bass/ }) as HTMLButtonElement; expect(transcribeButton.disabled).toBe(false); expect(transcribeButton.title).toBe("Transcribe part"); }); + it("names unavailable transcription for the selected non-bass role", () => { + setNavigatorLanguage("en-US"); + const song = createDemoRehearsalSong(); + song.sections[0]!.roles[0] = { + ...song.sections[0]!.roles[0]!, + id: "guitar-role", + name: "Guitar" + }; + + render(); + fireEvent.click(screen.getByRole("tab", { name: "Guitar" })); + + const label = "Guitar transcription is coming soon. Bass is ready first."; + const transcribeButton = screen.getByRole("button", { name: label }); + expect(transcribeButton).toHaveTextContent("Transcribe part"); + expect(transcribeButton).toHaveAttribute("aria-disabled", "true"); + expect(transcribeButton).toHaveAttribute("title", label); + }); + it("renders bass transcription in the dark rehearsal cockpit system", () => { const song = createDemoRehearsalSong(); song.sections[0]!.roles[0] = { diff --git a/apps/desktop/src/features/workspace/Workspace.tsx b/apps/desktop/src/features/workspace/Workspace.tsx index 71546b524..dda6628a4 100644 --- a/apps/desktop/src/features/workspace/Workspace.tsx +++ b/apps/desktop/src/features/workspace/Workspace.tsx @@ -150,6 +150,9 @@ export function Workspace({ song, sourceBootstrap = null, onSongUpdate }: Worksp return roleMap.get(activeRole); }, [activeRole, roleMap]); const canTranscribeBass = activeRoleDetails?.name.toLowerCase().includes("bass") ?? false; + const transcriptionUnavailableLabel = t("transcriptionComingSoon", { + roleName: activeRoleDetails?.name ?? t("thisRole") + }); /** Handle the practice progress change internally by immutably updating the song state. */ const handlePracticeProgressChange = (newProgress: number) => { @@ -263,7 +266,7 @@ export function Workspace({ song, sourceBootstrap = null, onSongUpdate }: Worksp className="min-h-10 border-cyan-300/30 bg-cyan-300/10 font-semibold text-cyan-50 shadow-[0_10px_30px_rgba(34,211,238,0.16)] hover:bg-cyan-300/20 hover:text-white" >