diff options
| author | Adam <[email protected]> | 2026-02-27 09:45:00 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-27 09:45:00 -0600 |
| commit | 6ef3af73dfa1c72bb2001c86d898f2edf8ea4b10 (patch) | |
| tree | 845adb9ccc47884a0f102a59cb887bd17a51a75c /packages/app/src | |
| parent | e5ae6c51b0d2f5dececd16970250aa2ab6c71a2f (diff) | |
| download | opencode-6ef3af73dfa1c72bb2001c86d898f2edf8ea4b10.tar.gz opencode-6ef3af73dfa1c72bb2001c86d898f2edf8ea4b10.zip | |
chore(app): i18n sync (#15362)
Diffstat (limited to 'packages/app/src')
25 files changed, 311 insertions, 23 deletions
diff --git a/packages/app/src/components/dialog-release-notes.tsx b/packages/app/src/components/dialog-release-notes.tsx index 2040009a8..d0a35b71b 100644 --- a/packages/app/src/components/dialog-release-notes.tsx +++ b/packages/app/src/components/dialog-release-notes.tsx @@ -2,6 +2,7 @@ import { createSignal } from "solid-js" import { Dialog } from "@opencode-ai/ui/dialog" import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" export type Highlight = { @@ -16,6 +17,7 @@ export type Highlight = { export function DialogReleaseNotes(props: { highlights: Highlight[] }) { const dialog = useDialog() + const language = useLanguage() const settings = useSettings() const [index, setIndex] = createSignal(0) @@ -83,16 +85,16 @@ export function DialogReleaseNotes(props: { highlights: Highlight[] }) { <div class="flex flex-col items-start gap-3"> {isLast() ? ( <Button variant="primary" size="large" onClick={handleClose}> - Get started + {language.t("dialog.releaseNotes.action.getStarted")} </Button> ) : ( <Button variant="secondary" size="large" onClick={handleNext}> - Next + {language.t("dialog.releaseNotes.action.next")} </Button> )} <Button variant="ghost" size="small" onClick={handleDisable}> - Don't show these in the future + {language.t("dialog.releaseNotes.action.hideFuture")} </Button> </div> @@ -128,7 +130,7 @@ export function DialogReleaseNotes(props: { highlights: Highlight[] }) { {feature()!.media!.type === "image" ? ( <img src={feature()!.media!.src} - alt={feature()!.media!.alt ?? feature()?.title ?? "Release preview"} + alt={feature()!.media!.alt ?? feature()?.title ?? language.t("dialog.releaseNotes.media.alt")} class="w-full h-full object-cover" /> ) : ( diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index 29a3666c0..b530aff53 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -449,7 +449,7 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil </div> <Show when={item.updated}> <span class="text-12-regular text-text-weak whitespace-nowrap ml-2"> - {getRelativeTime(new Date(item.updated!).toISOString())} + {getRelativeTime(new Date(item.updated!).toISOString(), language.t)} </span> </Show> </div> diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index f3209c354..27b1b9cc0 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -430,7 +430,7 @@ export function SessionHeader() { <Spinner class="size-3.5 text-icon-base" /> </Show> </div> - <span class="text-12-regular text-text-strong">Open</span> + <span class="text-12-regular text-text-strong">{language.t("common.open")}</span> </Button> <div class="self-stretch w-px bg-border-weak-base" /> <DropdownMenu diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index 55a25ca0c..6fac9feca 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -162,7 +162,7 @@ export const SettingsProviders: Component = () => { when={canDisconnect(item)} fallback={ <span class="text-14-regular text-text-base opacity-0 group-hover:opacity-100 transition-opacity duration-200 pr-3 cursor-default"> - Connected from your environment variables + {language.t("settings.providers.connected.environmentDescription")} </span> } > @@ -229,10 +229,12 @@ export const SettingsProviders: Component = () => { <div class="flex flex-col min-w-0"> <div class="flex flex-wrap items-center gap-x-3 gap-y-1"> <ProviderIcon id={icon("synthetic")} class="size-5 shrink-0 icon-strong-base" /> - <span class="text-14-medium text-text-strong">Custom provider</span> + <span class="text-14-medium text-text-strong">{language.t("provider.custom.title")}</span> <Tag>{language.t("settings.providers.tag.custom")}</Tag> </div> - <span class="text-12-regular text-text-weak pl-8">Add an OpenAI-compatible provider by base URL.</span> + <span class="text-12-regular text-text-weak pl-8"> + {language.t("settings.providers.custom.description")} + </span> </div> <Button size="large" diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index f87c3fb39..112bc9240 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -204,7 +204,10 @@ function createGlobalSync() { showToast({ variant: "error", title: language.t("toast.session.listFailed.title", { project }), - description: formatServerError(err), + description: formatServerError(err, { + unknown: language.t("error.chain.unknown"), + invalidConfiguration: language.t("error.server.invalidConfiguration"), + }), }) }) @@ -234,6 +237,8 @@ function createGlobalSync() { setStore: child[1], vcsCache: cache, loadSessions, + unknownError: language.t("error.chain.unknown"), + invalidConfigurationError: language.t("error.server.invalidConfiguration"), }) })() @@ -308,6 +313,9 @@ function createGlobalSync() { url: globalSDK.url, }), requestFailedTitle: language.t("common.requestFailed"), + unknownError: language.t("error.chain.unknown"), + invalidConfigurationError: language.t("error.server.invalidConfiguration"), + formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }), setGlobalStore, }) } diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index b26106561..bc84eb169 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -36,6 +36,9 @@ export async function bootstrapGlobal(input: { connectErrorTitle: string connectErrorDescription: string requestFailedTitle: string + unknownError: string + invalidConfigurationError: string + formatMoreCount: (count: number) => string setGlobalStore: SetStoreFunction<GlobalStore> }) { const health = await input.globalSDK.global @@ -88,8 +91,11 @@ export async function bootstrapGlobal(input: { const results = await Promise.allSettled(tasks) const errors = results.filter((r): r is PromiseRejectedResult => r.status === "rejected").map((r) => r.reason) if (errors.length) { - const message = errors[0] instanceof Error ? errors[0].message : String(errors[0]) - const more = errors.length > 1 ? ` (+${errors.length - 1} more)` : "" + const message = formatServerError(errors[0], { + unknown: input.unknownError, + invalidConfiguration: input.invalidConfigurationError, + }) + const more = errors.length > 1 ? input.formatMoreCount(errors.length - 1) : "" showToast({ variant: "error", title: input.requestFailedTitle, @@ -116,6 +122,8 @@ export async function bootstrapDirectory(input: { setStore: SetStoreFunction<State> vcsCache: VcsCache loadSessions: (directory: string) => Promise<void> | void + unknownError: string + invalidConfigurationError: string }) { if (input.store.status !== "complete") input.setStore("status", "loading") @@ -137,7 +145,10 @@ export async function bootstrapDirectory(input: { showToast({ variant: "error", title: `Failed to reload ${project}`, - description: formatServerError(err), + description: formatServerError(err, { + unknown: input.unknownError, + invalidConfiguration: input.invalidConfigurationError, + }), }) input.setStore("status", "partial") return diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 0046a8bc4..16f2fbf49 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -734,4 +734,18 @@ export const dict = { "workspace.reset.archived.one": "ستتم أرشفة جلسة واحدة.", "workspace.reset.archived.many": "ستتم أرشفة {{count}} جلسات.", "workspace.reset.note": "سيؤدي هذا إلى إعادة تعيين مساحة العمل لتتطابق مع الفرع الافتراضي.", + "common.open": "فتح", + "dialog.releaseNotes.action.getStarted": "البدء", + "dialog.releaseNotes.action.next": "التالي", + "dialog.releaseNotes.action.hideFuture": "عدم إظهار هذا في المستقبل", + "dialog.releaseNotes.media.alt": "معاينة الإصدار", + "toast.project.reloadFailed.title": "فشل في إعادة تحميل {{project}}", + "error.server.invalidConfiguration": "تكوين غير صالح", + "common.moreCountSuffix": " (+{{count}} إضافي)", + "common.time.justNow": "الآن", + "common.time.minutesAgo.short": "قبل {{count}} د", + "common.time.hoursAgo.short": "قبل {{count}} س", + "common.time.daysAgo.short": "قبل {{count}} ي", + "settings.providers.connected.environmentDescription": "متصل من متغيرات البيئة الخاصة بك", + "settings.providers.custom.description": "أضف مزود متوافق مع OpenAI بواسطة عنوان URL الأساسي.", } diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 0d41ba7fc..26cf433e0 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -742,4 +742,18 @@ export const dict = { "workspace.reset.archived.one": "1 sessão será arquivada.", "workspace.reset.archived.many": "{{count}} sessões serão arquivadas.", "workspace.reset.note": "Isso redefinirá o espaço de trabalho para corresponder ao branch padrão.", + "common.open": "Abrir", + "dialog.releaseNotes.action.getStarted": "Começar", + "dialog.releaseNotes.action.next": "Próximo", + "dialog.releaseNotes.action.hideFuture": "Não mostrar isso no futuro", + "dialog.releaseNotes.media.alt": "Prévia do lançamento", + "toast.project.reloadFailed.title": "Falha ao recarregar {{project}}", + "error.server.invalidConfiguration": "Configuração inválida", + "common.moreCountSuffix": " (+{{count}} mais)", + "common.time.justNow": "Agora mesmo", + "common.time.minutesAgo.short": "{{count}}m atrás", + "common.time.hoursAgo.short": "{{count}}h atrás", + "common.time.daysAgo.short": "{{count}}d atrás", + "settings.providers.connected.environmentDescription": "Conectado a partir de suas variáveis de ambiente", + "settings.providers.custom.description": "Adicionar um provedor compatível com a OpenAI através do URL base.", } diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index a34d857b9..6c8198bd7 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -819,4 +819,18 @@ export const dict = { "workspace.reset.archived.one": "1 sesija će biti arhivirana.", "workspace.reset.archived.many": "Biće arhivirano {{count}} sesija.", "workspace.reset.note": "Ovo će resetovati radni prostor da odgovara podrazumijevanoj grani.", + "common.open": "Otvori", + "dialog.releaseNotes.action.getStarted": "Započni", + "dialog.releaseNotes.action.next": "Sljedeće", + "dialog.releaseNotes.action.hideFuture": "Ne prikazuj ovo u budućnosti", + "dialog.releaseNotes.media.alt": "Pregled izdanja", + "toast.project.reloadFailed.title": "Nije uspjelo ponovno učitavanje {{project}}", + "error.server.invalidConfiguration": "Nevažeća konfiguracija", + "common.moreCountSuffix": " (+{{count}} više)", + "common.time.justNow": "Upravo sada", + "common.time.minutesAgo.short": "prije {{count}} min", + "common.time.hoursAgo.short": "prije {{count}} h", + "common.time.daysAgo.short": "prije {{count}} d", + "settings.providers.connected.environmentDescription": "Povezano sa vašim varijablama okruženja", + "settings.providers.custom.description": "Dodajte provajdera kompatibilnog s OpenAI putem osnovnog URL-a.", } diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 3df23bd43..11da68176 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -813,4 +813,18 @@ export const dict = { "workspace.reset.archived.one": "1 session vil blive arkiveret.", "workspace.reset.archived.many": "{{count}} sessioner vil blive arkiveret.", "workspace.reset.note": "Dette vil nulstille arbejdsområdet til at matche hovedgrenen.", + "common.open": "Åbn", + "dialog.releaseNotes.action.getStarted": "Kom i gang", + "dialog.releaseNotes.action.next": "Næste", + "dialog.releaseNotes.action.hideFuture": "Vis ikke disse i fremtiden", + "dialog.releaseNotes.media.alt": "Forhåndsvisning af udgivelse", + "toast.project.reloadFailed.title": "Kunne ikke genindlæse {{project}}", + "error.server.invalidConfiguration": "Ugyldig konfiguration", + "common.moreCountSuffix": " (+{{count}} mere)", + "common.time.justNow": "Lige nu", + "common.time.minutesAgo.short": "{{count}}m siden", + "common.time.hoursAgo.short": "{{count}}t siden", + "common.time.daysAgo.short": "{{count}}d siden", + "settings.providers.connected.environmentDescription": "Tilsluttet fra dine miljøvariabler", + "settings.providers.custom.description": "Tilføj en OpenAI-kompatibel udbyder via basis-URL.", } diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index ce48a1953..51b9ec353 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -751,4 +751,18 @@ export const dict = { "workspace.reset.archived.one": "1 Sitzung wird archiviert.", "workspace.reset.archived.many": "{{count}} Sitzungen werden archiviert.", "workspace.reset.note": "Dadurch wird der Arbeitsbereich auf den Standard-Branch zurückgesetzt.", + "common.open": "Öffnen", + "dialog.releaseNotes.action.getStarted": "Loslegen", + "dialog.releaseNotes.action.next": "Weiter", + "dialog.releaseNotes.action.hideFuture": "In Zukunft nicht mehr anzeigen", + "dialog.releaseNotes.media.alt": "Vorschau auf die Version", + "toast.project.reloadFailed.title": "Fehler beim Neuladen von {{project}}", + "error.server.invalidConfiguration": "Ungültige Konfiguration", + "common.moreCountSuffix": " (+{{count}} weitere)", + "common.time.justNow": "Gerade eben", + "common.time.minutesAgo.short": "vor {{count}} Min", + "common.time.hoursAgo.short": "vor {{count}} Std", + "common.time.daysAgo.short": "vor {{count}} Tg", + "settings.providers.connected.environmentDescription": "Verbunden aus Ihren Umgebungsvariablen", + "settings.providers.custom.description": "Fügen Sie einen OpenAI-kompatiblen Anbieter per Basis-URL hinzu.", } satisfies Partial<Record<Keys, string>> diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 4b97bfb89..7e95fd739 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -218,6 +218,7 @@ export const dict = { "common.loading": "Loading", "common.loading.ellipsis": "...", "common.cancel": "Cancel", + "common.open": "Open", "common.connect": "Connect", "common.disconnect": "Disconnect", "common.submit": "Submit", @@ -347,6 +348,11 @@ export const dict = { "dialog.project.edit.worktree.startup.description": "Runs after creating a new workspace (worktree).", "dialog.project.edit.worktree.startup.placeholder": "e.g. bun install", + "dialog.releaseNotes.action.getStarted": "Get started", + "dialog.releaseNotes.action.next": "Next", + "dialog.releaseNotes.action.hideFuture": "Don't show these in the future", + "dialog.releaseNotes.media.alt": "Release preview", + "context.breakdown.title": "Context Breakdown", "context.breakdown.note": 'Approximate breakdown of input tokens. "Other" includes tool definitions and overhead.', "context.breakdown.system": "System", @@ -436,6 +442,7 @@ export const dict = { "toast.session.unshare.failed.description": "An error occurred while unsharing the session", "toast.session.listFailed.title": "Failed to load sessions for {{project}}", + "toast.project.reloadFailed.title": "Failed to reload {{project}}", "toast.update.title": "Update available", "toast.update.description": "A new version of OpenCode ({{version}}) is now available to install.", @@ -460,6 +467,7 @@ export const dict = { "directory.error.invalidUrl": "Invalid directory in URL.", "error.chain.unknown": "Unknown error", + "error.server.invalidConfiguration": "Invalid configuration", "error.chain.causedBy": "Caused by:", "error.chain.apiError": "API error", "error.chain.status": "Status: {{status}}", @@ -570,6 +578,7 @@ export const dict = { "common.closeTab": "Close tab", "common.dismiss": "Dismiss", + "common.moreCountSuffix": " (+{{count}} more)", "common.requestFailed": "Request failed", "common.moreOptions": "More options", "common.learnMore": "Learn more", @@ -582,6 +591,11 @@ export const dict = { "common.loadMore": "Load more", "common.key.esc": "ESC", + "common.time.justNow": "Just now", + "common.time.minutesAgo.short": "{{count}}m ago", + "common.time.hoursAgo.short": "{{count}}h ago", + "common.time.daysAgo.short": "{{count}}d ago", + "sidebar.menu.toggle": "Toggle menu", "sidebar.nav.projectsAndSessions": "Projects and sessions", "sidebar.settings": "Settings", @@ -742,7 +756,9 @@ export const dict = { "settings.providers.description": "Provider settings will be configurable here.", "settings.providers.section.connected": "Connected providers", "settings.providers.connected.empty": "No connected providers", + "settings.providers.connected.environmentDescription": "Connected from your environment variables", "settings.providers.section.popular": "Popular providers", + "settings.providers.custom.description": "Add an OpenAI-compatible provider by base URL.", "settings.providers.tag.environment": "Environment", "settings.providers.tag.config": "Config", "settings.providers.tag.custom": "Custom", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index de490cbe9..2665a8085 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -825,4 +825,18 @@ export const dict = { "workspace.reset.archived.one": "1 sesión será archivada.", "workspace.reset.archived.many": "{{count}} sesiones serán archivadas.", "workspace.reset.note": "Esto restablecerá el espacio de trabajo para coincidir con la rama predeterminada.", + "common.open": "Abrir", + "dialog.releaseNotes.action.getStarted": "Comenzar", + "dialog.releaseNotes.action.next": "Siguiente", + "dialog.releaseNotes.action.hideFuture": "No mostrar esto en el futuro", + "dialog.releaseNotes.media.alt": "Vista previa de la versión", + "toast.project.reloadFailed.title": "Error al recargar {{project}}", + "error.server.invalidConfiguration": "Configuración inválida", + "common.moreCountSuffix": " (+{{count}} más)", + "common.time.justNow": "Justo ahora", + "common.time.minutesAgo.short": "hace {{count}} min", + "common.time.hoursAgo.short": "hace {{count}} h", + "common.time.daysAgo.short": "hace {{count}} d", + "settings.providers.connected.environmentDescription": "Conectado desde tus variables de entorno", + "settings.providers.custom.description": "Añade un proveedor compatible con OpenAI por su URL base.", } diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 5e197b4fb..1e67db193 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -749,4 +749,18 @@ export const dict = { "workspace.reset.archived.one": "1 session sera archivée.", "workspace.reset.archived.many": "{{count}} sessions seront archivées.", "workspace.reset.note": "Cela réinitialisera l'espace de travail pour correspondre à la branche par défaut.", + "common.open": "Ouvrir", + "dialog.releaseNotes.action.getStarted": "Commencer", + "dialog.releaseNotes.action.next": "Suivant", + "dialog.releaseNotes.action.hideFuture": "Ne plus afficher à l'avenir", + "dialog.releaseNotes.media.alt": "Aperçu de la version", + "toast.project.reloadFailed.title": "Échec du rechargement de {{project}}", + "error.server.invalidConfiguration": "Configuration invalide", + "common.moreCountSuffix": " (+{{count}} de plus)", + "common.time.justNow": "À l'instant", + "common.time.minutesAgo.short": "il y a {{count}}m", + "common.time.hoursAgo.short": "il y a {{count}}h", + "common.time.daysAgo.short": "il y a {{count}}j", + "settings.providers.connected.environmentDescription": "Connecté à partir de vos variables d'environnement", + "settings.providers.custom.description": "Ajouter un fournisseur compatible avec OpenAI via l'URL de base.", } diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 30f27c197..ecd38d332 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -738,4 +738,18 @@ export const dict = { "workspace.reset.archived.one": "1つのセッションがアーカイブされます。", "workspace.reset.archived.many": "{{count}}個のセッションがアーカイブされます。", "workspace.reset.note": "これにより、ワークスペースはデフォルトブランチと一致するようにリセットされます。", + "common.open": "開く", + "dialog.releaseNotes.action.getStarted": "始める", + "dialog.releaseNotes.action.next": "次へ", + "dialog.releaseNotes.action.hideFuture": "今後表示しない", + "dialog.releaseNotes.media.alt": "リリースのプレビュー", + "toast.project.reloadFailed.title": "{{project}} の再読み込みに失敗しました", + "error.server.invalidConfiguration": "無効な設定", + "common.moreCountSuffix": " (他 {{count}} 件)", + "common.time.justNow": "たった今", + "common.time.minutesAgo.short": "{{count}} 分前", + "common.time.hoursAgo.short": "{{count}} 時間前", + "common.time.daysAgo.short": "{{count}} 日前", + "settings.providers.connected.environmentDescription": "環境変数から接続されました", + "settings.providers.custom.description": "ベース URL を指定して OpenAI 互換のプロバイダーを追加します。", } diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index da6cde9ea..8f54b8abd 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -738,4 +738,18 @@ export const dict = { "workspace.reset.archived.one": "1개의 세션이 보관됩니다.", "workspace.reset.archived.many": "{{count}}개의 세션이 보관됩니다.", "workspace.reset.note": "이 작업은 작업 공간을 기본 브랜치와 일치하도록 재설정합니다.", + "common.open": "열기", + "dialog.releaseNotes.action.getStarted": "시작하기", + "dialog.releaseNotes.action.next": "다음", + "dialog.releaseNotes.action.hideFuture": "다시 보지 않기", + "dialog.releaseNotes.media.alt": "릴리스 미리보기", + "toast.project.reloadFailed.title": "{{project}} 다시 불러오기 실패", + "error.server.invalidConfiguration": "잘못된 구성", + "common.moreCountSuffix": " (외 {{count}}개)", + "common.time.justNow": "방금 전", + "common.time.minutesAgo.short": "{{count}}분 전", + "common.time.hoursAgo.short": "{{count}}시간 전", + "common.time.daysAgo.short": "{{count}}일 전", + "settings.providers.connected.environmentDescription": "환경 변수에서 연결됨", + "settings.providers.custom.description": "기본 URL로 OpenAI 호환 공급자를 추가합니다.", } diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index bc04695d3..0c94046eb 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -821,4 +821,18 @@ export const dict = { "workspace.reset.archived.one": "1 sesjon vil bli arkivert.", "workspace.reset.archived.many": "{{count}} sesjoner vil bli arkivert.", "workspace.reset.note": "Dette vil tilbakestille arbeidsområdet til å samsvare med standardgrenen.", + "common.open": "Åpne", + "dialog.releaseNotes.action.getStarted": "Kom i gang", + "dialog.releaseNotes.action.next": "Neste", + "dialog.releaseNotes.action.hideFuture": "Ikke vis disse igjen", + "dialog.releaseNotes.media.alt": "Forhåndsvisning av utgivelse", + "toast.project.reloadFailed.title": "Kunne ikke laste inn {{project}} på nytt", + "error.server.invalidConfiguration": "Ugyldig konfigurasjon", + "common.moreCountSuffix": " (+{{count}} mer)", + "common.time.justNow": "Akkurat nå", + "common.time.minutesAgo.short": "{{count}} m siden", + "common.time.hoursAgo.short": "{{count}} t siden", + "common.time.daysAgo.short": "{{count}} d siden", + "settings.providers.connected.environmentDescription": "Koblet til fra miljøvariablene dine", + "settings.providers.custom.description": "Legg til en OpenAI-kompatibel leverandør via basis-URL.", } satisfies Partial<Record<Keys, string>> diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 0be46f095..59c0513be 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -740,4 +740,18 @@ export const dict = { "workspace.reset.archived.one": "1 sesja zostanie zarchiwizowana.", "workspace.reset.archived.many": "{{count}} sesji zostanie zarchiwizowanych.", "workspace.reset.note": "To zresetuje przestrzeń roboczą, aby odpowiadała domyślnej gałęzi.", + "common.open": "Otwórz", + "dialog.releaseNotes.action.getStarted": "Rozpocznij", + "dialog.releaseNotes.action.next": "Dalej", + "dialog.releaseNotes.action.hideFuture": "Nie pokazuj tego w przyszłości", + "dialog.releaseNotes.media.alt": "Podgląd wydania", + "toast.project.reloadFailed.title": "Nie udało się ponownie wczytać {{project}}", + "error.server.invalidConfiguration": "Nieprawidłowa konfiguracja", + "common.moreCountSuffix": " (jeszcze {{count}})", + "common.time.justNow": "Przed chwilą", + "common.time.minutesAgo.short": "{{count}} min temu", + "common.time.hoursAgo.short": "{{count}} godz. temu", + "common.time.daysAgo.short": "{{count}} dni temu", + "settings.providers.connected.environmentDescription": "Połączono ze zmiennymi środowiskowymi", + "settings.providers.custom.description": "Dodaj dostawcę zgodnego z OpenAI poprzez podstawowy URL.", } diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index cbb916a59..2071eaae7 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -821,4 +821,18 @@ export const dict = { "workspace.reset.archived.one": "1 сессия будет архивирована.", "workspace.reset.archived.many": "{{count}} сессий будет архивировано.", "workspace.reset.note": "Рабочее пространство будет сброшено в соответствие с веткой по умолчанию.", + "common.open": "Открыть", + "dialog.releaseNotes.action.getStarted": "Начать", + "dialog.releaseNotes.action.next": "Далее", + "dialog.releaseNotes.action.hideFuture": "Больше не показывать", + "dialog.releaseNotes.media.alt": "Превью релиза", + "toast.project.reloadFailed.title": "Не удалось перезагрузить {{project}}", + "error.server.invalidConfiguration": "Недопустимая конфигурация", + "common.moreCountSuffix": " (ещё {{count}})", + "common.time.justNow": "Только что", + "common.time.minutesAgo.short": "{{count}} мин назад", + "common.time.hoursAgo.short": "{{count}} ч назад", + "common.time.daysAgo.short": "{{count}} д назад", + "settings.providers.connected.environmentDescription": "Подключено из ваших переменных окружения", + "settings.providers.custom.description": "Добавить провайдера, совместимого с OpenAI, по базовому URL.", } diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index c6a33dc67..987155553 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -811,4 +811,18 @@ export const dict = { "workspace.reset.archived.one": "1 เซสชันจะถูกจัดเก็บ", "workspace.reset.archived.many": "{{count}} เซสชันจะถูกจัดเก็บ", "workspace.reset.note": "สิ่งนี้จะรีเซ็ตพื้นที่ทำงานให้ตรงกับสาขาเริ่มต้น", + "common.open": "เปิด", + "dialog.releaseNotes.action.getStarted": "เริ่มต้น", + "dialog.releaseNotes.action.next": "ถัดไป", + "dialog.releaseNotes.action.hideFuture": "ไม่ต้องแสดงสิ่งนี้อีกในอนาคต", + "dialog.releaseNotes.media.alt": "ตัวอย่างรุ่น", + "toast.project.reloadFailed.title": "ไม่สามารถโหลด {{project}} ใหม่ได้", + "error.server.invalidConfiguration": "การกำหนดค่าไม่ถูกต้อง", + "common.moreCountSuffix": " (เพิ่มอีก {{count}})", + "common.time.justNow": "เมื่อสักครู่นี้", + "common.time.minutesAgo.short": "{{count}} นาทีที่แล้ว", + "common.time.hoursAgo.short": "{{count}} ชม. ที่แล้ว", + "common.time.daysAgo.short": "{{count}} วันที่แล้ว", + "settings.providers.connected.environmentDescription": "เชื่อมต่อจากตัวแปรสภาพแวดล้อมของคุณ", + "settings.providers.custom.description": "เพิ่มผู้ให้บริการที่รองรับ OpenAI ด้วย URL หลัก", } diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index 4a38e61ec..701ee0919 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -832,4 +832,18 @@ export const dict = { "workspace.reset.archived.one": "1 oturum arşivlenecek.", "workspace.reset.archived.many": "{{count}} oturum arşivlenecek.", "workspace.reset.note": "Bu işlem çalışma alanını varsayılan dalla eşleşecek şekilde sıfırlayacak.", + "common.open": "Aç", + "dialog.releaseNotes.action.getStarted": "Başla", + "dialog.releaseNotes.action.next": "İleri", + "dialog.releaseNotes.action.hideFuture": "Bunu gelecekte bir daha gösterme", + "dialog.releaseNotes.media.alt": "Sürüm önizlemesi", + "toast.project.reloadFailed.title": "{{project}} yeniden yüklenemedi", + "error.server.invalidConfiguration": "Geçersiz yapılandırma", + "common.moreCountSuffix": " (+{{count}} daha)", + "common.time.justNow": "Şimdi", + "common.time.minutesAgo.short": "{{count}}dk önce", + "common.time.hoursAgo.short": "{{count}}sa önce", + "common.time.daysAgo.short": "{{count}}g önce", + "settings.providers.connected.environmentDescription": "Ortam değişkenlerinizden bağlandı", + "settings.providers.custom.description": "Temel URL üzerinden OpenAI uyumlu bir sağlayıcı ekleyin.", } satisfies Partial<Record<Keys, string>> diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 0b5739083..e72d4c0e3 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -809,4 +809,18 @@ export const dict = { "workspace.reset.archived.one": "将归档 1 个会话。", "workspace.reset.archived.many": "将归档 {{count}} 个会话。", "workspace.reset.note": "这将把工作区重置为与默认分支一致。", + "common.open": "打开", + "dialog.releaseNotes.action.getStarted": "开始", + "dialog.releaseNotes.action.next": "下一步", + "dialog.releaseNotes.action.hideFuture": "不再显示", + "dialog.releaseNotes.media.alt": "发布预览", + "toast.project.reloadFailed.title": "无法重新加载 {{project}}", + "error.server.invalidConfiguration": "配置无效", + "common.moreCountSuffix": " (还有 {{count}} 个)", + "common.time.justNow": "刚刚", + "common.time.minutesAgo.short": "{{count}}分钟前", + "common.time.hoursAgo.short": "{{count}}小时前", + "common.time.daysAgo.short": "{{count}}天前", + "settings.providers.connected.environmentDescription": "已通过环境变量连接", + "settings.providers.custom.description": "通过基础 URL 添加与 OpenAI 兼容的提供商。", } satisfies Partial<Record<Keys, string>> diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 4e4509e20..70421dfe1 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -804,4 +804,18 @@ export const dict = { "workspace.reset.archived.one": "將封存 1 個工作階段。", "workspace.reset.archived.many": "將封存 {{count}} 個工作階段。", "workspace.reset.note": "這將把工作區重設為與預設分支一致。", + "common.open": "打開", + "dialog.releaseNotes.action.getStarted": "開始", + "dialog.releaseNotes.action.next": "下一步", + "dialog.releaseNotes.action.hideFuture": "不再顯示", + "dialog.releaseNotes.media.alt": "發佈預覽", + "toast.project.reloadFailed.title": "無法重新載入 {{project}}", + "error.server.invalidConfiguration": "無效的設定", + "common.moreCountSuffix": " (還有 {{count}} 個)", + "common.time.justNow": "剛剛", + "common.time.minutesAgo.short": "{{count}}分鐘前", + "common.time.hoursAgo.short": "{{count}}小時前", + "common.time.daysAgo.short": "{{count}}天前", + "settings.providers.connected.environmentDescription": "已從環境變數連線", + "settings.providers.custom.description": "透過基本 URL 新增與 OpenAI 相容的提供者。", } satisfies Partial<Record<Keys, string>> diff --git a/packages/app/src/utils/server-errors.ts b/packages/app/src/utils/server-errors.ts index 4b9727e61..85ebca132 100644 --- a/packages/app/src/utils/server-errors.ts +++ b/packages/app/src/utils/server-errors.ts @@ -7,11 +7,28 @@ export type ConfigInvalidError = { } } -export function formatServerError(error: unknown) { - if (isConfigInvalidErrorLike(error)) return parseReabaleConfigInvalidError(error) +type Label = { + unknown: string + invalidConfiguration: string +} + +const fallback: Label = { + unknown: "Unknown error", + invalidConfiguration: "Invalid configuration", +} + +function resolveLabel(labels: Partial<Label> | undefined): Label { + return { + unknown: labels?.unknown ?? fallback.unknown, + invalidConfiguration: labels?.invalidConfiguration ?? fallback.invalidConfiguration, + } +} + +export function formatServerError(error: unknown, labels?: Partial<Label>) { + if (isConfigInvalidErrorLike(error)) return parseReabaleConfigInvalidError(error, labels) if (error instanceof Error && error.message) return error.message if (typeof error === "string" && error) return error - return "Unknown error" + return resolveLabel(labels).unknown } function isConfigInvalidErrorLike(error: unknown): error is ConfigInvalidError { @@ -20,8 +37,8 @@ function isConfigInvalidErrorLike(error: unknown): error is ConfigInvalidError { return o.name === "ConfigInvalidError" && typeof o.data === "object" && o.data !== null } -export function parseReabaleConfigInvalidError(errorInput: ConfigInvalidError) { - const head = "Invalid configuration" +export function parseReabaleConfigInvalidError(errorInput: ConfigInvalidError, labels?: Partial<Label>) { + const head = resolveLabel(labels).invalidConfiguration const file = errorInput.data.path && errorInput.data.path !== "config" ? errorInput.data.path : "" const detail = errorInput.data.message?.trim() ?? "" const issues = (errorInput.data.issues ?? []).map((issue) => { diff --git a/packages/app/src/utils/time.ts b/packages/app/src/utils/time.ts index ac709d86d..d183e1080 100644 --- a/packages/app/src/utils/time.ts +++ b/packages/app/src/utils/time.ts @@ -1,4 +1,12 @@ -export function getRelativeTime(dateString: string): string { +type TimeKey = + | "common.time.justNow" + | "common.time.minutesAgo.short" + | "common.time.hoursAgo.short" + | "common.time.daysAgo.short" + +type Translate = (key: TimeKey, params?: Record<string, string | number>) => string + +export function getRelativeTime(dateString: string, t: Translate): string { const date = new Date(dateString) const now = new Date() const diffMs = now.getTime() - date.getTime() @@ -7,8 +15,8 @@ export function getRelativeTime(dateString: string): string { const diffHours = Math.floor(diffMinutes / 60) const diffDays = Math.floor(diffHours / 24) - if (diffSeconds < 60) return "Just now" - if (diffMinutes < 60) return `${diffMinutes}m ago` - if (diffHours < 24) return `${diffHours}h ago` - return `${diffDays}d ago` + if (diffSeconds < 60) return t("common.time.justNow") + if (diffMinutes < 60) return t("common.time.minutesAgo.short", { count: diffMinutes }) + if (diffHours < 24) return t("common.time.hoursAgo.short", { count: diffHours }) + return t("common.time.daysAgo.short", { count: diffDays }) } |
