diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 46fbf9e5..ea1a3729 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -16,6 +16,7 @@ "@open-codesign/artifacts": "workspace:*", "@open-codesign/core": "workspace:*", "@open-codesign/exporters": "workspace:*", + "@open-codesign/i18n": "workspace:*", "@open-codesign/providers": "workspace:*", "@open-codesign/runtime": "workspace:*", "@open-codesign/shared": "workspace:*", diff --git a/apps/desktop/src/main/index.ts b/apps/desktop/src/main/index.ts index 33a94563..c694d8ee 100644 --- a/apps/desktop/src/main/index.ts +++ b/apps/desktop/src/main/index.ts @@ -9,6 +9,7 @@ import { autoUpdater } from 'electron-updater'; import { scanDesignSystem } from './design-system'; import { BrowserWindow, app, dialog, ipcMain, shell } from './electron-runtime'; import { registerExporterIpc } from './exporter-ipc'; +import { registerLocaleIpc } from './locale-ipc'; import { getLogPath, getLogger, initLogger } from './logger'; import { getApiKeyForProvider, @@ -32,6 +33,7 @@ function createWindow(): void { height: 820, minWidth: 960, minHeight: 640, + autoHideMenuBar: process.platform !== 'darwin', titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : 'default', backgroundColor: BRAND.backgroundColor, show: false, @@ -254,6 +256,7 @@ void app.whenReady().then(async () => { initLogger(); await loadConfigOnBoot(); registerIpcHandlers(); + registerLocaleIpc(); registerOnboardingIpc(); registerExporterIpc(() => mainWindow); setupAutoUpdater(); diff --git a/apps/desktop/src/preload/index.ts b/apps/desktop/src/preload/index.ts index b55abefa..ca3179b1 100644 --- a/apps/desktop/src/preload/index.ts +++ b/apps/desktop/src/preload/index.ts @@ -52,6 +52,11 @@ const api = { ipcRenderer.invoke('codesign:clear-design-system') as Promise, export: (payload: { format: ExportFormat; htmlContent: string; defaultFilename?: string }) => ipcRenderer.invoke('codesign:export', payload) as Promise, + locale: { + getSystem: () => ipcRenderer.invoke('locale:get-system') as Promise, + getCurrent: () => ipcRenderer.invoke('locale:get-current') as Promise, + set: (locale: string) => ipcRenderer.invoke('locale:set', locale) as Promise, + }, checkForUpdates: () => ipcRenderer.invoke('codesign:check-for-updates'), downloadUpdate: () => ipcRenderer.invoke('codesign:download-update'), installUpdate: () => ipcRenderer.invoke('codesign:install-update'), diff --git a/apps/desktop/src/renderer/src/App.tsx b/apps/desktop/src/renderer/src/App.tsx index 7259f8ad..d7458eed 100644 --- a/apps/desktop/src/renderer/src/App.tsx +++ b/apps/desktop/src/renderer/src/App.tsx @@ -1,3 +1,4 @@ +import { useT } from '@open-codesign/i18n'; import { useEffect, useMemo, useState } from 'react'; import { CommandPalette } from './components/CommandPalette'; import { PreviewPane } from './components/PreviewPane'; @@ -10,6 +11,7 @@ import { Onboarding } from './onboarding'; import { useCodesignStore } from './store'; export function App() { + const t = useT(); const config = useCodesignStore((s) => s.config); const configLoaded = useCodesignStore((s) => s.configLoaded); const loadConfig = useCodesignStore((s) => s.loadConfig); @@ -90,7 +92,7 @@ export function App() { if (!configLoaded) { return (
- Loading… + {t('common.loading')}
); } diff --git a/apps/desktop/src/renderer/src/components/CanvasErrorBar.tsx b/apps/desktop/src/renderer/src/components/CanvasErrorBar.tsx index 5a7342e6..69a6d599 100644 --- a/apps/desktop/src/renderer/src/components/CanvasErrorBar.tsx +++ b/apps/desktop/src/renderer/src/components/CanvasErrorBar.tsx @@ -1,16 +1,9 @@ -/** - * CanvasErrorBar — slim red strip shown above the preview iframe when the - * sandbox runtime postMessages an IFRAME_ERROR. - * - * Loud surface (PRINCIPLES §10): every JS exception thrown inside the - * generated HTML lands here with file + line. Users can dismiss the bar - * (it clears the store slice) but errors are never auto-hidden. - */ - +import { useT } from '@open-codesign/i18n'; import { X } from 'lucide-react'; import { useCodesignStore } from '../store'; export function CanvasErrorBar() { + const t = useT(); const errors = useCodesignStore((s) => s.iframeErrors); const clear = useCodesignStore((s) => s.clearIframeErrors); if (errors.length === 0) return null; @@ -24,7 +17,8 @@ export function CanvasErrorBar() {
- Preview runtime error{errors.length > 1 ? ` (${errors.length})` : ''} + {t('preview.runtimeError')} + {errors.length > 1 ? ` (${errors.length})` : ''}
{latest} @@ -33,7 +27,7 @@ export function CanvasErrorBar() { diff --git a/apps/desktop/src/renderer/src/components/InlineCommentComposer.tsx b/apps/desktop/src/renderer/src/components/InlineCommentComposer.tsx index 007b4183..9ef56dea 100644 --- a/apps/desktop/src/renderer/src/components/InlineCommentComposer.tsx +++ b/apps/desktop/src/renderer/src/components/InlineCommentComposer.tsx @@ -1,3 +1,4 @@ +import { useT } from '@open-codesign/i18n'; import type { SelectedElement } from '@open-codesign/shared'; import { MessageSquareText, X } from 'lucide-react'; import { useState } from 'react'; @@ -16,6 +17,7 @@ interface InlineCommentComposerCardProps { } function InlineCommentComposerCard({ selectedElement }: InlineCommentComposerCardProps) { + const t = useT(); const clearCanvasElement = useCodesignStore((s) => s.clearCanvasElement); const applyInlineComment = useCodesignStore((s) => s.applyInlineComment); const isGenerating = useCodesignStore((s) => s.isGenerating); @@ -27,7 +29,7 @@ function InlineCommentComposerCard({ selectedElement }: InlineCommentComposerCar
- Comment on {selectedElement.tag} + {t('inlineComment.title')} {selectedElement.tag}

@@ -48,13 +50,12 @@ function InlineCommentComposerCard({ selectedElement }: InlineCommentComposerCar

- Clicked elements stay selected in the canvas. Describe the visual or content change you - want, and open-codesign will rewrite the artifact around that target. + {t('inlineComment.description')}