Adam 1 місяць тому
батько
коміт
7f851da15e
32 змінених файлів з 664 додано та 56 видалено
  1. 14 5
      packages/console/app/src/app.tsx
  2. 2 2
      packages/console/app/src/component/header.tsx
  3. 33 0
      packages/console/app/src/i18n/ar.ts
  4. 33 0
      packages/console/app/src/i18n/br.ts
  5. 33 0
      packages/console/app/src/i18n/da.ts
  6. 33 0
      packages/console/app/src/i18n/de.ts
  7. 33 0
      packages/console/app/src/i18n/en.ts
  8. 33 0
      packages/console/app/src/i18n/es.ts
  9. 31 0
      packages/console/app/src/i18n/fr.ts
  10. 33 0
      packages/console/app/src/i18n/it.ts
  11. 34 0
      packages/console/app/src/i18n/ja.ts
  12. 33 0
      packages/console/app/src/i18n/ko.ts
  13. 33 0
      packages/console/app/src/i18n/no.ts
  14. 33 0
      packages/console/app/src/i18n/pl.ts
  15. 33 0
      packages/console/app/src/i18n/ru.ts
  16. 33 0
      packages/console/app/src/i18n/th.ts
  17. 33 0
      packages/console/app/src/i18n/tr.ts
  18. 31 0
      packages/console/app/src/i18n/zh.ts
  19. 31 0
      packages/console/app/src/i18n/zht.ts
  20. 3 0
      packages/console/app/src/lib/form-error.ts
  21. 2 2
      packages/console/app/src/routes/[...404].tsx
  22. 7 4
      packages/console/app/src/routes/api/enterprise.ts
  23. 3 1
      packages/console/app/src/routes/auth/[...callback].ts
  24. 4 1
      packages/console/app/src/routes/bench/submission.ts
  25. 9 8
      packages/console/app/src/routes/brand/index.tsx
  26. 1 1
      packages/console/app/src/routes/download/[channel]/[platform].ts
  27. 1 1
      packages/console/app/src/routes/stripe/webhook.ts
  28. 2 2
      packages/console/app/src/routes/temp.tsx
  29. 2 1
      packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx
  30. 2 1
      packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx
  31. 50 24
      packages/console/app/src/routes/zen/util/handler.ts
  32. 6 3
      packages/console/app/src/routes/zen/util/rateLimiter.ts

+ 14 - 5
packages/console/app/src/app.tsx

@@ -7,9 +7,21 @@ import { Font } from "@opencode-ai/ui/font"
 import "@ibm/plex/css/ibm-plex.css"
 import "./app.css"
 import { LanguageProvider } from "~/context/language"
-import { I18nProvider } from "~/context/i18n"
+import { I18nProvider, useI18n } from "~/context/i18n"
 import { strip } from "~/lib/language"
 
+function AppMeta() {
+  const i18n = useI18n()
+  return (
+    <>
+      <Title>opencode</Title>
+      <Meta name="description" content={i18n.t("app.meta.description")} />
+      <Favicon />
+      <Font />
+    </>
+  )
+}
+
 export default function App() {
   return (
     <Router
@@ -19,10 +31,7 @@ export default function App() {
         <LanguageProvider>
           <I18nProvider>
             <MetaProvider>
-              <Title>opencode</Title>
-              <Meta name="description" content="OpenCode - The open source coding agent." />
-              <Favicon />
-              <Font />
+              <AppMeta />
               <Suspense>{props.children}</Suspense>
             </MetaProvider>
           </I18nProvider>

+ 2 - 2
packages/console/app/src/component/header.tsx

@@ -124,8 +124,8 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
     <section data-component="top">
       <div onContextMenu={handleLogoContextMenu}>
         <A href={language.route("/")}>
-          <img data-slot="logo light" src={logoLight} alt="OpenCode" width="189" height="34" />
-          <img data-slot="logo dark" src={logoDark} alt="OpenCode" width="189" height="34" />
+          <img data-slot="logo light" src={logoLight} alt={i18n.t("nav.logoAlt")} width="189" height="34" />
+          <img data-slot="logo dark" src={logoDark} alt={i18n.t("nav.logoAlt")} width="189" height="34" />
         </A>
       </div>
 

+ 33 - 0
packages/console/app/src/i18n/ar.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "الرئيسية",
   "nav.openMenu": "فتح القائمة",
   "nav.getStartedFree": "ابدأ مجانا",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "نسخ الشعار كـ SVG",
   "nav.context.copyWordmark": "نسخ اسم العلامة كـ SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "الوثائق",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "شعار opencode الفاتح",
+  "notFound.logoDarkAlt": "شعار opencode الداكن",
 
   "user.logout": "تسجيل الخروج",
 
+  "auth.callback.error.codeMissing": "لم يتم العثور على رمز التفويض.",
+
   "workspace.select": "اختر مساحة العمل",
   "workspace.createNew": "+ إنشاء مساحة عمل جديدة",
   "workspace.modal.title": "إنشاء مساحة عمل جديدة",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "يجب أن يكون مبلغ الشحن ${{amount}} على الأقل",
   "error.reloadTriggerMin": "يجب أن يكون حد الرصيد ${{amount}} على الأقل",
 
+  "app.meta.description": "OpenCode - وكيل البرمجة مفتوح المصدر.",
+
   "home.title": "OpenCode | وكيل برمجة بالذكاء الاصطناعي مفتوح المصدر",
 
   "temp.title": "opencode | وكيل برمجة بالذكاء الاصطناعي مبني للطرفية",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": "، بما في ذلك النماذج المحلية",
   "temp.screenshot.caption": "واجهة OpenCode الطرفية مع سمة tokyonight",
   "temp.screenshot.alt": "واجهة OpenCode الطرفية بسمة tokyonight",
+  "temp.logoLightAlt": "شعار opencode الفاتح",
+  "temp.logoDarkAlt": "شعار opencode الداكن",
 
   "home.banner.badge": "جديد",
   "home.banner.text": "تطبيق سطح المكتب متاح بنسخة تجريبية",
@@ -238,6 +247,24 @@ export const dict = {
     "تتم استضافة جميع نماذج Zen في الولايات المتحدة. يتبع المزودون سياسة عدم الاحتفاظ بالبيانات ولا يستخدمون بياناتك لتدريب النماذج، مع",
   "zen.privacy.exceptionsLink": "الاستثناءات التالية",
 
+  "zen.api.error.rateLimitExceeded": "تم تجاوز حد الطلبات. يرجى المحاولة مرة أخرى لاحقًا.",
+  "zen.api.error.modelNotSupported": "النموذج {{model}} غير مدعوم",
+  "zen.api.error.modelFormatNotSupported": "النموذج {{model}} غير مدعوم للتنسيق {{format}}",
+  "zen.api.error.noProviderAvailable": "لا يوجد مزود متاح",
+  "zen.api.error.providerNotSupported": "المزود {{provider}} غير مدعوم",
+  "zen.api.error.missingApiKey": "مفتاح API مفقود.",
+  "zen.api.error.invalidApiKey": "مفتاح API غير صالح.",
+  "zen.api.error.subscriptionQuotaExceeded": "تم تجاوز حصة الاشتراك. أعد المحاولة خلال {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "تم تجاوز حصة الاشتراك. يمكنك الاستمرار في استخدام النماذج المجانية.",
+  "zen.api.error.noPaymentMethod": "لا توجد طريقة دفع. أضف طريقة دفع هنا: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "رصيد غير كاف. إدارة فواتيرك هنا: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "وصلت مساحة العمل الخاصة بك إلى حد الإنفاق الشهري البالغ ${{amount}}. إدارة حدودك هنا: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "لقد وصلت إلى حد الإنفاق الشهري البالغ ${{amount}}. إدارة حدودك هنا: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "النموذج معطل",
+
   "black.meta.title": "OpenCode Black | الوصول إلى أفضل نماذج البرمجة في العالم",
   "black.meta.description": "احصل على وصول إلى Claude، GPT، Gemini والمزيد مع خطط اشتراك OpenCode Black.",
   "black.hero.title": "الوصول إلى أفضل نماذج البرمجة في العالم",
@@ -446,6 +473,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "يرجى تحديث طريقة الدفع والمحاولة مرة أخرى.",
   "workspace.reload.retrying": "جارٍ إعادة المحاولة...",
   "workspace.reload.retry": "أعد المحاولة",
+  "workspace.reload.error.paymentFailed": "فشلت عملية الدفع.",
 
   "workspace.payments.title": "سجل المدفوعات",
   "workspace.payments.subtitle": "معاملات الدفع الأخيرة.",
@@ -563,6 +591,10 @@ export const dict = {
   "enterprise.form.send": "إرسال",
   "enterprise.form.sending": "جارٍ الإرسال...",
   "enterprise.form.success": "تم إرسال الرسالة، سنتواصل معك قريبًا.",
+  "enterprise.form.success.submitted": "تم إرسال النموذج بنجاح.",
+  "enterprise.form.error.allFieldsRequired": "جميع الحقول مطلوبة.",
+  "enterprise.form.error.invalidEmailFormat": "تنسيق البريد الإلكتروني غير صالح.",
+  "enterprise.form.error.internalServer": "خطأ داخلي في الخادم.",
   "enterprise.faq.title": "الأسئلة الشائعة",
   "enterprise.faq.q1": "ما هو OpenCode Enterprise؟",
   "enterprise.faq.a1":
@@ -595,6 +627,7 @@ export const dict = {
   "bench.list.table.agent": "الوكيل",
   "bench.list.table.model": "النموذج",
   "bench.list.table.score": "الدرجة",
+  "bench.submission.error.allFieldsRequired": "جميع الحقول مطلوبة.",
 
   "bench.detail.title": "المعيار - {{task}}",
   "bench.detail.notFound": "المهمة غير موجودة",

+ 33 - 0
packages/console/app/src/i18n/br.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Início",
   "nav.openMenu": "Abrir menu",
   "nav.getStartedFree": "Começar grátis",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Copiar logo como SVG",
   "nav.context.copyWordmark": "Copiar marca como SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Documentação",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "logo opencode claro",
+  "notFound.logoDarkAlt": "logo opencode escuro",
 
   "user.logout": "Sair",
 
+  "auth.callback.error.codeMissing": "Nenhum código de autorização encontrado.",
+
   "workspace.select": "Selecionar workspace",
   "workspace.createNew": "+ Criar novo workspace",
   "workspace.modal.title": "Criar novo workspace",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "O valor de recarga deve ser de pelo menos ${{amount}}",
   "error.reloadTriggerMin": "O gatilho de saldo deve ser de pelo menos ${{amount}}",
 
+  "app.meta.description": "OpenCode - O agente de codificação de código aberto.",
+
   "home.title": "OpenCode | O agente de codificação de código aberto com IA",
 
   "temp.title": "opencode | Agente de codificação com IA feito para o terminal",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", incluindo modelos locais",
   "temp.screenshot.caption": "OpenCode TUI com o tema tokyonight",
   "temp.screenshot.alt": "OpenCode TUI com tema tokyonight",
+  "temp.logoLightAlt": "logo opencode claro",
+  "temp.logoDarkAlt": "logo opencode escuro",
 
   "home.banner.badge": "Novo",
   "home.banner.text": "App desktop disponível em beta",
@@ -242,6 +251,24 @@ export const dict = {
     "Todos os modelos Zen são hospedados nos EUA. Os provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelo, com as",
   "zen.privacy.exceptionsLink": "seguintes exceções",
 
+  "zen.api.error.rateLimitExceeded": "Limite de taxa excedido. Por favor, tente novamente mais tarde.",
+  "zen.api.error.modelNotSupported": "Modelo {{model}} não suportado",
+  "zen.api.error.modelFormatNotSupported": "Modelo {{model}} não suportado para o formato {{format}}",
+  "zen.api.error.noProviderAvailable": "Nenhum provedor disponível",
+  "zen.api.error.providerNotSupported": "Provedor {{provider}} não suportado",
+  "zen.api.error.missingApiKey": "Chave de API ausente.",
+  "zen.api.error.invalidApiKey": "Chave de API inválida.",
+  "zen.api.error.subscriptionQuotaExceeded": "Cota de assinatura excedida. Tente novamente em {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Cota de assinatura excedida. Você pode continuar usando modelos gratuitos.",
+  "zen.api.error.noPaymentMethod": "Nenhuma forma de pagamento. Adicione uma forma de pagamento aqui: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Saldo insuficiente. Gerencie seu faturamento aqui: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Seu workspace atingiu o limite de gastos mensais de ${{amount}}. Gerencie seus limites aqui: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Você atingiu seu limite de gastos mensais de ${{amount}}. Gerencie seus limites aqui: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "O modelo está desabilitado",
+
   "black.meta.title": "OpenCode Black | Acesse os melhores modelos de codificação do mundo",
   "black.meta.description": "Tenha acesso ao Claude, GPT, Gemini e mais com os planos de assinatura OpenCode Black.",
   "black.hero.title": "Acesse os melhores modelos de codificação do mundo",
@@ -451,6 +478,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Por favor, atualize sua forma de pagamento e tente novamente.",
   "workspace.reload.retrying": "Tentando novamente...",
   "workspace.reload.retry": "Tentar novamente",
+  "workspace.reload.error.paymentFailed": "Pagamento falhou.",
 
   "workspace.payments.title": "Histórico de Pagamentos",
   "workspace.payments.subtitle": "Transações de pagamento recentes.",
@@ -571,6 +599,10 @@ export const dict = {
   "enterprise.form.send": "Enviar",
   "enterprise.form.sending": "Enviando...",
   "enterprise.form.success": "Mensagem enviada, entraremos em contato em breve.",
+  "enterprise.form.success.submitted": "Formulário enviado com sucesso.",
+  "enterprise.form.error.allFieldsRequired": "Todos os campos são obrigatórios.",
+  "enterprise.form.error.invalidEmailFormat": "Formato de e-mail inválido.",
+  "enterprise.form.error.internalServer": "Erro interno do servidor.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "O que é OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -603,6 +635,7 @@ export const dict = {
   "bench.list.table.agent": "Agente",
   "bench.list.table.model": "Modelo",
   "bench.list.table.score": "Pontuação",
+  "bench.submission.error.allFieldsRequired": "Todos os campos são obrigatórios.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Tarefa não encontrada",

+ 33 - 0
packages/console/app/src/i18n/da.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Hjem",
   "nav.openMenu": "Åbn menu",
   "nav.getStartedFree": "Kom i gang gratis",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Kopier logo som SVG",
   "nav.context.copyWordmark": "Kopier wordmark som SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Dokumentation",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo light",
+  "notFound.logoDarkAlt": "opencode logo dark",
 
   "user.logout": "Log ud",
 
+  "auth.callback.error.codeMissing": "Ingen autorisationskode fundet.",
+
   "workspace.select": "Vælg workspace",
   "workspace.createNew": "+ Opret nyt workspace",
   "workspace.modal.title": "Opret nyt workspace",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "Genopfyldningsbeløb skal være mindst ${{amount}}",
   "error.reloadTriggerMin": "Saldogrænse skal være mindst ${{amount}}",
 
+  "app.meta.description": "OpenCode - Den open source kodningsagent.",
+
   "home.title": "OpenCode | Den open source AI-kodningsagent",
 
   "temp.title": "opencode | AI-kodningsagent bygget til terminalen",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", inklusive lokale modeller",
   "temp.screenshot.caption": "opencode TUI med tokyonight-temaet",
   "temp.screenshot.alt": "opencode TUI med tokyonight-temaet",
+  "temp.logoLightAlt": "opencode logo light",
+  "temp.logoDarkAlt": "opencode logo dark",
 
   "home.banner.badge": "Ny",
   "home.banner.text": "Desktop-app tilgængelig i beta",
@@ -240,6 +249,24 @@ export const dict = {
     "Alle Zen-modeller er hostet i USA. Udbydere følger en nulopbevaringspolitik og bruger ikke dine data til modeltræning med",
   "zen.privacy.exceptionsLink": "følgende undtagelser",
 
+  "zen.api.error.rateLimitExceeded": "Hastighedsgrænse overskredet. Prøv venligst igen senere.",
+  "zen.api.error.modelNotSupported": "Model {{model}} understøttes ikke",
+  "zen.api.error.modelFormatNotSupported": "Model {{model}} understøttes ikke for format {{format}}",
+  "zen.api.error.noProviderAvailable": "Ingen udbyder tilgængelig",
+  "zen.api.error.providerNotSupported": "Udbyder {{provider}} understøttes ikke",
+  "zen.api.error.missingApiKey": "Manglende API-nøgle.",
+  "zen.api.error.invalidApiKey": "Ugyldig API-nøgle.",
+  "zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igen om {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Abonnementskvote overskredet. Du kan fortsætte med at bruge gratis modeller.",
+  "zen.api.error.noPaymentMethod": "Ingen betalingsmetode. Tilføj en betalingsmetode her: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Utilstrækkelig saldo. Administrer din fakturering her: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Dit workspace har nået sin månedlige forbrugsgrænse på ${{amount}}. Administrer dine grænser her: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Du har nået din månedlige forbrugsgrænse på ${{amount}}. Administrer dine grænser her: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Modellen er deaktiveret",
+
   "black.meta.title": "OpenCode Black | Få adgang til verdens bedste kodningsmodeller",
   "black.meta.description": "Få adgang til Claude, GPT, Gemini og mere med OpenCode Black-abonnementer.",
   "black.hero.title": "Få adgang til verdens bedste kodningsmodeller",
@@ -449,6 +476,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Opdater din betalingsmetode, og prøv igen.",
   "workspace.reload.retrying": "Prøver igen...",
   "workspace.reload.retry": "Prøv igen",
+  "workspace.reload.error.paymentFailed": "Betaling mislykkedes.",
 
   "workspace.payments.title": "Betalingshistorik",
   "workspace.payments.subtitle": "Seneste betalingstransaktioner.",
@@ -567,6 +595,10 @@ export const dict = {
   "enterprise.form.send": "Send",
   "enterprise.form.sending": "Sender...",
   "enterprise.form.success": "Besked sendt, vi vender tilbage snart.",
+  "enterprise.form.success.submitted": "Formular indsendt med succes.",
+  "enterprise.form.error.allFieldsRequired": "Alle felter er påkrævet.",
+  "enterprise.form.error.invalidEmailFormat": "Ugyldigt e-mailformat.",
+  "enterprise.form.error.internalServer": "Intern serverfejl.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Hvad er OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -599,6 +631,7 @@ export const dict = {
   "bench.list.table.agent": "Agent",
   "bench.list.table.model": "Model",
   "bench.list.table.score": "Score",
+  "bench.submission.error.allFieldsRequired": "Alle felter er påkrævet.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Opgave ikke fundet",

+ 33 - 0
packages/console/app/src/i18n/de.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Startseite",
   "nav.openMenu": "Menü öffnen",
   "nav.getStartedFree": "Kostenlos starten",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Logo als SVG kopieren",
   "nav.context.copyWordmark": "Wortmarke als SVG kopieren",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Dokumentation",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "OpenCode Logo hell",
+  "notFound.logoDarkAlt": "OpenCode Logo dunkel",
 
   "user.logout": "Abmelden",
 
+  "auth.callback.error.codeMissing": "Kein Autorisierungscode gefunden.",
+
   "workspace.select": "Workspace auswählen",
   "workspace.createNew": "+ Neuen Workspace erstellen",
   "workspace.modal.title": "Neuen Workspace erstellen",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "Aufladebetrag muss mindestens ${{amount}} betragen",
   "error.reloadTriggerMin": "Guthaben-Auslöser muss mindestens ${{amount}} betragen",
 
+  "app.meta.description": "OpenCode - Der Open-Source Coding-Agent.",
+
   "home.title": "OpenCode | Der Open-Source AI-Coding-Agent",
 
   "temp.title": "OpenCode | Für das Terminal gebauter AI-Coding-Agent",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", einschließlich lokaler Modelle",
   "temp.screenshot.caption": "OpenCode TUI mit dem Tokyonight-Theme",
   "temp.screenshot.alt": "OpenCode TUI mit Tokyonight-Theme",
+  "temp.logoLightAlt": "OpenCode Logo hell",
+  "temp.logoDarkAlt": "OpenCode Logo dunkel",
 
   "home.banner.badge": "Neu",
   "home.banner.text": "Desktop-App in der Beta verfügbar",
@@ -242,6 +251,24 @@ export const dict = {
     "Alle Zen-Modelle werden in den USA gehostet. Anbieter folgen einer Zero-Retention-Policy und nutzen deine Daten nicht für Modelltraining, mit den",
   "zen.privacy.exceptionsLink": "folgenden Ausnahmen",
 
+  "zen.api.error.rateLimitExceeded": "Ratenlimit überschritten. Bitte versuche es später erneut.",
+  "zen.api.error.modelNotSupported": "Modell {{model}} wird nicht unterstützt",
+  "zen.api.error.modelFormatNotSupported": "Modell {{model}} wird für das Format {{format}} nicht unterstützt",
+  "zen.api.error.noProviderAvailable": "Kein Anbieter verfügbar",
+  "zen.api.error.providerNotSupported": "Anbieter {{provider}} wird nicht unterstützt",
+  "zen.api.error.missingApiKey": "Fehlender API-Key.",
+  "zen.api.error.invalidApiKey": "Ungültiger API-Key.",
+  "zen.api.error.subscriptionQuotaExceeded": "Abonnement-Quote überschritten. Erneuter Versuch in {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Abonnement-Quote überschritten. Du kannst weiterhin kostenlose Modelle nutzen.",
+  "zen.api.error.noPaymentMethod": "Keine Zahlungsmethode. Füge hier eine Zahlungsmethode hinzu: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Unzureichendes Guthaben. Verwalte deine Abrechnung hier: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Dein Workspace hat sein monatliches Ausgabenlimit von ${{amount}} erreicht. Verwalte deine Limits hier: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Du hast dein monatliches Ausgabenlimit von ${{amount}} erreicht. Verwalte deine Limits hier: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Modell ist deaktiviert",
+
   "black.meta.title": "OpenCode Black | Zugriff auf die weltweit besten Coding-Modelle",
   "black.meta.description": "Erhalte Zugriff auf Claude, GPT, Gemini und mehr mit OpenCode Black Abos.",
   "black.hero.title": "Zugriff auf die weltweit besten Coding-Modelle",
@@ -451,6 +478,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Bitte aktualisiere deine Zahlungsmethode und versuche es erneut.",
   "workspace.reload.retrying": "Versuche erneut...",
   "workspace.reload.retry": "Erneut versuchen",
+  "workspace.reload.error.paymentFailed": "Zahlung fehlgeschlagen.",
 
   "workspace.payments.title": "Zahlungshistorie",
   "workspace.payments.subtitle": "Kürzliche Zahlungstransaktionen.",
@@ -571,6 +599,10 @@ export const dict = {
   "enterprise.form.send": "Senden",
   "enterprise.form.sending": "Sende...",
   "enterprise.form.success": "Nachricht gesendet, wir melden uns bald.",
+  "enterprise.form.success.submitted": "Formular erfolgreich gesendet.",
+  "enterprise.form.error.allFieldsRequired": "Alle Felder sind erforderlich.",
+  "enterprise.form.error.invalidEmailFormat": "Ungültiges E-Mail-Format.",
+  "enterprise.form.error.internalServer": "Interner Serverfehler.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Was ist OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -603,6 +635,7 @@ export const dict = {
   "bench.list.table.agent": "Agent",
   "bench.list.table.model": "Modell",
   "bench.list.table.score": "Score",
+  "bench.submission.error.allFieldsRequired": "Alle Felder sind erforderlich.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Task nicht gefunden",

+ 33 - 0
packages/console/app/src/i18n/en.ts

@@ -11,6 +11,7 @@ export const dict = {
   "nav.home": "Home",
   "nav.openMenu": "Open menu",
   "nav.getStartedFree": "Get started for free",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Copy logo as SVG",
   "nav.context.copyWordmark": "Copy wordmark as SVG",
@@ -38,9 +39,13 @@ export const dict = {
   "notFound.docs": "Docs",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo light",
+  "notFound.logoDarkAlt": "opencode logo dark",
 
   "user.logout": "Logout",
 
+  "auth.callback.error.codeMissing": "No authorization code found.",
+
   "workspace.select": "Select workspace",
   "workspace.createNew": "+ Create New Workspace",
   "workspace.modal.title": "Create New Workspace",
@@ -72,6 +77,8 @@ export const dict = {
   "error.reloadAmountMin": "Reload amount must be at least ${{amount}}",
   "error.reloadTriggerMin": "Balance trigger must be at least ${{amount}}",
 
+  "app.meta.description": "OpenCode - The open source coding agent.",
+
   "home.title": "OpenCode | The open source AI coding agent",
 
   "temp.title": "opencode | AI coding agent built for the terminal",
@@ -87,6 +94,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", including local models",
   "temp.screenshot.caption": "opencode TUI with the tokyonight theme",
   "temp.screenshot.alt": "opencode TUI with tokyonight theme",
+  "temp.logoLightAlt": "opencode logo light",
+  "temp.logoDarkAlt": "opencode logo dark",
 
   "home.banner.badge": "New",
   "home.banner.text": "Desktop app available in beta",
@@ -234,6 +243,24 @@ export const dict = {
     "All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the",
   "zen.privacy.exceptionsLink": "following exceptions",
 
+  "zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.",
+  "zen.api.error.modelNotSupported": "Model {{model}} not supported",
+  "zen.api.error.modelFormatNotSupported": "Model {{model}} not supported for format {{format}}",
+  "zen.api.error.noProviderAvailable": "No provider available",
+  "zen.api.error.providerNotSupported": "Provider {{provider}} not supported",
+  "zen.api.error.missingApiKey": "Missing API key.",
+  "zen.api.error.invalidApiKey": "Invalid API key.",
+  "zen.api.error.subscriptionQuotaExceeded": "Subscription quota exceeded. Retry in {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Subscription quota exceeded. You can continue using free models.",
+  "zen.api.error.noPaymentMethod": "No payment method. Add a payment method here: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Insufficient balance. Manage your billing here: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Your workspace has reached its monthly spending limit of ${{amount}}. Manage your limits here: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "You have reached your monthly spending limit of ${{amount}}. Manage your limits here: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Model is disabled",
+
   "black.meta.title": "OpenCode Black | Access all the world's best coding models",
   "black.meta.description": "Get access to Claude, GPT, Gemini and more with OpenCode Black subscription plans.",
   "black.hero.title": "Access all the world's best coding models",
@@ -443,6 +470,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Please update your payment method and try again.",
   "workspace.reload.retrying": "Retrying...",
   "workspace.reload.retry": "Retry",
+  "workspace.reload.error.paymentFailed": "Payment failed.",
 
   "workspace.payments.title": "Payments History",
   "workspace.payments.subtitle": "Recent payment transactions.",
@@ -561,6 +589,10 @@ export const dict = {
   "enterprise.form.send": "Send",
   "enterprise.form.sending": "Sending...",
   "enterprise.form.success": "Message sent, we'll be in touch soon.",
+  "enterprise.form.success.submitted": "Form submitted successfully.",
+  "enterprise.form.error.allFieldsRequired": "All fields are required.",
+  "enterprise.form.error.invalidEmailFormat": "Invalid email format.",
+  "enterprise.form.error.internalServer": "Internal server error.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "What is OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -593,6 +625,7 @@ export const dict = {
   "bench.list.table.agent": "Agent",
   "bench.list.table.model": "Model",
   "bench.list.table.score": "Score",
+  "bench.submission.error.allFieldsRequired": "All fields are required.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Task not found",

+ 33 - 0
packages/console/app/src/i18n/es.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Inicio",
   "nav.openMenu": "Abrir menú",
   "nav.getStartedFree": "Empezar gratis",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Copiar logo como SVG",
   "nav.context.copyWordmark": "Copiar marca como SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Documentación",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo claro",
+  "notFound.logoDarkAlt": "opencode logo oscuro",
 
   "user.logout": "Cerrar sesión",
 
+  "auth.callback.error.codeMissing": "No se encontró código de autorización.",
+
   "workspace.select": "Seleccionar espacio de trabajo",
   "workspace.createNew": "+ Crear nuevo espacio de trabajo",
   "workspace.modal.title": "Crear nuevo espacio de trabajo",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "La cantidad de recarga debe ser al menos ${{amount}}",
   "error.reloadTriggerMin": "El disparador de saldo debe ser al menos ${{amount}}",
 
+  "app.meta.description": "OpenCode - El agente de codificación de código abierto.",
+
   "home.title": "OpenCode | El agente de codificación IA de código abierto",
 
   "temp.title": "opencode | Agente de codificación IA creado para la terminal",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", incluyendo modelos locales",
   "temp.screenshot.caption": "opencode TUI con el tema tokyonight",
   "temp.screenshot.alt": "opencode TUI con tema tokyonight",
+  "temp.logoLightAlt": "logo de opencode claro",
+  "temp.logoDarkAlt": "logo de opencode oscuro",
 
   "home.banner.badge": "Nuevo",
   "home.banner.text": "Aplicación de escritorio disponible en beta",
@@ -243,6 +252,24 @@ export const dict = {
     "Todos los modelos Zen están alojados en EE. UU. Los proveedores siguen una política de cero retención y no usan tus datos para entrenamiento de modelos, con las",
   "zen.privacy.exceptionsLink": "siguientes excepciones",
 
+  "zen.api.error.rateLimitExceeded": "Límite de tasa excedido. Por favor, inténtalo de nuevo más tarde.",
+  "zen.api.error.modelNotSupported": "Modelo {{model}} no soportado",
+  "zen.api.error.modelFormatNotSupported": "Modelo {{model}} no soportado para el formato {{format}}",
+  "zen.api.error.noProviderAvailable": "Ningún proveedor disponible",
+  "zen.api.error.providerNotSupported": "Proveedor {{provider}} no soportado",
+  "zen.api.error.missingApiKey": "Falta la clave API.",
+  "zen.api.error.invalidApiKey": "Clave API inválida.",
+  "zen.api.error.subscriptionQuotaExceeded": "Cuota de suscripción excedida. Reintenta en {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Cuota de suscripción excedida. Puedes continuar usando modelos gratuitos.",
+  "zen.api.error.noPaymentMethod": "Sin método de pago. Añade un método de pago aquí: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Saldo insuficiente. Gestiona tu facturación aquí: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Tu espacio de trabajo ha alcanzado su límite de gasto mensual de ${{amount}}. Gestiona tus límites aquí: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Has alcanzado tu límite de gasto mensual de ${{amount}}. Gestiona tus límites aquí: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "El modelo está deshabilitado",
+
   "black.meta.title": "OpenCode Black | Accede a los mejores modelos de codificación del mundo",
   "black.meta.description": "Obtén acceso a Claude, GPT, Gemini y más con los planes de suscripción de OpenCode Black.",
   "black.hero.title": "Accede a los mejores modelos de codificación del mundo",
@@ -452,6 +479,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Por favor actualiza tu método de pago e intenta de nuevo.",
   "workspace.reload.retrying": "Reintentando...",
   "workspace.reload.retry": "Reintentar",
+  "workspace.reload.error.paymentFailed": "El pago falló.",
 
   "workspace.payments.title": "Historial de Pagos",
   "workspace.payments.subtitle": "Transacciones de pago recientes.",
@@ -571,6 +599,10 @@ export const dict = {
   "enterprise.form.send": "Enviar",
   "enterprise.form.sending": "Enviando...",
   "enterprise.form.success": "Mensaje enviado, estaremos en contacto pronto.",
+  "enterprise.form.success.submitted": "Formulario enviado con éxito.",
+  "enterprise.form.error.allFieldsRequired": "Todos los campos son obligatorios.",
+  "enterprise.form.error.invalidEmailFormat": "Formato de correo inválido.",
+  "enterprise.form.error.internalServer": "Error interno del servidor.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "¿Qué es OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -603,6 +635,7 @@ export const dict = {
   "bench.list.table.agent": "Agente",
   "bench.list.table.model": "Modelo",
   "bench.list.table.score": "Puntuación",
+  "bench.submission.error.allFieldsRequired": "Todos los campos son obligatorios.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Tarea no encontrada",

+ 31 - 0
packages/console/app/src/i18n/fr.ts

@@ -3,6 +3,7 @@ import { dict as en } from "./en"
 
 export const dict = {
   ...en,
+  "app.meta.description": "OpenCode - L'agent de code open source.",
   "nav.github": "GitHub",
   "nav.docs": "Documentation",
   "nav.changelog": "Changelog",
@@ -15,6 +16,7 @@ export const dict = {
   "nav.home": "Accueil",
   "nav.openMenu": "Ouvrir le menu",
   "nav.getStartedFree": "Commencer gratuitement",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Copier le logo en SVG",
   "nav.context.copyWordmark": "Copier le logotype en SVG",
@@ -42,6 +44,8 @@ export const dict = {
   "notFound.docs": "Documentation",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo light",
+  "notFound.logoDarkAlt": "opencode logo dark",
 
   "user.logout": "Se déconnecter",
 
@@ -75,6 +79,7 @@ export const dict = {
   "error.modelRequired": "Le modèle est requis",
   "error.reloadAmountMin": "Le montant de recharge doit être d'au moins {{amount}} $",
   "error.reloadTriggerMin": "Le seuil de déclenchement doit être d'au moins {{amount}} $",
+  "auth.callback.error.codeMissing": "Aucun code d'autorisation trouvé.",
 
   "home.title": "OpenCode | L'agent de code IA open source",
 
@@ -91,6 +96,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", y compris les modèles locaux",
   "temp.screenshot.caption": "OpenCode TUI avec le thème tokyonight",
   "temp.screenshot.alt": "OpenCode TUI avec le thème tokyonight",
+  "temp.logoLightAlt": "opencode logo light",
+  "temp.logoDarkAlt": "opencode logo dark",
 
   "home.banner.badge": "Nouveau",
   "home.banner.text": "Application desktop disponible en bêta",
@@ -246,6 +253,24 @@ export const dict = {
     "Tous les modèles Zen sont hébergés aux États-Unis. Les fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour l'entraînement des modèles, avec les",
   "zen.privacy.exceptionsLink": "exceptions suivantes",
 
+  "zen.api.error.rateLimitExceeded": "Limite de débit dépassée. Veuillez réessayer plus tard.",
+  "zen.api.error.modelNotSupported": "Modèle {{model}} non pris en charge",
+  "zen.api.error.modelFormatNotSupported": "Modèle {{model}} non pris en charge pour le format {{format}}",
+  "zen.api.error.noProviderAvailable": "Aucun fournisseur disponible",
+  "zen.api.error.providerNotSupported": "Fournisseur {{provider}} non pris en charge",
+  "zen.api.error.missingApiKey": "Clé API manquante.",
+  "zen.api.error.invalidApiKey": "Clé API invalide.",
+  "zen.api.error.subscriptionQuotaExceeded": "Quota d'abonnement dépassé. Réessayez dans {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Quota d'abonnement dépassé. Vous pouvez continuer à utiliser les modèles gratuits.",
+  "zen.api.error.noPaymentMethod": "Aucune méthode de paiement. Ajoutez une méthode de paiement ici : {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Solde insuffisant. Gérez votre facturation ici : {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Votre espace de travail a atteint sa limite de dépense mensuelle de {{amount}} $. Gérez vos limites ici : {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Vous avez atteint votre limite de dépense mensuelle de {{amount}} $. Gérez vos limites ici : {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Le modèle est désactivé",
+
   "black.meta.title": "OpenCode Black | Accédez aux meilleurs modèles de code au monde",
   "black.meta.description": "Accédez à Claude, GPT, Gemini et plus avec les forfaits d'abonnement OpenCode Black.",
   "black.hero.title": "Accédez aux meilleurs modèles de code au monde",
@@ -457,6 +482,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Veuillez mettre à jour votre méthode de paiement et réessayer.",
   "workspace.reload.retrying": "Nouvelle tentative...",
   "workspace.reload.retry": "Réessayer",
+  "workspace.reload.error.paymentFailed": "Échec du paiement.",
 
   "workspace.payments.title": "Historique des paiements",
   "workspace.payments.subtitle": "Transactions de paiement récentes.",
@@ -581,6 +607,10 @@ export const dict = {
   "enterprise.form.send": "Envoyer",
   "enterprise.form.sending": "Envoi...",
   "enterprise.form.success": "Message envoyé, nous vous contacterons bientôt.",
+  "enterprise.form.success.submitted": "Formulaire soumis avec succès.",
+  "enterprise.form.error.allFieldsRequired": "Tous les champs sont requis.",
+  "enterprise.form.error.invalidEmailFormat": "Format d'e-mail invalide.",
+  "enterprise.form.error.internalServer": "Erreur interne du serveur.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Qu'est-ce que OpenCode Enterprise ?",
   "enterprise.faq.a1":
@@ -640,4 +670,5 @@ export const dict = {
   "bench.detail.table.duration": "Durée",
   "bench.detail.run.title": "Exécution {{n}}",
   "bench.detail.rawJson": "JSON brut",
+  "bench.submission.error.allFieldsRequired": "Tous les champs sont requis.",
 } satisfies Dict

+ 33 - 0
packages/console/app/src/i18n/it.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Home",
   "nav.openMenu": "Apri menu",
   "nav.getStartedFree": "Inizia gratis",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Copia il logo come SVG",
   "nav.context.copyWordmark": "Copia il wordmark come SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Documentazione",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "logo chiaro di opencode",
+  "notFound.logoDarkAlt": "logo scuro di opencode",
 
   "user.logout": "Esci",
 
+  "auth.callback.error.codeMissing": "Nessun codice di autorizzazione trovato.",
+
   "workspace.select": "Seleziona workspace",
   "workspace.createNew": "+ Crea nuovo workspace",
   "workspace.modal.title": "Crea nuovo workspace",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "L'importo della ricarica deve essere almeno ${{amount}}",
   "error.reloadTriggerMin": "La soglia del saldo deve essere almeno ${{amount}}",
 
+  "app.meta.description": "OpenCode - L'agente di programmazione open source.",
+
   "home.title": "OpenCode | L'agente di coding IA open source",
 
   "temp.title": "opencode | Agente di coding IA costruito per il terminale",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", inclusi modelli locali",
   "temp.screenshot.caption": "OpenCode TUI con il tema tokyonight",
   "temp.screenshot.alt": "OpenCode TUI con tema tokyonight",
+  "temp.logoLightAlt": "logo chiaro di opencode",
+  "temp.logoDarkAlt": "logo scuro di opencode",
 
   "home.banner.badge": "Nuovo",
   "home.banner.text": "App desktop disponibile in beta",
@@ -240,6 +249,24 @@ export const dict = {
     "Tutti i modelli Zen sono ospitati negli Stati Uniti. I provider seguono una policy di zero-retention e non usano i tuoi dati per l'addestramento dei modelli, con le",
   "zen.privacy.exceptionsLink": "seguenti eccezioni",
 
+  "zen.api.error.rateLimitExceeded": "Limite di richieste superato. Riprova più tardi.",
+  "zen.api.error.modelNotSupported": "Modello {{model}} non supportato",
+  "zen.api.error.modelFormatNotSupported": "Modello {{model}} non supportato per il formato {{format}}",
+  "zen.api.error.noProviderAvailable": "Nessun provider disponibile",
+  "zen.api.error.providerNotSupported": "Provider {{provider}} non supportato",
+  "zen.api.error.missingApiKey": "Chiave API mancante.",
+  "zen.api.error.invalidApiKey": "Chiave API non valida.",
+  "zen.api.error.subscriptionQuotaExceeded": "Quota dell'abbonamento superata. Riprova tra {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Quota dell'abbonamento superata. Puoi continuare a utilizzare modelli gratuiti.",
+  "zen.api.error.noPaymentMethod": "Nessun metodo di pagamento. Aggiungi un metodo di pagamento qui: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Saldo insufficiente. Gestisci la tua fatturazione qui: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "La tua area di lavoro ha raggiunto il limite di spesa mensile di ${{amount}}. Gestisci i tuoi limiti qui: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Hai raggiunto il tuo limite di spesa mensile di ${{amount}}. Gestisci i tuoi limiti qui: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Il modello è disabilitato",
+
   "black.meta.title": "OpenCode Black | Accedi ai migliori modelli di coding al mondo",
   "black.meta.description":
     "Ottieni l'accesso a Claude, GPT, Gemini e altri con i piani di abbonamento OpenCode Black.",
@@ -451,6 +478,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Aggiorna il tuo metodo di pagamento e riprova.",
   "workspace.reload.retrying": "Riprovo...",
   "workspace.reload.retry": "Riprova",
+  "workspace.reload.error.paymentFailed": "Pagamento fallito.",
 
   "workspace.payments.title": "Cronologia Pagamenti",
   "workspace.payments.subtitle": "Transazioni di pagamento recenti.",
@@ -569,6 +597,10 @@ export const dict = {
   "enterprise.form.send": "Invia",
   "enterprise.form.sending": "Invio...",
   "enterprise.form.success": "Messaggio inviato, ti contatteremo presto.",
+  "enterprise.form.success.submitted": "Modulo inviato con successo.",
+  "enterprise.form.error.allFieldsRequired": "Tutti i campi sono obbligatori.",
+  "enterprise.form.error.invalidEmailFormat": "Formato email non valido.",
+  "enterprise.form.error.internalServer": "Errore interno del server.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Cos'è OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -601,6 +633,7 @@ export const dict = {
   "bench.list.table.agent": "Agente",
   "bench.list.table.model": "Modello",
   "bench.list.table.score": "Punteggio",
+  "bench.submission.error.allFieldsRequired": "Tutti i campi sono obbligatori.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Task non trovato",

+ 34 - 0
packages/console/app/src/i18n/ja.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "ホーム",
   "nav.openMenu": "メニューを開く",
   "nav.getStartedFree": "無料ではじめる",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "ロゴをSVGでコピー",
   "nav.context.copyWordmark": "ワードマークをSVGでコピー",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "ドキュメント",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencodeのロゴ(ライト)",
+  "notFound.logoDarkAlt": "opencodeのロゴ(ダーク)",
 
   "user.logout": "ログアウト",
 
+  "auth.callback.error.codeMissing": "認証コードが見つかりません。",
+
   "workspace.select": "ワークスペースを選択",
   "workspace.createNew": "+ 新しいワークスペースを作成",
   "workspace.modal.title": "新しいワークスペースを作成",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "リロード額は少なくとも ${{amount}} である必要があります",
   "error.reloadTriggerMin": "残高トリガーは少なくとも ${{amount}} である必要があります",
 
+  "app.meta.description": "OpenCode - オープンソースのコーディングエージェント。",
+
   "home.title": "OpenCode | オープンソースのAIコーディングエージェント",
 
   "temp.title": "OpenCode | ターミナル向けに構築されたAIコーディングエージェント",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": "を通じて75以上のLLMプロバイダーをサポート",
   "temp.screenshot.caption": "tokyonight テーマを使用した OpenCode TUI",
   "temp.screenshot.alt": "tokyonight テーマの OpenCode TUI",
+  "temp.logoLightAlt": "opencodeのロゴ(ライト)",
+  "temp.logoDarkAlt": "opencodeのロゴ(ダーク)",
 
   "home.banner.badge": "新着",
   "home.banner.text": "デスクトップアプリのベータ版が利用可能",
@@ -239,6 +248,25 @@ export const dict = {
     "すべてのZenモデルは米国でホストされています。プロバイダーはゼロ保持ポリシーに従い、モデルのトレーニングにデータを使用しません(",
   "zen.privacy.exceptionsLink": "以下の例外",
 
+  "zen.api.error.rateLimitExceeded": "レート制限を超えました。後でもう一度お試しください。",
+  "zen.api.error.modelNotSupported": "モデル {{model}} はサポートされていません",
+  "zen.api.error.modelFormatNotSupported": "フォーマット {{format}} ではモデル {{model}} はサポートされていません",
+  "zen.api.error.noProviderAvailable": "利用可能なプロバイダーがありません",
+  "zen.api.error.providerNotSupported": "プロバイダー {{provider}} はサポートされていません",
+  "zen.api.error.missingApiKey": "APIキーがありません。",
+  "zen.api.error.invalidApiKey": "無効なAPIキーです。",
+  "zen.api.error.subscriptionQuotaExceeded":
+    "サブスクリプションの制限を超えました。{{retryIn}} 後に再試行してください。",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "サブスクリプションの制限を超えました。無料モデルは引き続きご利用いただけます。",
+  "zen.api.error.noPaymentMethod": "お支払い方法がありません。こちらからお支払い方法を追加してください: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "残高が不足しています。こちらから請求を管理してください: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "ワークスペースが月額の利用上限 ${{amount}} に達しました。こちらから上限を管理してください: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "月額の利用上限 ${{amount}} に達しました。こちらから上限を管理してください: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "モデルが無効です",
+
   "black.meta.title": "OpenCode Black | 世界最高峰のコーディングモデルすべてにアクセス",
   "black.meta.description": "OpenCode Black サブスクリプションプランで、Claude、GPT、Gemini などにアクセス。",
   "black.hero.title": "世界最高峰のコーディングモデルすべてにアクセス",
@@ -448,6 +476,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "支払い方法を更新して、もう一度お試しください。",
   "workspace.reload.retrying": "再試行中...",
   "workspace.reload.retry": "再試行",
+  "workspace.reload.error.paymentFailed": "支払いに失敗しました。",
 
   "workspace.payments.title": "支払い履歴",
   "workspace.payments.subtitle": "最近の支払い取引。",
@@ -568,6 +597,10 @@ export const dict = {
   "enterprise.form.send": "送信",
   "enterprise.form.sending": "送信中...",
   "enterprise.form.success": "送信しました。まもなくご連絡いたします。",
+  "enterprise.form.success.submitted": "フォームが正常に送信されました。",
+  "enterprise.form.error.allFieldsRequired": "すべての項目は必須です。",
+  "enterprise.form.error.invalidEmailFormat": "無効なメール形式です。",
+  "enterprise.form.error.internalServer": "内部サーバーエラー。",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "OpenCode Enterpriseとは?",
   "enterprise.faq.a1":
@@ -600,6 +633,7 @@ export const dict = {
   "bench.list.table.agent": "エージェント",
   "bench.list.table.model": "モデル",
   "bench.list.table.score": "スコア",
+  "bench.submission.error.allFieldsRequired": "すべての項目は必須です。",
 
   "bench.detail.title": "ベンチマーク - {{task}}",
   "bench.detail.notFound": "タスクが見つかりません",

+ 33 - 0
packages/console/app/src/i18n/ko.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "홈",
   "nav.openMenu": "메뉴 열기",
   "nav.getStartedFree": "무료로 시작하기",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "로고를 SVG로 복사",
   "nav.context.copyWordmark": "워드마크를 SVG로 복사",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "문서",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode 밝은 로고",
+  "notFound.logoDarkAlt": "opencode 어두운 로고",
 
   "user.logout": "로그아웃",
 
+  "auth.callback.error.codeMissing": "인증 코드를 찾을 수 없습니다.",
+
   "workspace.select": "워크스페이스 선택",
   "workspace.createNew": "+ 새 워크스페이스 만들기",
   "workspace.modal.title": "새 워크스페이스 만들기",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "충전 금액은 최소 ${{amount}}이어야 합니다",
   "error.reloadTriggerMin": "잔액 트리거는 최소 ${{amount}}이어야 합니다",
 
+  "app.meta.description": "OpenCode - 오픈 소스 코딩 에이전트.",
+
   "home.title": "OpenCode | 오픈 소스 AI 코딩 에이전트",
 
   "temp.title": "OpenCode | 터미널을 위해 만들어진 AI 코딩 에이전트",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": "를 통해 75개 이상의 LLM 제공자 지원",
   "temp.screenshot.caption": "tokyonight 테마가 적용된 OpenCode TUI",
   "temp.screenshot.alt": "tokyonight 테마가 적용된 OpenCode TUI",
+  "temp.logoLightAlt": "opencode 밝은 로고",
+  "temp.logoDarkAlt": "opencode 어두운 로고",
 
   "home.banner.badge": "신규",
   "home.banner.text": "데스크톱 앱 베타 버전 출시",
@@ -236,6 +245,24 @@ export const dict = {
     "모든 Zen 모델은 미국에서 호스팅됩니다. 제공자들은 데이터 보존 금지 정책을 따르며 모델 학습에 데이터를 사용하지 않습니다. 단,",
   "zen.privacy.exceptionsLink": "다음 예외",
 
+  "zen.api.error.rateLimitExceeded": "속도 제한을 초과했습니다. 나중에 다시 시도해 주세요.",
+  "zen.api.error.modelNotSupported": "{{model}} 모델은 지원되지 않습니다",
+  "zen.api.error.modelFormatNotSupported": "{{model}} 모델은 {{format}} 형식에 대해 지원되지 않습니다",
+  "zen.api.error.noProviderAvailable": "사용 가능한 제공자가 없습니다",
+  "zen.api.error.providerNotSupported": "{{provider}} 제공자는 지원되지 않습니다",
+  "zen.api.error.missingApiKey": "API 키가 누락되었습니다.",
+  "zen.api.error.invalidApiKey": "유효하지 않은 API 키입니다.",
+  "zen.api.error.subscriptionQuotaExceeded": "구독 할당량을 초과했습니다. {{retryIn}} 후 다시 시도해 주세요.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "구독 할당량을 초과했습니다. 무료 모델은 계속 사용할 수 있습니다.",
+  "zen.api.error.noPaymentMethod": "결제 수단이 없습니다. 결제 수단을 추가하세요: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "잔액이 부족합니다. 결제 관리를 여기서 하세요: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "워크스페이스의 월간 지출 한도인 ${{amount}}에 도달했습니다. 한도 관리를 여기서 하세요: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "월간 지출 한도인 ${{amount}}에 도달했습니다. 한도 관리를 여기서 하세요: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "모델이 비활성화되었습니다",
+
   "black.meta.title": "OpenCode Black | 세계 최고의 코딩 모델에 액세스하세요",
   "black.meta.description": "OpenCode Black 구독 플랜으로 Claude, GPT, Gemini 등에 액세스하세요.",
   "black.hero.title": "세계 최고의 코딩 모델에 액세스하세요",
@@ -445,6 +472,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "결제 수단을 업데이트하고 다시 시도해 주세요.",
   "workspace.reload.retrying": "재시도 중...",
   "workspace.reload.retry": "재시도",
+  "workspace.reload.error.paymentFailed": "결제에 실패했습니다.",
 
   "workspace.payments.title": "결제 내역",
   "workspace.payments.subtitle": "최근 결제 거래 내역입니다.",
@@ -562,6 +590,10 @@ export const dict = {
   "enterprise.form.send": "전송",
   "enterprise.form.sending": "전송 중...",
   "enterprise.form.success": "메시지가 전송되었습니다. 곧 연락드리겠습니다.",
+  "enterprise.form.success.submitted": "양식이 성공적으로 제출되었습니다.",
+  "enterprise.form.error.allFieldsRequired": "모든 필드는 필수 항목입니다.",
+  "enterprise.form.error.invalidEmailFormat": "유효하지 않은 이메일 형식입니다.",
+  "enterprise.form.error.internalServer": "내부 서버 오류입니다.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "OpenCode 엔터프라이즈란 무엇인가요?",
   "enterprise.faq.a1":
@@ -594,6 +626,7 @@ export const dict = {
   "bench.list.table.agent": "에이전트",
   "bench.list.table.model": "모델",
   "bench.list.table.score": "점수",
+  "bench.submission.error.allFieldsRequired": "모든 필드는 필수 항목입니다.",
 
   "bench.detail.title": "벤치마크 - {{task}}",
   "bench.detail.notFound": "태스크를 찾을 수 없음",

+ 33 - 0
packages/console/app/src/i18n/no.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Hjem",
   "nav.openMenu": "Åpne meny",
   "nav.getStartedFree": "Kom i gang gratis",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Kopier logo som SVG",
   "nav.context.copyWordmark": "Kopier wordmark som SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Dokumentasjon",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo lys",
+  "notFound.logoDarkAlt": "opencode logo mørk",
 
   "user.logout": "Logg ut",
 
+  "auth.callback.error.codeMissing": "Ingen autorisasjonskode funnet.",
+
   "workspace.select": "Velg arbeidsområde",
   "workspace.createNew": "+ Opprett nytt arbeidsområde",
   "workspace.modal.title": "Opprett nytt arbeidsområde",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "Påfyllingsbeløp må være minst ${{amount}}",
   "error.reloadTriggerMin": "Saldo-trigger må være minst ${{amount}}",
 
+  "app.meta.description": "OpenCode - Den åpne kildekode kodingsagenten.",
+
   "home.title": "OpenCode | Den åpne kildekode AI-kodingsagenten",
 
   "temp.title": "opencode | AI-kodingsagent bygget for terminalen",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", inkludert lokale modeller",
   "temp.screenshot.caption": "opencode TUI med tokyonight-tema",
   "temp.screenshot.alt": "opencode TUI med tokyonight-tema",
+  "temp.logoLightAlt": "opencode logo lys",
+  "temp.logoDarkAlt": "opencode logo mørk",
 
   "home.banner.badge": "Ny",
   "home.banner.text": "Desktop-app tilgjengelig i beta",
@@ -240,6 +249,24 @@ export const dict = {
     "Alle Zen-modeller hostes i USA. Leverandører følger en policy om null oppbevaring og bruker ikke dataene dine til modelltrening, med",
   "zen.privacy.exceptionsLink": "følgende unntak",
 
+  "zen.api.error.rateLimitExceeded": "Rate limit overskredet. Vennligst prøv igjen senere.",
+  "zen.api.error.modelNotSupported": "Modell {{model}} støttes ikke",
+  "zen.api.error.modelFormatNotSupported": "Modell {{model}} støttes ikke for format {{format}}",
+  "zen.api.error.noProviderAvailable": "Ingen leverandør tilgjengelig",
+  "zen.api.error.providerNotSupported": "Leverandør {{provider}} støttes ikke",
+  "zen.api.error.missingApiKey": "Mangler API-nøkkel.",
+  "zen.api.error.invalidApiKey": "Ugyldig API-nøkkel.",
+  "zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igjen om {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Abonnementskvote overskredet. Du kan fortsette å bruke gratis modeller.",
+  "zen.api.error.noPaymentMethod": "Ingen betalingsmetode. Legg til en betalingsmetode her: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Utilstrekkelig saldo. Administrer faktureringen din her: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Arbeidsområdet ditt har nådd sin månedlige utgiftsgrense på ${{amount}}. Administrer grensene dine her: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Du har nådd din månedlige utgiftsgrense på ${{amount}}. Administrer grensene dine her: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Modellen er deaktivert",
+
   "black.meta.title": "OpenCode Black | Få tilgang til verdens beste kodemodeller",
   "black.meta.description": "Få tilgang til Claude, GPT, Gemini og mer med OpenCode Black-abonnementer.",
   "black.hero.title": "Få tilgang til verdens beste kodemodeller",
@@ -449,6 +476,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Vennligst oppdater betalingsmetoden din og prøv på nytt.",
   "workspace.reload.retrying": "Prøver på nytt...",
   "workspace.reload.retry": "Prøv på nytt",
+  "workspace.reload.error.paymentFailed": "Betaling mislyktes.",
 
   "workspace.payments.title": "Betalingshistorikk",
   "workspace.payments.subtitle": "Nylige betalingstransaksjoner.",
@@ -567,6 +595,10 @@ export const dict = {
   "enterprise.form.send": "Send",
   "enterprise.form.sending": "Sender...",
   "enterprise.form.success": "Melding sendt, vi tar kontakt snart.",
+  "enterprise.form.success.submitted": "Skjemaet ble sendt inn.",
+  "enterprise.form.error.allFieldsRequired": "Alle felt er obligatoriske.",
+  "enterprise.form.error.invalidEmailFormat": "Ugyldig e-postformat.",
+  "enterprise.form.error.internalServer": "Intern serverfeil.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Hva er OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -599,6 +631,7 @@ export const dict = {
   "bench.list.table.agent": "Agent",
   "bench.list.table.model": "Modell",
   "bench.list.table.score": "Poengsum",
+  "bench.submission.error.allFieldsRequired": "Alle felt er obligatoriske.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Oppgave ikke funnet",

+ 33 - 0
packages/console/app/src/i18n/pl.ts

@@ -14,6 +14,7 @@ export const dict = {
   "nav.home": "Strona główna",
   "nav.openMenu": "Otwórz menu",
   "nav.getStartedFree": "Zacznij za darmo",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Skopiuj logo jako SVG",
   "nav.context.copyWordmark": "Skopiuj logotyp jako SVG",
@@ -41,9 +42,13 @@ export const dict = {
   "notFound.docs": "Dokumentacja",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "jasne logo opencode",
+  "notFound.logoDarkAlt": "ciemne logo opencode",
 
   "user.logout": "Wyloguj się",
 
+  "auth.callback.error.codeMissing": "Nie znaleziono kodu autoryzacji.",
+
   "workspace.select": "Wybierz obszar roboczy",
   "workspace.createNew": "+ Utwórz nowy obszar roboczy",
   "workspace.modal.title": "Utwórz nowy obszar roboczy",
@@ -75,6 +80,8 @@ export const dict = {
   "error.reloadAmountMin": "Kwota doładowania musi wynosić co najmniej ${{amount}}",
   "error.reloadTriggerMin": "Próg salda musi wynosić co najmniej ${{amount}}",
 
+  "app.meta.description": "OpenCode - Otwartoźródłowy agent programistyczny.",
+
   "home.title": "OpenCode | Open source'owy agent AI do kodowania",
 
   "temp.title": "opencode | Agent AI do kodowania zbudowany dla terminala",
@@ -90,6 +97,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", w tym modele lokalne",
   "temp.screenshot.caption": "OpenCode TUI z motywem tokyonight",
   "temp.screenshot.alt": "OpenCode TUI z motywem tokyonight",
+  "temp.logoLightAlt": "jasne logo opencode",
+  "temp.logoDarkAlt": "ciemne logo opencode",
 
   "home.banner.badge": "Nowość",
   "home.banner.text": "Aplikacja desktopowa dostępna w wersji beta",
@@ -241,6 +250,24 @@ export const dict = {
     "Wszystkie modele Zen są hostowane w USA. Dostawcy stosują politykę zerowej retencji i nie wykorzystują Twoich danych do trenowania modeli, z",
   "zen.privacy.exceptionsLink": "następującymi wyjątkami",
 
+  "zen.api.error.rateLimitExceeded": "Przekroczono limit zapytań. Spróbuj ponownie później.",
+  "zen.api.error.modelNotSupported": "Model {{model}} nie jest obsługiwany",
+  "zen.api.error.modelFormatNotSupported": "Model {{model}} nie jest obsługiwany dla formatu {{format}}",
+  "zen.api.error.noProviderAvailable": "Brak dostępnego dostawcy",
+  "zen.api.error.providerNotSupported": "Dostawca {{provider}} nie jest obsługiwany",
+  "zen.api.error.missingApiKey": "Brak klucza API.",
+  "zen.api.error.invalidApiKey": "Nieprawidłowy klucz API.",
+  "zen.api.error.subscriptionQuotaExceeded": "Przekroczono limit subskrypcji. Spróbuj ponownie za {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Przekroczono limit subskrypcji. Możesz kontynuować korzystanie z darmowych modeli.",
+  "zen.api.error.noPaymentMethod": "Brak metody płatności. Dodaj metodę płatności tutaj: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Niewystarczające saldo. Zarządzaj swoimi płatnościami tutaj: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Twoja przestrzeń robocza osiągnęła miesięczny limit wydatków w wysokości ${{amount}}. Zarządzaj swoimi limitami tutaj: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Osiągnąłeś swój miesięczny limit wydatków w wysokości ${{amount}}. Zarządzaj swoimi limitami tutaj: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Model jest wyłączony",
+
   "black.meta.title": "OpenCode Black | Dostęp do najlepszych na świecie modeli kodujących",
   "black.meta.description": "Uzyskaj dostęp do Claude, GPT, Gemini i innych dzięki planom subskrypcji OpenCode Black.",
   "black.hero.title": "Dostęp do najlepszych na świecie modeli kodujących",
@@ -450,6 +477,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Zaktualizuj metodę płatności i spróbuj ponownie.",
   "workspace.reload.retrying": "Ponawianie...",
   "workspace.reload.retry": "Spróbuj ponownie",
+  "workspace.reload.error.paymentFailed": "Płatność nie powiodła się.",
 
   "workspace.payments.title": "Historia płatności",
   "workspace.payments.subtitle": "Ostatnie transakcje płatnicze.",
@@ -570,6 +598,10 @@ export const dict = {
   "enterprise.form.send": "Wyślij",
   "enterprise.form.sending": "Wysyłanie...",
   "enterprise.form.success": "Wiadomość wysłana, skontaktujemy się wkrótce.",
+  "enterprise.form.success.submitted": "Formularz został pomyślnie wysłany.",
+  "enterprise.form.error.allFieldsRequired": "Wszystkie pola są wymagane.",
+  "enterprise.form.error.invalidEmailFormat": "Nieprawidłowy format adresu e-mail.",
+  "enterprise.form.error.internalServer": "Wewnętrzny błąd serwera.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Czym jest OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -602,6 +634,7 @@ export const dict = {
   "bench.list.table.agent": "Agent",
   "bench.list.table.model": "Model",
   "bench.list.table.score": "Wynik",
+  "bench.submission.error.allFieldsRequired": "Wszystkie pola są wymagane.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Nie znaleziono zadania",

+ 33 - 0
packages/console/app/src/i18n/ru.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Главная",
   "nav.openMenu": "Открыть меню",
   "nav.getStartedFree": "Начать бесплатно",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Скопировать логотип как SVG",
   "nav.context.copyWordmark": "Скопировать название как SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Документация",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "светлый логотип opencode",
+  "notFound.logoDarkAlt": "темный логотип opencode",
 
   "user.logout": "Выйти",
 
+  "auth.callback.error.codeMissing": "Код авторизации не найден.",
+
   "workspace.select": "Выбрать рабочее пространство",
   "workspace.createNew": "+ Создать рабочее пространство",
   "workspace.modal.title": "Создать рабочее пространство",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "Сумма пополнения должна быть не менее ${{amount}}",
   "error.reloadTriggerMin": "Порог баланса должен быть не менее ${{amount}}",
 
+  "app.meta.description": "OpenCode - AI-агент с открытым кодом для программирования.",
+
   "home.title": "OpenCode | AI-агент с открытым кодом для программирования",
 
   "temp.title": "opencode | AI-агент для программирования в терминале",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ", включая локальные модели",
   "temp.screenshot.caption": "OpenCode TUI с темой tokyonight",
   "temp.screenshot.alt": "OpenCode TUI с темой tokyonight",
+  "temp.logoLightAlt": "светлый логотип opencode",
+  "temp.logoDarkAlt": "темный логотип opencode",
 
   "home.banner.badge": "Новое",
   "home.banner.text": "Доступно десктопное приложение (бета)",
@@ -244,6 +253,24 @@ export const dict = {
     "Все модели Zen размещены в США. Провайдеры следуют политике нулевого хранения и не используют ваши данные для обучения моделей, за",
   "zen.privacy.exceptionsLink": "следующими исключениями",
 
+  "zen.api.error.rateLimitExceeded": "Превышен лимит запросов. Пожалуйста, попробуйте позже.",
+  "zen.api.error.modelNotSupported": "Модель {{model}} не поддерживается",
+  "zen.api.error.modelFormatNotSupported": "Модель {{model}} не поддерживается для формата {{format}}",
+  "zen.api.error.noProviderAvailable": "Нет доступных провайдеров",
+  "zen.api.error.providerNotSupported": "Провайдер {{provider}} не поддерживается",
+  "zen.api.error.missingApiKey": "Отсутствует API ключ.",
+  "zen.api.error.invalidApiKey": "Неверный API ключ.",
+  "zen.api.error.subscriptionQuotaExceeded": "Квота подписки превышена. Повторите попытку через {{retryIn}}.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Квота подписки превышена. Вы можете продолжить использовать бесплатные модели.",
+  "zen.api.error.noPaymentMethod": "Нет способа оплаты. Добавьте способ оплаты здесь: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Недостаточно средств. Управляйте оплатой здесь: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Ваше рабочее пространство достигло ежемесячного лимита расходов в ${{amount}}. Управляйте лимитами здесь: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Вы достигли ежемесячного лимита расходов в ${{amount}}. Управляйте лимитами здесь: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Модель отключена",
+
   "black.meta.title": "OpenCode Black | Доступ к лучшим моделям для кодинга в мире",
   "black.meta.description": "Получите доступ к Claude, GPT, Gemini и другим моделям с подпиской OpenCode Black.",
   "black.hero.title": "Доступ к лучшим моделям для кодинга в мире",
@@ -455,6 +482,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Пожалуйста, обновите способ оплаты и попробуйте снова.",
   "workspace.reload.retrying": "Повторная попытка...",
   "workspace.reload.retry": "Повторить",
+  "workspace.reload.error.paymentFailed": "Ошибка оплаты.",
 
   "workspace.payments.title": "История платежей",
   "workspace.payments.subtitle": "Недавние транзакции.",
@@ -574,6 +602,10 @@ export const dict = {
   "enterprise.form.send": "Отправить",
   "enterprise.form.sending": "Отправка...",
   "enterprise.form.success": "Сообщение отправлено, мы скоро свяжемся с вами.",
+  "enterprise.form.success.submitted": "Форма успешно отправлена.",
+  "enterprise.form.error.allFieldsRequired": "Все поля обязательны.",
+  "enterprise.form.error.invalidEmailFormat": "Неверный формат email.",
+  "enterprise.form.error.internalServer": "Внутренняя ошибка сервера.",
   "enterprise.faq.title": "FAQ",
   "enterprise.faq.q1": "Что такое OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -606,6 +638,7 @@ export const dict = {
   "bench.list.table.agent": "Агент",
   "bench.list.table.model": "Модель",
   "bench.list.table.score": "Оценка",
+  "bench.submission.error.allFieldsRequired": "Все поля обязательны.",
 
   "bench.detail.title": "Бенчмарк - {{task}}",
   "bench.detail.notFound": "Задача не найдена",

+ 33 - 0
packages/console/app/src/i18n/th.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "หน้าหลัก",
   "nav.openMenu": "เปิดเมนู",
   "nav.getStartedFree": "เริ่มต้นฟรี",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "คัดลอกโลโก้เป็น SVG",
   "nav.context.copyWordmark": "คัดลอกตัวอักษรแบรนด์เป็น SVG",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "เอกสาร",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "โลโก้ opencode แบบสว่าง",
+  "notFound.logoDarkAlt": "โลโก้ opencode แบบมืด",
 
   "user.logout": "ออกจากระบบ",
 
+  "auth.callback.error.codeMissing": "ไม่พบ authorization code",
+
   "workspace.select": "เลือก Workspace",
   "workspace.createNew": "+ สร้าง Workspace ใหม่",
   "workspace.modal.title": "สร้าง Workspace ใหม่",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "จำนวนเงินที่โหลดซ้ำต้องมีอย่างน้อย ${{amount}}",
   "error.reloadTriggerMin": "ยอดคงเหลือที่กระตุ้นต้องมีอย่างน้อย ${{amount}}",
 
+  "app.meta.description": "OpenCode - เอเจนต์เขียนโค้ดแบบโอเพนซอร์ส",
+
   "home.title": "OpenCode | เอเจนต์เขียนโค้ดด้วย AI แบบโอเพนซอร์ส",
 
   "temp.title": "OpenCode | เอเจนต์เขียนโค้ด AI ที่สร้างมาเพื่อเทอร์มินัล",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": "รวมถึงโมเดล Local",
   "temp.screenshot.caption": "OpenCode TUI พร้อมธีม tokyonight",
   "temp.screenshot.alt": "OpenCode TUI พร้อมธีม tokyonight",
+  "temp.logoLightAlt": "โลโก้ opencode แบบสว่าง",
+  "temp.logoDarkAlt": "โลโก้ opencode แบบมืด",
 
   "home.banner.badge": "ใหม่",
   "home.banner.text": "แอปเดสก์ท็อปพร้อมใช้งานในเวอร์ชันเบต้า",
@@ -239,6 +248,24 @@ export const dict = {
     "โมเดล Zen ทั้งหมดโฮสต์ในสหรัฐอเมริกา ผู้ให้บริการปฏิบัติตามนโยบายไม่เก็บรักษาข้อมูล (zero-retention policy) และไม่ใช้ข้อมูลของคุณสำหรับการฝึกโมเดล โดยมี",
   "zen.privacy.exceptionsLink": "ข้อยกเว้นดังนี้",
 
+  "zen.api.error.rateLimitExceeded": "เกินขีดจำกัดอัตราการใช้งาน กรุณาลองใหม่ในภายหลัง",
+  "zen.api.error.modelNotSupported": "ไม่รองรับโมเดล {{model}}",
+  "zen.api.error.modelFormatNotSupported": "ไม่รองรับโมเดล {{model}} สำหรับรูปแบบ {{format}}",
+  "zen.api.error.noProviderAvailable": "ไม่มีผู้ให้บริการที่พร้อมใช้งาน",
+  "zen.api.error.providerNotSupported": "ไม่รองรับผู้ให้บริการ {{provider}}",
+  "zen.api.error.missingApiKey": "ไม่มี API key",
+  "zen.api.error.invalidApiKey": "API key ไม่ถูกต้อง",
+  "zen.api.error.subscriptionQuotaExceeded": "โควต้าการสมัครสมาชิกเกินขีดจำกัด ลองใหม่ในอีก {{retryIn}}",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "โควต้าการสมัครสมาชิกเกินขีดจำกัด คุณสามารถดำเนินการต่อโดยใช้โมเดลฟรี",
+  "zen.api.error.noPaymentMethod": "ไม่มีวิธีการชำระเงิน เพิ่มวิธีการชำระเงินที่นี่: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "ยอดเงินคงเหลือไม่เพียงพอ จัดการการเรียกเก็บเงินของคุณที่นี่: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Workspace ของคุณถึงขีดจำกัดการใช้จ่ายรายเดือนที่ ${{amount}} แล้ว จัดการขีดจำกัดของคุณที่นี่: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "คุณถึงขีดจำกัดการใช้จ่ายรายเดือนที่ ${{amount}} แล้ว จัดการขีดจำกัดของคุณที่นี่: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "โมเดลถูกปิดใช้งาน",
+
   "black.meta.title": "OpenCode Black | เข้าถึงโมเดลเขียนโค้ดที่ดีที่สุดในโลก",
   "black.meta.description": "เข้าถึง Claude, GPT, Gemini และอื่นๆ ด้วยแผนสมาชิก OpenCode Black",
   "black.hero.title": "เข้าถึงโมเดลเขียนโค้ดที่ดีที่สุดในโลก",
@@ -448,6 +475,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "โปรดอัปเดตวิธีการชำระเงินของคุณแล้วลองอีกครั้ง",
   "workspace.reload.retrying": "กำลังลองอีกครั้ง...",
   "workspace.reload.retry": "ลองอีกครั้ง",
+  "workspace.reload.error.paymentFailed": "การชำระเงินล้มเหลว",
 
   "workspace.payments.title": "ประวัติการชำระเงิน",
   "workspace.payments.subtitle": "รายการธุรกรรมการชำระเงินล่าสุด",
@@ -566,6 +594,10 @@ export const dict = {
   "enterprise.form.send": "ส่ง",
   "enterprise.form.sending": "กำลังส่ง...",
   "enterprise.form.success": "ส่งข้อความแล้ว เราจะติดต่อกลับเร็วๆ นี้",
+  "enterprise.form.success.submitted": "ส่งแบบฟอร์มสำเร็จแล้ว",
+  "enterprise.form.error.allFieldsRequired": "จำเป็นต้องกรอกทุกช่อง",
+  "enterprise.form.error.invalidEmailFormat": "รูปแบบอีเมลไม่ถูกต้อง",
+  "enterprise.form.error.internalServer": "เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์",
   "enterprise.faq.title": "คำถามที่พบบ่อย",
   "enterprise.faq.q1": "OpenCode Enterprise คืออะไร?",
   "enterprise.faq.a1":
@@ -598,6 +630,7 @@ export const dict = {
   "bench.list.table.agent": "เอเจนต์",
   "bench.list.table.model": "โมเดล",
   "bench.list.table.score": "คะแนน",
+  "bench.submission.error.allFieldsRequired": "จำเป็นต้องกรอกทุกช่อง",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "ไม่พบงาน",

+ 33 - 0
packages/console/app/src/i18n/tr.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "Ana sayfa",
   "nav.openMenu": "Menüyü aç",
   "nav.getStartedFree": "Ücretsiz başla",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "Logoyu SVG olarak kopyala",
   "nav.context.copyWordmark": "Wordmark'ı SVG olarak kopyala",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "Dokümantasyon",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode açık logo",
+  "notFound.logoDarkAlt": "opencode koyu logo",
 
   "user.logout": "Çıkış",
 
+  "auth.callback.error.codeMissing": "Yetkilendirme kodu bulunamadı.",
+
   "workspace.select": "Çalışma alanı seç",
   "workspace.createNew": "+ Yeni çalışma alanı oluştur",
   "workspace.modal.title": "Yeni çalışma alanı oluştur",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "Yükleme tutarı en az ${{amount}} olmalıdır",
   "error.reloadTriggerMin": "Bakiye tetikleyicisi en az ${{amount}} olmalıdır",
 
+  "app.meta.description": "OpenCode - Açık kaynaklı kodlama ajanı.",
+
   "home.title": "OpenCode | Açık kaynaklı yapay zeka kodlama ajanı",
 
   "temp.title": "opencode | Terminal için geliştirilmiş yapay zeka kodlama ajanı",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": " üzerinden destekler",
   "temp.screenshot.caption": "opencode TUI ve tokyonight teması",
   "temp.screenshot.alt": "tokyonight temalı opencode TUI",
+  "temp.logoLightAlt": "opencode açık logo",
+  "temp.logoDarkAlt": "opencode koyu logo",
 
   "home.banner.badge": "Yeni",
   "home.banner.text": "Masaüstü uygulaması beta olarak kullanılabilir",
@@ -242,6 +251,24 @@ export const dict = {
     "Tüm Zen modelleri ABD'de barındırılmaktadır. Sağlayıcılar sıfır saklama politikası izler ve verilerinizi model eğitimi için kullanmaz; şu",
   "zen.privacy.exceptionsLink": "aşağıdaki istisnalar",
 
+  "zen.api.error.rateLimitExceeded": "İstek limiti aşıldı. Lütfen daha sonra tekrar deneyin.",
+  "zen.api.error.modelNotSupported": "{{model}} modeli desteklenmiyor",
+  "zen.api.error.modelFormatNotSupported": "{{model}} modeli {{format}} formatı için desteklenmiyor",
+  "zen.api.error.noProviderAvailable": "Kullanılabilir sağlayıcı yok",
+  "zen.api.error.providerNotSupported": "{{provider}} sağlayıcısı desteklenmiyor",
+  "zen.api.error.missingApiKey": "API anahtarı eksik.",
+  "zen.api.error.invalidApiKey": "Geçersiz API anahtarı.",
+  "zen.api.error.subscriptionQuotaExceeded": "Abonelik kotası aşıldı. {{retryIn}} içinde tekrar deneyin.",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels":
+    "Abonelik kotası aşıldı. Ücretsiz modelleri kullanmaya devam edebilirsiniz.",
+  "zen.api.error.noPaymentMethod": "Ödeme yöntemi bulunamadı. Buradan bir ödeme yöntemi ekleyin: {{billingUrl}}",
+  "zen.api.error.insufficientBalance": "Yetersiz bakiye. Faturalandırmanızı buradan yönetin: {{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "Çalışma alanınız aylık ${{amount}} harcama limitine ulaştı. Limitlerinizi buradan yönetin: {{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached":
+    "Aylık ${{amount}} harcama limitinize ulaştınız. Limitlerinizi buradan yönetin: {{membersUrl}}",
+  "zen.api.error.modelDisabled": "Model devre dışı",
+
   "black.meta.title": "OpenCode Black | Dünyanın en iyi kodlama modellerine erişin",
   "black.meta.description": "OpenCode Black abonelik planlarıyla Claude, GPT, Gemini ve daha fazlasına erişin.",
   "black.hero.title": "Dünyanın en iyi kodlama modellerine erişin",
@@ -451,6 +478,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "Lütfen ödeme yönteminizi güncelleyin ve tekrar deneyin.",
   "workspace.reload.retrying": "Yeniden deneniyor...",
   "workspace.reload.retry": "Yeniden dene",
+  "workspace.reload.error.paymentFailed": "Ödeme başarısız.",
 
   "workspace.payments.title": "Ödeme Geçmişi",
   "workspace.payments.subtitle": "Son ödeme işlemleri.",
@@ -571,6 +599,10 @@ export const dict = {
   "enterprise.form.send": "Gönder",
   "enterprise.form.sending": "Gönderiliyor...",
   "enterprise.form.success": "Mesaj gönderildi, yakında size dönüş yapacağız.",
+  "enterprise.form.success.submitted": "Form başarıyla gönderildi.",
+  "enterprise.form.error.allFieldsRequired": "Tüm alanlar gereklidir.",
+  "enterprise.form.error.invalidEmailFormat": "Geçersiz e-posta formatı.",
+  "enterprise.form.error.internalServer": "İç sunucu hatası.",
   "enterprise.faq.title": "SSS",
   "enterprise.faq.q1": "OpenCode Enterprise nedir?",
   "enterprise.faq.a1":
@@ -603,6 +635,7 @@ export const dict = {
   "bench.list.table.agent": "Ajan",
   "bench.list.table.model": "Model",
   "bench.list.table.score": "Puan",
+  "bench.submission.error.allFieldsRequired": "Tüm alanlar gereklidir.",
 
   "bench.detail.title": "Benchmark - {{task}}",
   "bench.detail.notFound": "Görev bulunamadı",

+ 31 - 0
packages/console/app/src/i18n/zh.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "首页",
   "nav.openMenu": "打开菜单",
   "nav.getStartedFree": "免费开始",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "复制 Logo (SVG)",
   "nav.context.copyWordmark": "复制商标 (SVG)",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "文档",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode logo 亮色",
+  "notFound.logoDarkAlt": "opencode logo 暗色",
 
   "user.logout": "退出登录",
 
+  "auth.callback.error.codeMissing": "未找到授权码。",
+
   "workspace.select": "选择工作区",
   "workspace.createNew": "+ 新建工作区",
   "workspace.modal.title": "新建工作区",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "充值金额必须至少为 ${{amount}}",
   "error.reloadTriggerMin": "余额触发阈值必须至少为 ${{amount}}",
 
+  "app.meta.description": "OpenCode - 开源编程代理。",
+
   "home.title": "OpenCode | 开源 AI 编程代理",
 
   "temp.title": "OpenCode | 专为终端打造的 AI 编程代理",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": ",包括本地模型",
   "temp.screenshot.caption": "使用 Tokyonight 主题的 OpenCode TUI",
   "temp.screenshot.alt": "使用 Tokyonight 主题的 OpenCode TUI",
+  "temp.logoLightAlt": "opencode logo 亮色",
+  "temp.logoDarkAlt": "opencode logo 暗色",
 
   "home.banner.badge": "新",
   "home.banner.text": "桌面应用 Beta 版现已推出",
@@ -229,6 +238,22 @@ export const dict = {
   "zen.privacy.beforeExceptions": "所有 Zen 模型均托管在美国。提供商遵循零留存政策,不使用您的数据进行模型训练,",
   "zen.privacy.exceptionsLink": "以下例外情况除外",
 
+  "zen.api.error.rateLimitExceeded": "超出速率限制。请稍后重试。",
+  "zen.api.error.modelNotSupported": "不支持模型 {{model}}",
+  "zen.api.error.modelFormatNotSupported": "格式 {{format}} 不支持模型 {{model}}",
+  "zen.api.error.noProviderAvailable": "没有可用的提供商",
+  "zen.api.error.providerNotSupported": "不支持提供商 {{provider}}",
+  "zen.api.error.missingApiKey": "缺少 API 密钥。",
+  "zen.api.error.invalidApiKey": "无效的 API 密钥。",
+  "zen.api.error.subscriptionQuotaExceeded": "超出订阅配额。请在 {{retryIn}} 后重试。",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels": "超出订阅配额。您可以继续使用免费模型。",
+  "zen.api.error.noPaymentMethod": "没有付款方式。请在此处添加付款方式:{{billingUrl}}",
+  "zen.api.error.insufficientBalance": "余额不足。请在此处管理您的计费:{{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "您的工作区已达到每月支出限额 ${{amount}}。请在此处管理您的限额:{{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached": "您已达到每月支出限额 ${{amount}}。请在此处管理您的限额:{{membersUrl}}",
+  "zen.api.error.modelDisabled": "模型已禁用",
+
   "black.meta.title": "OpenCode Black | 访问全球顶尖编程模型",
   "black.meta.description": "通过 OpenCode Black 订阅计划使用 Claude, GPT, Gemini 等模型。",
   "black.hero.title": "访问全球顶尖编程模型",
@@ -436,6 +461,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "请更新您的付款方式并重试。",
   "workspace.reload.retrying": "正在重试...",
   "workspace.reload.retry": "重试",
+  "workspace.reload.error.paymentFailed": "支付失败。",
 
   "workspace.payments.title": "支付历史",
   "workspace.payments.subtitle": "近期支付交易。",
@@ -552,6 +578,10 @@ export const dict = {
   "enterprise.form.send": "发送",
   "enterprise.form.sending": "正在发送...",
   "enterprise.form.success": "消息已发送,我们会尽快与您联系。",
+  "enterprise.form.success.submitted": "表单提交成功。",
+  "enterprise.form.error.allFieldsRequired": "所有字段均为必填项。",
+  "enterprise.form.error.invalidEmailFormat": "邮箱格式无效。",
+  "enterprise.form.error.internalServer": "内部服务器错误。",
   "enterprise.faq.title": "常见问题",
   "enterprise.faq.q1": "什么是 OpenCode 企业版?",
   "enterprise.faq.a1":
@@ -584,6 +614,7 @@ export const dict = {
   "bench.list.table.agent": "代理",
   "bench.list.table.model": "模型",
   "bench.list.table.score": "分数",
+  "bench.submission.error.allFieldsRequired": "所有字段均为必填项。",
 
   "bench.detail.title": "基准测试 - {{task}}",
   "bench.detail.notFound": "未找到任务",

+ 31 - 0
packages/console/app/src/i18n/zht.ts

@@ -15,6 +15,7 @@ export const dict = {
   "nav.home": "首頁",
   "nav.openMenu": "開啟選單",
   "nav.getStartedFree": "免費開始使用",
+  "nav.logoAlt": "OpenCode",
 
   "nav.context.copyLogo": "複製標誌(SVG)",
   "nav.context.copyWordmark": "複製字標(SVG)",
@@ -42,9 +43,13 @@ export const dict = {
   "notFound.docs": "文件",
   "notFound.github": "GitHub",
   "notFound.discord": "Discord",
+  "notFound.logoLightAlt": "opencode 淺色標誌",
+  "notFound.logoDarkAlt": "opencode 深色標誌",
 
   "user.logout": "登出",
 
+  "auth.callback.error.codeMissing": "找不到授權碼。",
+
   "workspace.select": "選取工作區",
   "workspace.createNew": "+ 建立新工作區",
   "workspace.modal.title": "建立新工作區",
@@ -76,6 +81,8 @@ export const dict = {
   "error.reloadAmountMin": "儲值金額必須至少為 ${{amount}}",
   "error.reloadTriggerMin": "餘額觸發門檻必須至少為 ${{amount}}",
 
+  "app.meta.description": "OpenCode - 開源編碼代理。",
+
   "home.title": "OpenCode | 開源 AI 編碼代理",
 
   "temp.title": "OpenCode | 專為終端打造的 AI 編碼代理",
@@ -91,6 +98,8 @@ export const dict = {
   "temp.feature.models.afterLink": "支援 75+ 家 LLM 供應商,包括本地模型",
   "temp.screenshot.caption": "使用 tokyonight 主題的 OpenCode TUI",
   "temp.screenshot.alt": "使用 tokyonight 主題的 OpenCode TUI",
+  "temp.logoLightAlt": "opencode 淺色標誌",
+  "temp.logoDarkAlt": "opencode 深色標誌",
 
   "home.banner.badge": "新",
   "home.banner.text": "桌面應用已推出 Beta",
@@ -229,6 +238,22 @@ export const dict = {
   "zen.privacy.beforeExceptions": "所有 Zen 模型均在美國託管。供應商遵循零留存政策,不會將你的資料用於模型訓練,並且有",
   "zen.privacy.exceptionsLink": "以下例外情況",
 
+  "zen.api.error.rateLimitExceeded": "超出頻率限制。請稍後再試。",
+  "zen.api.error.modelNotSupported": "不支援模型 {{model}}",
+  "zen.api.error.modelFormatNotSupported": "模型 {{model}} 不支援格式 {{format}}",
+  "zen.api.error.noProviderAvailable": "無可用的供應商",
+  "zen.api.error.providerNotSupported": "不支援供應商 {{provider}}",
+  "zen.api.error.missingApiKey": "缺少 API 金鑰。",
+  "zen.api.error.invalidApiKey": "無效的 API 金鑰。",
+  "zen.api.error.subscriptionQuotaExceeded": "超出訂閱配額。請在 {{retryIn}} 後重試。",
+  "zen.api.error.subscriptionQuotaExceededUseFreeModels": "超出訂閱配額。你可以繼續使用免費模型。",
+  "zen.api.error.noPaymentMethod": "無付款方式。請在此處新增付款方式:{{billingUrl}}",
+  "zen.api.error.insufficientBalance": "餘額不足。請在此處管理你的帳務:{{billingUrl}}",
+  "zen.api.error.workspaceMonthlyLimitReached":
+    "你的工作區已達到每月支出限額 ${{amount}}。請在此處管理你的限額:{{billingUrl}}",
+  "zen.api.error.userMonthlyLimitReached": "你已達到每月支出限額 ${{amount}}。請在此處管理你的限額:{{membersUrl}}",
+  "zen.api.error.modelDisabled": "模型已停用",
+
   "black.meta.title": "OpenCode Black | 存取全球最佳編碼模型",
   "black.meta.description": "透過 OpenCode Black 訂閱方案存取 Claude、GPT、Gemini 等模型。",
   "black.hero.title": "存取全球最佳編碼模型",
@@ -436,6 +461,7 @@ export const dict = {
   "workspace.reload.updatePaymentMethod": "請更新你的付款方式並重試。",
   "workspace.reload.retrying": "重試中...",
   "workspace.reload.retry": "重試",
+  "workspace.reload.error.paymentFailed": "付款失敗。",
 
   "workspace.payments.title": "付款紀錄",
   "workspace.payments.subtitle": "最近的付款交易。",
@@ -551,6 +577,10 @@ export const dict = {
   "enterprise.form.send": "傳送",
   "enterprise.form.sending": "傳送中...",
   "enterprise.form.success": "訊息已傳送,我們會盡快與你聯絡。",
+  "enterprise.form.success.submitted": "表單已成功送出。",
+  "enterprise.form.error.allFieldsRequired": "所有欄位均為必填。",
+  "enterprise.form.error.invalidEmailFormat": "無效的電子郵件格式。",
+  "enterprise.form.error.internalServer": "內部伺服器錯誤。",
   "enterprise.faq.title": "常見問題",
   "enterprise.faq.q1": "什麼是 OpenCode Enterprise?",
   "enterprise.faq.a1":
@@ -583,6 +613,7 @@ export const dict = {
   "bench.list.table.agent": "代理",
   "bench.list.table.model": "模型",
   "bench.list.table.score": "分數",
+  "bench.submission.error.allFieldsRequired": "所有欄位均為必填。",
 
   "bench.detail.title": "評測 - {{task}}",
   "bench.detail.notFound": "找不到任務",

+ 3 - 0
packages/console/app/src/lib/form-error.ts

@@ -48,6 +48,9 @@ const map = {
   "Provider is required": "error.providerRequired",
   "API key is required": "error.apiKeyRequired",
   "Model is required": "error.modelRequired",
+  "workspace.reload.error.paymentFailed": "workspace.reload.error.paymentFailed",
+  "Payment failed": "workspace.reload.error.paymentFailed",
+  "Payment failed.": "workspace.reload.error.paymentFailed",
 } as const satisfies Record<string, Key>
 
 export function formErrorReloadAmountMin(amount: number) {

+ 2 - 2
packages/console/app/src/routes/[...404].tsx

@@ -16,8 +16,8 @@ export default function NotFound() {
       <div data-component="content">
         <section data-component="top">
           <a href={language.route("/")} data-slot="logo-link">
-            <img data-slot="logo light" src={logoLight} alt="opencode logo light" />
-            <img data-slot="logo dark" src={logoDark} alt="opencode logo dark" />
+            <img data-slot="logo light" src={logoLight} alt={i18n.t("notFound.logoLightAlt")} />
+            <img data-slot="logo dark" src={logoDark} alt={i18n.t("notFound.logoDarkAlt")} />
           </a>
           <h1 data-slot="title">{i18n.t("notFound.heading")}</h1>
         </section>

+ 7 - 4
packages/console/app/src/routes/api/enterprise.ts

@@ -1,5 +1,7 @@
 import type { APIEvent } from "@solidjs/start/server"
 import { AWS } from "@opencode-ai/console-core/aws.js"
+import { i18n } from "~/i18n"
+import { localeFromRequest } from "~/lib/language"
 
 interface EnterpriseFormData {
   name: string
@@ -9,18 +11,19 @@ interface EnterpriseFormData {
 }
 
 export async function POST(event: APIEvent) {
+  const dict = i18n(localeFromRequest(event.request))
   try {
     const body = (await event.request.json()) as EnterpriseFormData
 
     // Validate required fields
     if (!body.name || !body.role || !body.email || !body.message) {
-      return Response.json({ error: "All fields are required" }, { status: 400 })
+      return Response.json({ error: dict["enterprise.form.error.allFieldsRequired"] }, { status: 400 })
     }
 
     // Validate email format
     const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
     if (!emailRegex.test(body.email)) {
-      return Response.json({ error: "Invalid email format" }, { status: 400 })
+      return Response.json({ error: dict["enterprise.form.error.invalidEmailFormat"] }, { status: 400 })
     }
 
     // Create email content
@@ -39,9 +42,9 @@ ${body.email}`.trim()
       replyTo: body.email,
     })
 
-    return Response.json({ success: true, message: "Form submitted successfully" }, { status: 200 })
+    return Response.json({ success: true, message: dict["enterprise.form.success.submitted"] }, { status: 200 })
   } catch (error) {
     console.error("Error processing enterprise form:", error)
-    return Response.json({ error: "Internal server error" }, { status: 500 })
+    return Response.json({ error: dict["enterprise.form.error.internalServer"] }, { status: 500 })
   }
 }

+ 3 - 1
packages/console/app/src/routes/auth/[...callback].ts

@@ -2,15 +2,17 @@ import { redirect } from "@solidjs/router"
 import type { APIEvent } from "@solidjs/start/server"
 import { AuthClient } from "~/context/auth"
 import { useAuthSession } from "~/context/auth"
+import { i18n } from "~/i18n"
 import { localeFromRequest, route } from "~/lib/language"
 
 export async function GET(input: APIEvent) {
   const url = new URL(input.request.url)
   const locale = localeFromRequest(input.request)
+  const dict = i18n(locale)
 
   try {
     const code = url.searchParams.get("code")
-    if (!code) throw new Error("No code found")
+    if (!code) throw new Error(dict["auth.callback.error.codeMissing"])
     const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`)
     if (result.err) throw new Error(result.err.message)
     const decoded = AuthClient.decode(result.tokens.access, {} as any)

+ 4 - 1
packages/console/app/src/routes/bench/submission.ts

@@ -2,6 +2,8 @@ import type { APIEvent } from "@solidjs/start/server"
 import { Database } from "@opencode-ai/console-core/drizzle/index.js"
 import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js"
 import { Identifier } from "@opencode-ai/console-core/identifier.js"
+import { i18n } from "~/i18n"
+import { localeFromRequest } from "~/lib/language"
 
 interface SubmissionBody {
   model: string
@@ -10,10 +12,11 @@ interface SubmissionBody {
 }
 
 export async function POST(event: APIEvent) {
+  const dict = i18n(localeFromRequest(event.request))
   const body = (await event.request.json()) as SubmissionBody
 
   if (!body.model || !body.agent || !body.result) {
-    return Response.json({ error: "All fields are required" }, { status: 400 })
+    return Response.json({ error: dict["bench.submission.error.allFieldsRequired"] }, { status: 400 })
   }
 
   await Database.use((tx) =>

+ 9 - 8
packages/console/app/src/routes/brand/index.tsx

@@ -33,6 +33,7 @@ const brandAssets = "/opencode-brand-assets.zip"
 
 export default function Brand() {
   const i18n = useI18n()
+  const alt = i18n.t("brand.meta.description")
   const downloadFile = async (url: string, filename: string) => {
     try {
       const response = await fetch(url)
@@ -88,7 +89,7 @@ export default function Brand() {
 
             <div data-component="brand-grid">
               <div>
-                <img src={previewLogoLight} alt="OpenCode brand guidelines" />
+                <img src={previewLogoLight} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(logoLightPng, "opencode-logo-light.png")}>
                     PNG
@@ -115,7 +116,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewLogoDark} alt="OpenCode brand guidelines" />
+                <img src={previewLogoDark} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(logoDarkPng, "opencode-logo-dark.png")}>
                     PNG
@@ -142,7 +143,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewLogoLightSquare} alt="OpenCode brand guidelines" />
+                <img src={previewLogoLightSquare} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(logoLightSquarePng, "opencode-logo-light-square.png")}>
                     PNG
@@ -169,7 +170,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewLogoDarkSquare} alt="OpenCode brand guidelines" />
+                <img src={previewLogoDarkSquare} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(logoDarkSquarePng, "opencode-logo-dark-square.png")}>
                     PNG
@@ -196,7 +197,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewWordmarkLight} alt="OpenCode brand guidelines" />
+                <img src={previewWordmarkLight} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(wordmarkLightPng, "opencode-wordmark-light.png")}>
                     PNG
@@ -223,7 +224,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewWordmarkDark} alt="OpenCode brand guidelines" />
+                <img src={previewWordmarkDark} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(wordmarkDarkPng, "opencode-wordmark-dark.png")}>
                     PNG
@@ -250,7 +251,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewWordmarkSimpleLight} alt="OpenCode brand guidelines" />
+                <img src={previewWordmarkSimpleLight} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(wordmarkSimpleLightPng, "opencode-wordmark-simple-light.png")}>
                     PNG
@@ -277,7 +278,7 @@ export default function Brand() {
                 </div>
               </div>
               <div>
-                <img src={previewWordmarkSimpleDark} alt="OpenCode brand guidelines" />
+                <img src={previewWordmarkSimpleDark} alt={alt} />
                 <div data-component="actions">
                   <button onClick={() => downloadFile(wordmarkSimpleDarkPng, "opencode-wordmark-simple-dark.png")}>
                     PNG

+ 1 - 1
packages/console/app/src/routes/download/[channel]/[platform].ts

@@ -19,7 +19,7 @@ const downloadNames: Record<string, string> = {
 
 export async function GET({ params: { platform, channel } }: APIEvent) {
   const assetName = assetNames[platform]
-  if (!assetName) return new Response("Not Found", { status: 404 })
+  if (!assetName) return new Response(null, { status: 404 })
 
   const resp = await fetch(
     `https://github.com/anomalyco/${channel === "stable" ? "opencode" : "opencode-beta"}/releases/latest/download/${assetName}`,

+ 1 - 1
packages/console/app/src/routes/stripe/webhook.ts

@@ -306,7 +306,7 @@ export async function POST(input: APIEvent) {
               .update(BillingTable)
               .set({
                 reload: false,
-                reloadError: errorMessage ?? "Payment failed.",
+                reloadError: errorMessage ?? "workspace.reload.error.paymentFailed",
                 timeReloadError: sql`now()`,
               })
               .where(eq(BillingTable.workspaceID, Actor.workspace())),

+ 2 - 2
packages/console/app/src/routes/temp.tsx

@@ -47,8 +47,8 @@ export default function Home() {
 
       <div data-component="content">
         <section data-component="top">
-          <img data-slot="logo light" src={logoLight} alt="opencode logo light" />
-          <img data-slot="logo dark" src={logoDark} alt="opencode logo dark" />
+          <img data-slot="logo light" src={logoLight} alt={i18n.t("temp.logoLightAlt")} />
+          <img data-slot="logo dark" src={logoDark} alt={i18n.t("temp.logoDarkAlt")} />
           <h1 data-slot="title">{i18n.t("temp.hero.title")}</h1>
           <div data-slot="login">
             <a href="/auth">{i18n.t("temp.zen")}</a>

+ 2 - 1
packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx

@@ -12,6 +12,7 @@ import { queryBillingInfo } from "../../common"
 import styles from "./lite-section.module.css"
 import { useI18n } from "~/context/i18n"
 import { useLanguage } from "~/context/language"
+import { formError } from "~/lib/form-error"
 
 const queryLiteSubscription = query(async (workspaceID: string) => {
   "use server"
@@ -114,7 +115,7 @@ const createSessionUrl = action(async (workspaceID: string, returnUrl: string) =
 const setLiteUseBalance = action(async (form: FormData) => {
   "use server"
   const workspaceID = form.get("workspaceID")?.toString()
-  if (!workspaceID) return { error: "Workspace ID is required" }
+  if (!workspaceID) return { error: formError.workspaceRequired }
   const useBalance = form.get("useBalance")?.toString() === "true"
 
   return json(

+ 2 - 1
packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx

@@ -202,7 +202,8 @@ export function ReloadSection() {
                 minute: "2-digit",
                 second: "2-digit",
               })}
-              . {i18n.t("workspace.reload.reason")} {billingInfo()?.reloadError?.replace(/\.$/, "")}.{" "}
+              . {i18n.t("workspace.reload.reason")}{" "}
+              {localizeError(i18n.t, billingInfo()?.reloadError ?? undefined).replace(/\.$/, "")}.{" "}
               {i18n.t("workspace.reload.updatePaymentMethod")}
             </p>
             <form action={reload} method="post" data-slot="create-form">

+ 50 - 24
packages/console/app/src/routes/zen/util/handler.ts

@@ -35,6 +35,8 @@ import { createTrialLimiter } from "./trialLimiter"
 import { createStickyTracker } from "./stickyProviderTracker"
 import { LiteData } from "@opencode-ai/console-core/lite.js"
 import { Resource } from "@opencode-ai/console-resource"
+import { i18n, type Key } from "~/i18n"
+import { localeFromRequest } from "~/lib/language"
 
 type ZenData = Awaited<ReturnType<typeof ZenData.list>>
 type RetryOptions = {
@@ -43,6 +45,15 @@ type RetryOptions = {
 }
 type BillingSource = "anonymous" | "free" | "byok" | "subscription" | "lite" | "balance"
 
+function resolve(text: string, params?: Record<string, string | number>) {
+  if (!params) return text
+  return text.replace(/\{\{(\w+)\}\}/g, (raw, key) => {
+    const value = params[key]
+    if (value === undefined || value === null) return raw
+    return String(value)
+  })
+}
+
 export async function handler(
   input: APIEvent,
   opts: {
@@ -60,6 +71,8 @@ export async function handler(
 
   const MAX_FAILOVER_RETRIES = 3
   const MAX_429_RETRIES = 3
+  const dict = i18n(localeFromRequest(input.request))
+  const t = (key: Key, params?: Record<string, string | number>) => resolve(dict[key], params)
   const ADMIN_WORKSPACES = [
     "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
     "wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench
@@ -86,7 +99,7 @@ export async function handler(
     const dataDumper = createDataDumper(sessionId, requestId, projectId)
     const trialLimiter = createTrialLimiter(modelInfo.trial, ip, ocClient)
     const isTrial = await trialLimiter?.isTrial()
-    const rateLimiter = createRateLimiter(modelInfo.rateLimit, ip, input.request.headers)
+    const rateLimiter = createRateLimiter(modelInfo.rateLimit, ip, input.request)
     await rateLimiter?.check()
     const stickyTracker = createStickyTracker(modelInfo.stickyProvider, sessionId)
     const stickyProvider = await stickyTracker?.get()
@@ -359,14 +372,20 @@ export async function handler(
   }
 
   function validateModel(zenData: ZenData, reqModel: string) {
-    if (!(reqModel in zenData.models)) throw new ModelError(`Model ${reqModel} not supported`)
+    if (!(reqModel in zenData.models)) throw new ModelError(t("zen.api.error.modelNotSupported", { model: reqModel }))
 
     const modelId = reqModel as keyof typeof zenData.models
     const modelData = Array.isArray(zenData.models[modelId])
       ? zenData.models[modelId].find((model) => opts.format === model.formatFilter)
       : zenData.models[modelId]
 
-    if (!modelData) throw new ModelError(`Model ${reqModel} not supported for format ${opts.format}`)
+    if (!modelData)
+      throw new ModelError(
+        t("zen.api.error.modelFormatNotSupported", {
+          model: reqModel,
+          format: opts.format,
+        }),
+      )
 
     logger.metric({ model: modelId })
 
@@ -418,8 +437,9 @@ export async function handler(
       return modelInfo.providers.find((provider) => provider.id === modelInfo.fallbackProvider)
     })()
 
-    if (!modelProvider) throw new ModelError("No provider available")
-    if (!(modelProvider.id in zenData.providers)) throw new ModelError(`Provider ${modelProvider.id} not supported`)
+    if (!modelProvider) throw new ModelError(t("zen.api.error.noProviderAvailable"))
+    if (!(modelProvider.id in zenData.providers))
+      throw new ModelError(t("zen.api.error.providerNotSupported", { provider: modelProvider.id }))
 
     return {
       ...modelProvider,
@@ -439,7 +459,7 @@ export async function handler(
     const apiKey = opts.parseApiKey(input.request.headers)
     if (!apiKey || apiKey === "public") {
       if (modelInfo.allowAnonymous) return
-      throw new AuthError("Missing API key.")
+      throw new AuthError(t("zen.api.error.missingApiKey"))
     }
 
     const data = await Database.use((tx) =>
@@ -520,13 +540,13 @@ export async function handler(
         .then((rows) => rows[0]),
     )
 
-    if (!data) throw new AuthError("Invalid API key.")
+    if (!data) throw new AuthError(t("zen.api.error.invalidApiKey"))
     if (
       modelInfo.id.startsWith("alpha-") &&
       Resource.App.stage === "production" &&
       !ADMIN_WORKSPACES.includes(data.workspaceID)
     )
-      throw new AuthError(`Model ${modelInfo.id} not supported`)
+      throw new AuthError(t("zen.api.error.modelNotSupported", { model: modelInfo.id }))
 
     logger.metric({
       api_key: data.apiKey,
@@ -590,7 +610,9 @@ export async function handler(
           })
           if (result.status === "rate-limited")
             throw new SubscriptionUsageLimitError(
-              `Subscription quota exceeded. Retry in ${formatRetryTime(result.resetInSec)}.`,
+              t("zen.api.error.subscriptionQuotaExceeded", {
+                retryIn: formatRetryTime(result.resetInSec),
+              }),
               result.resetInSec,
             )
         }
@@ -606,7 +628,9 @@ export async function handler(
           })
           if (result.status === "rate-limited")
             throw new SubscriptionUsageLimitError(
-              `Subscription quota exceeded. Retry in ${formatRetryTime(result.resetInSec)}.`,
+              t("zen.api.error.subscriptionQuotaExceeded", {
+                retryIn: formatRetryTime(result.resetInSec),
+              }),
               result.resetInSec,
             )
         }
@@ -632,7 +656,7 @@ export async function handler(
           })
           if (result.status === "rate-limited")
             throw new SubscriptionUsageLimitError(
-              `Subscription quota exceeded. You can continue using free models.`,
+              t("zen.api.error.subscriptionQuotaExceededUseFreeModels"),
               result.resetInSec,
             )
         }
@@ -647,7 +671,7 @@ export async function handler(
           })
           if (result.status === "rate-limited")
             throw new SubscriptionUsageLimitError(
-              `Subscription quota exceeded. You can continue using free models.`,
+              t("zen.api.error.subscriptionQuotaExceededUseFreeModels"),
               result.resetInSec,
             )
         }
@@ -662,7 +686,7 @@ export async function handler(
           })
           if (result.status === "rate-limited")
             throw new SubscriptionUsageLimitError(
-              `Subscription quota exceeded. You can continue using free models.`,
+              t("zen.api.error.subscriptionQuotaExceededUseFreeModels"),
               result.resetInSec,
             )
         }
@@ -675,14 +699,10 @@ export async function handler(
 
     // Validate pay as you go billing
     const billing = authInfo.billing
-    if (!billing.paymentMethodID)
-      throw new CreditsError(
-        `No payment method. Add a payment method here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`,
-      )
-    if (billing.balance <= 0)
-      throw new CreditsError(
-        `Insufficient balance. Manage your billing here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`,
-      )
+    const billingUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/billing`
+    const membersUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/members`
+    if (!billing.paymentMethodID) throw new CreditsError(t("zen.api.error.noPaymentMethod", { billingUrl }))
+    if (billing.balance <= 0) throw new CreditsError(t("zen.api.error.insufficientBalance", { billingUrl }))
 
     const now = new Date()
     const currentYear = now.getUTCFullYear()
@@ -696,7 +716,10 @@ export async function handler(
       currentMonth === billing.timeMonthlyUsageUpdated.getUTCMonth()
     )
       throw new MonthlyLimitError(
-        `Your workspace has reached its monthly spending limit of $${billing.monthlyLimit}. Manage your limits here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`,
+        t("zen.api.error.workspaceMonthlyLimitReached", {
+          amount: billing.monthlyLimit,
+          billingUrl,
+        }),
       )
 
     if (
@@ -708,7 +731,10 @@ export async function handler(
       currentMonth === authInfo.user.timeMonthlyUsageUpdated.getUTCMonth()
     )
       throw new UserLimitError(
-        `You have reached your monthly spending limit of $${authInfo.user.monthlyLimit}. Manage your limits here: https://opencode.ai/workspace/${authInfo.workspaceID}/members`,
+        t("zen.api.error.userMonthlyLimitReached", {
+          amount: authInfo.user.monthlyLimit,
+          membersUrl,
+        }),
       )
 
     return "balance"
@@ -716,7 +742,7 @@ export async function handler(
 
   function validateModelSettings(authInfo: AuthInfo) {
     if (!authInfo) return
-    if (authInfo.isDisabled) throw new ModelError("Model is disabled")
+    if (authInfo.isDisabled) throw new ModelError(t("zen.api.error.modelDisabled"))
   }
 
   function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) {

+ 6 - 3
packages/console/app/src/routes/zen/util/rateLimiter.ts

@@ -3,11 +3,14 @@ import { IpRateLimitTable } from "@opencode-ai/console-core/schema/ip.sql.js"
 import { FreeUsageLimitError } from "./error"
 import { logger } from "./logger"
 import { ZenData } from "@opencode-ai/console-core/model.js"
+import { i18n } from "~/i18n"
+import { localeFromRequest } from "~/lib/language"
 
-export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: string, headers: Headers) {
+export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: string, request: Request) {
   if (!limit) return
+  const dict = i18n(localeFromRequest(request))
 
-  const limitValue = limit.checkHeader && !headers.get(limit.checkHeader) ? limit.fallbackValue! : limit.value
+  const limitValue = limit.checkHeader && !request.headers.get(limit.checkHeader) ? limit.fallbackValue! : limit.value
 
   const ip = !rawIp.length ? "unknown" : rawIp
   const now = Date.now()
@@ -36,7 +39,7 @@ export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: s
       logger.debug(`rate limit total: ${total}`)
       if (total >= limitValue)
         throw new FreeUsageLimitError(
-          `Rate limit exceeded. Please try again later.`,
+          dict["zen.api.error.rateLimitExceeded"],
           limit.period === "day" ? getRetryAfterDay(now) : getRetryAfterHour(rows, intervals, limitValue, now),
         )
     },