From 1ea9412f2496010724e1be89a2013395333fc2a8 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 05:51:54 +0000 Subject: [PATCH] feat(i18n): translate the four highest-traffic namespaces into the eight trailing locales (#2872 part a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backfills `console`, `home`, `topbar` and `layout` — 193 keys x 8 packs, 1,544 strings — so a ja/ko/de/fr/es/pt/ru/ar admin sees the AI console, the home screen, the top bar and the system navigation in their own language instead of silently falling back to English. The gap in those eight packs drops from 469-471 keys to 277-279; en and zh stay at exact parity. This is the "high-frequency namespaces only" strategy, not a full backfill: `grid` (101), `gantt` (58), `dashboard` (25) and the long tail stay on English fallback and remain tracked under #2872. Four keys are deliberately NOT translated, and that is the load-bearing part of this change: console.ai.planApproveMessage console.ai.planApproveDefaultsMessage console.ai.planAnswerMessage console.ai.changesConfirmMessage These are not labels — they are text a button TRANSMITS to the agent, and the cloud confirm gate (service-ai-studio confirm-gate.ts APPROVAL_RE) decides whether it reads as approval. It recognises Chinese and English, nothing else. AiChatPage picks them by the language of the CONVERSATION, not the UI, so the t() call is expected to miss in every non-Chinese pack and fall through to its English defaultValue. Translating them would make a German user's "Build it" send German, the gate stop matching, and the agent re-propose instead of building — the button looks inert while nothing visibly errors. #2900 shipped exactly that bug for changesConfirmMessage, which had been added to all ten packs; this removes it from the eight and restores the English fallback. A new guard pins the invariant in both directions and was mutation-tested against re-adding an outbound key and against dropping an ordinary label. Translations are model-generated and would benefit from native review; every string's placeholder set was verified programmatically against the English source. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01TubWYdWquVkS9dj733sDmC --- .changeset/high-frequency-locale-backfill.md | 52 ++++ .../__tests__/outbound-agent-messages.test.ts | 78 ++++++ packages/i18n/src/locales/ar.ts | 242 +++++++++++++++++- packages/i18n/src/locales/de.ts | 242 +++++++++++++++++- packages/i18n/src/locales/es.ts | 242 +++++++++++++++++- packages/i18n/src/locales/fr.ts | 242 +++++++++++++++++- packages/i18n/src/locales/ja.ts | 242 +++++++++++++++++- packages/i18n/src/locales/ko.ts | 242 +++++++++++++++++- packages/i18n/src/locales/pt.ts | 242 +++++++++++++++++- packages/i18n/src/locales/ru.ts | 242 +++++++++++++++++- 10 files changed, 2058 insertions(+), 8 deletions(-) create mode 100644 .changeset/high-frequency-locale-backfill.md create mode 100644 packages/i18n/src/__tests__/outbound-agent-messages.test.ts diff --git a/.changeset/high-frequency-locale-backfill.md b/.changeset/high-frequency-locale-backfill.md new file mode 100644 index 000000000..30ef5b5c7 --- /dev/null +++ b/.changeset/high-frequency-locale-backfill.md @@ -0,0 +1,52 @@ +--- +"@object-ui/i18n": patch +--- + +feat(i18n): translate the four highest-traffic namespaces into the eight trailing locales (objectui#2872 part a) + +Backfills `console`, `home`, `topbar` and `layout` — 193 keys × 8 packs, 1,544 +strings — so a ja/ko/de/fr/es/pt/ru/ar admin sees the AI console, the home +screen, the top bar and the system navigation in their own language instead of +silently falling back to English. + +The gap in those eight packs drops from **469–471 keys to 277–279**. `en` and +`zh` remain at exact parity (2499 : 2499, zero difference in both directions). + +This is the "high-frequency namespaces only" strategy from the objectui#2872 +discussion, not a full backfill: `grid` (101), `gantt` (58), `dashboard` (25) +and the long tail stay on English fallback and remain tracked there. + +**Four keys are deliberately left untranslated**, and that is the load-bearing +part of this change: + +``` +console.ai.planApproveMessage +console.ai.planApproveDefaultsMessage +console.ai.planAnswerMessage +console.ai.changesConfirmMessage +``` + +These are not labels. They are the text a button *transmits to the agent*, and +the cloud confirm gate (`service-ai-studio` `confirm-gate.ts` `APPROVAL_RE`) +decides whether that text reads as approval. It recognises Chinese and English +— nothing else. `AiChatPage` therefore selects them by the language of the +CONVERSATION rather than of the UI, and the `t()` call is *expected* to miss in +every non-Chinese pack and fall through to its English `defaultValue`. + +Translating them would be an outright regression: a German user's "Build it" +would start sending German, the gate would stop matching, and the agent would +re-propose instead of building — the button looks inert while nothing visibly +errors. + +objectui#2900 shipped precisely that bug for `changesConfirmMessage`, which had +been added to all ten packs. **This change removes it from the eight**, +restoring the English fallback. A new guard, +`packages/i18n/src/__tests__/outbound-agent-messages.test.ts`, pins the +invariant in both directions: the four keys must be absent from the eight packs +AND present in `en`/`zh`, while every *other* `console.ai` label must be +translated — so the narrow fix can't be over-applied into an excuse for leaving +surrounding labels in English. + +Translations are model-generated and would benefit from native review; the +placeholder set of every string was verified programmatically against the +English source. diff --git a/packages/i18n/src/__tests__/outbound-agent-messages.test.ts b/packages/i18n/src/__tests__/outbound-agent-messages.test.ts new file mode 100644 index 000000000..f3a5289c9 --- /dev/null +++ b/packages/i18n/src/__tests__/outbound-agent-messages.test.ts @@ -0,0 +1,78 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Guard: the strings the console SENDS to the AI agent must not be translated + * into arbitrary locales. + * + * Most `console.ai.*` keys are labels and should be localized everywhere. Four + * are not labels — they are the message text a button transmits to the agent, + * and the cloud confirm gate (`service-ai-studio` `confirm-gate.ts` + * `APPROVAL_RE`) decides whether that text counts as approval. It recognises + * Chinese and English. Nothing else. + * + * So `AiChatPage` picks them by the language of the CONVERSATION, not the UI: + * + * const planApproveMessage = convZh + * ? '确认,开始搭建。' // matches the gate + * : t('console.ai.planApproveMessage', { defaultValue: … }); + * + * That `t()` call is expected to MISS in every non-Chinese pack and fall + * through to its English `defaultValue`. Add a German translation and a German + * user's "Build it" click starts sending German, the gate stops matching, and + * the agent re-proposes instead of building — the button looks inert while + * nothing visibly errors. objectui#2900 shipped exactly that for + * `changesConfirmMessage`; this test is why it can't happen twice. + * + * If the gate ever learns more languages, delete the offending entry here in + * the same change that teaches it — not before. + */ +import { describe, it, expect } from 'vitest'; +import { en, zh, ja, ko, de, fr, es, pt, ru, ar } from '../locales'; + +const OUTBOUND_KEYS = [ + 'console.ai.planApproveMessage', + 'console.ai.planApproveDefaultsMessage', + 'console.ai.planAnswerMessage', + 'console.ai.changesConfirmMessage', +] as const; + +const GATE_LOCALES: Record = { en, zh }; +const NON_GATE_LOCALES: Record = { ja, ko, de, fr, es, pt, ru, ar }; + +function lookup(pack: unknown, dotted: string): unknown { + return dotted + .split('.') + .reduce((node, part) => (node as Record)?.[part], pack); +} + +describe('outbound agent messages stay on gate-recognised languages', () => { + it.each(Object.keys(NON_GATE_LOCALES))( + 'the %s pack defines none of them, so t() falls through to the English default', + (lang) => { + const offenders = OUTBOUND_KEYS.filter( + (k) => lookup(NON_GATE_LOCALES[lang], k) !== undefined, + ); + expect(offenders).toEqual([]); + }, + ); + + it.each(Object.keys(GATE_LOCALES))('the %s pack defines all of them', (lang) => { + for (const k of OUTBOUND_KEYS) { + expect(typeof lookup(GATE_LOCALES[lang], k)).toBe('string'); + } + }); + + it('every OTHER console.ai key IS localized — this guard is narrow on purpose', () => { + // Guards against over-correcting: the fix for the outbound keys must not + // become a reason to leave the surrounding labels untranslated. + const aiLabels = Object.keys((en as any).console.ai).filter( + (k) => typeof (en as any).console.ai[k] === 'string', + ); + const outboundLeaf = new Set(OUTBOUND_KEYS.map((k) => k.split('.').pop())); + const labels = aiLabels.filter((k) => !outboundLeaf.has(k)); + expect(labels.length).toBeGreaterThan(20); + for (const k of labels) { + expect((de as any).console.ai[k], `de is missing console.ai.${k}`).toBeTypeOf('string'); + } + }); +}); diff --git a/packages/i18n/src/locales/ar.ts b/packages/i18n/src/locales/ar.ts index 304058925..52de220da 100644 --- a/packages/i18n/src/locales/ar.ts +++ b/packages/i18n/src/locales/ar.ts @@ -852,12 +852,185 @@ const ar = { }, }, console: { + settingsHub: { + title: "الإعدادات", + subtitle: "اضبط مساحة العمل والتكاملات وأعلام الميزات.", + loadError: "تعذّر تحميل الإعدادات", + empty: "لا توجد إعدادات مسجّلة. يمكن للإضافات تسجيل بيانات الإعدادات عبر SettingsService.", + settingsCount: "{{n}} من الإعدادات", + beta: "إصدار تجريبي", + categories: { + Workspace: "مساحة العمل", + Communication: "الاتصالات", + Security: "الأمان", + Infrastructure: "البنية التحتية", + Beta: "إصدار تجريبي", + Other: "أخرى", + }, + }, + objectData: { + badge: "البيانات", + description: "شريحة بيانات محددة عبر الرابط — غير مرتبطة بأي عرض محفوظ.", + filteredBy: "مُرشَّح حسب", + removeFilter: "إزالة عامل التصفية {{field}}", + saveAsView: "الحفظ كعرض", + noAccessTitle: "تم رفض الوصول", + noAccess: "ليس لديك إذن لعرض هذه البيانات.", + }, + identityImport: { + policyTitle: "إعداد تسجيل الدخول للمستخدمين المستوردين", + policy: { + auto: "تلقائي (موصى به)", + invite: "إرسال دعوات", + temporary: "كلمات مرور مؤقتة", + none: "بدون كلمة مرور (هوية فقط)", + }, + policyHint: { + auto: "يتلقى المستخدمون الذين يمكن الوصول إليهم دعوة (بريد إلكتروني أو رسالة نصية)؛ ومن يتعذّر الوصول إليه يحصل على كلمة مرور لمرة واحدة تُعرض مرة واحدة فقط في شاشة النتائج. تعمل مع خدمة البريد/الرسائل أو بدونها.", + invite: "يتلقى كل مستخدم يتم إنشاؤه بريدًا لتعيين كلمة المرور (أو رسالة دعوة نصية للصفوف التي تحتوي على هاتف فقط). يتطلب خدمة بريد/رسائل مُهيّأة — وتفشل الصفوف التي يتعذّر الوصول إليها.", + temporary: "للتنصيبات التي لا تتوفر فيها خدمة بريد/رسائل: يحصل كل مستخدم يتم إنشاؤه على كلمة مرور لمرة واحدة تُعرض مرة واحدة فقط في شاشة النتائج. ويفرض تسجيل الدخول الأول تغييرها.", + none: "يسجّل المستخدمون الدخول أولًا برمز لمرة واحدة عبر الهاتف أو برابط سحري أو برابط إعادة تعيين كلمة المرور، ثم يعيّنون كلمة المرور الخاصة بهم.", + }, + passwordsNote: "كلمات مرور مؤقتة — تُعرض مرة واحدة ولا تُخزَّن أبدًا. احفظها الآن؛ وعلى كل مستخدم تغيير كلمته عند أول تسجيل دخول.", + passwordsMore: "تم حذف إدخالات إضافية — استخدم التنزيل.", + passwordsDownload: "تنزيل ملف CSV", + }, ai: { + usage: { + title: "استخدام الذكاء الاصطناعي", + meterBuild: "الإنشاء", + meterAsk: "السؤال", + statusOk: "المتبقّي وفير", + statusLow: "على وشك النفاد", + statusFull: "تم بلوغ الحد", + resetsDaily: "تُعاد التهيئة الليلة", + resetsMonthly: "تُعاد التهيئة في الدورة القادمة", + ctaUpgrade: "قم بالترقية للمتابعة", + ctaTopUp: "أضف أرصدة للمتابعة", + ariaLabel: "استخدام الذكاء الاصطناعي: {{status}}", + }, + workspaceTitle: "مساحة عمل الذكاء الاصطناعي", + workspaceSubtitle: "اسأل وافحص واستأنف المحادثات", + openChats: "فتح المحادثات", + chats: "المحادثات", + chatsDescription: "تصفّح محادثات الذكاء الاصطناعي وأدرها.", + share: "مشاركة", + shareTitle: "مشاركة هذه المحادثة", + shareDisabledTitle: "ابدأ المحادثة لتفعيل المشاركة", + newChat: "جديدة", + searchChats: "البحث في المحادثات...", + noChatsYet: "لا توجد محادثات بعد", + noChatsDescription: "ابدأ محادثة جديدة لتظهر هنا.", + noMatchingChats: "لا توجد محادثات مطابقة.", + newConversation: "محادثة جديدة", + renameConversation: "إعادة تسمية المحادثة", + deleteConversation: "حذف المحادثة", + saveRename: "حفظ الاسم", + cancelRename: "إلغاء إعادة التسمية", + loadingHistory: "جارٍ تحميل سجل المحادثة...", + conversationReady: "المحادثة جاهزة", + preparingConversation: "جارٍ تجهيز محادثة جديدة", + offlineDemoMode: "وضع العرض دون اتصال — قائمة الوكلاء غير متاحة", + sendFailedRateLimited: "أنت ترسل الرسائل بسرعة كبيرة. رسالتك محفوظة بالأسفل — انتظر لحظة ثم أعد المحاولة.", + sendFailedGeneric: "تعذّر إرسال رسالتك. وهي محفوظة بالأسفل — يرجى إعادة المحاولة.", + askAgent: "اسأل {{agent}}...", + assistant: "المساعد", + liveCanvas: "معاينة حية — {{app}} (مسودة)", + liveCanvasUnlisted: "تطبيق حي — {{app}} (غير مُدرج حتى النشر)", + loadingAgents: "جارٍ تحميل الوكلاء...", + askAnything: "اسأل عن أي شيء...", + emptyTitle: "ابدأ محادثة", + emptyDescription: "اسأل عن أي شيء — يمكن للمساعد الاطلاع على سياق تطبيقك الحالي.", + switchAssistant: "تبديل المساعد", + chooseAgent: "اختر مساعدًا…", + empty: { + build: { + title: "الإنشاء بالذكاء الاصطناعي", + description: "صف تطبيقًا أو سير عمل بلغة بسيطة — سأعدّ مسودة الكائنات والشاشات والأتمتة، ثم تراجعها وتنشرها.", + }, + ask: { + title: "اسأل بياناتك", + description: "اطرح أسئلة عن سجلاتك — أعداد وقوائم وملخصات للبيانات التي يمكنك الوصول إليها.", + }, + editApp: { + title: "تحرير «{{app}}»", + titleGeneric: "تحرير هذا التطبيق", + description: "ما الذي تريد تغييره؟ سأعدّل هذا التطبيق في مكانه — إضافة حقل أو كائن أو عرض أو أتمتة، أو تعديل ما هو موجود.", + }, + }, + clearConversation: "مسح", + sendHint: "للإرسال", + agentActivity: "نشاط الوكيل", + toolCompleted: "مكتمل", + toolRunning: "قيد التنفيذ", + toolAwaitingApproval: "بانتظار الموافقة", + toolFailed: "فشل", + toolDetailsHidden: "مدخلات الأدوات والنتائج الخام مخفية في هذا العرض.", + copy: "نسخ", + copied: "تم النسخ", + regenerate: "إعادة التوليد", + model: "النموذج", + submit: "إرسال", + uploadFiles: "رفع الملفات", + stopResponse: "إيقاف الرد", + trace: "التتبّع", + viewTrace: "عرض التتبّع", + nextSteps: "الخطوة التالية", + publishDrafts: "نشر", + publishOk: "تم النشر — الكائنات فعّالة الآن.", + seedWarn: "تم النشر، لكن تعذّر تحميل بعض البيانات التجريبية.", + openBuiltApp: "فتح التطبيق", + designBuiltApp: "التصميم في Studio", + previewDraft: "معاينة", + previewApp: "معاينة التطبيق", + resizeSplit: "تغيير حجم المحادثة والمعاينة", + hideChats: "إخفاء المحادثات", + showChats: "إظهار المحادثات", + planTitle: "الخطة المقترحة", + planQuestions: "التأكيد قبل الإنشاء", + planAssumptions: "الافتراضات", + planApproveHint: "أجب للموافقة على هذه الخطة أو تعديلها.", + planApprove: "ابدأ الإنشاء", + planAdjust: "تعديل", + justNow: "الآن", + minutesAgo: "قبل {{count}} د", + hoursAgo: "قبل {{count}} س", + daysAgo: "قبل {{count}} ي", + agentLabels: { + ask: "السؤال", + build: "الإنشاء", + dataChat: "المساعد", + metadataAssistant: "مساعد البيانات الوصفية", + }, + suggestions: { + dataChat: { + userCount: "كم عدد المستخدمين في النظام؟ اذكر عناوين بريدهم الإلكتروني.", + recentRecords: "اذكر أحدث 5 سجلات تم إنشاؤها.", + recordCounts: "احسب عدد السجلات لكل كائن.", + }, + metadataAssistant: { + buildCrm: "أنشئ نظام إدارة علاقات عملاء للمبيعات — عملاء وجهات اتصال ومسار صفقات يمكنني تجميعه حسب المرحلة.", + buildApp: "أنشئ متتبّع مشاريع — مشاريع ومهام بمسؤولين وتواريخ استحقاق ولوحة حسب الحالة.", + buildFlow: "صمّم مكتب دعم — تذاكر بأولوية وسير عمل للحالات وروابط بالعملاء.", + buildInventory: "أنشئ تطبيق مخزون — منتجات ومستويات مخزون وموردين وتنبيه لانخفاض المخزون.", + buildRecruiting: "أنشئ متتبّع متقدمين — مرشحون ووظائف شاغرة ومراحل مقابلات وملاحظات.", + }, + generic: { + help: "بماذا يمكنك مساعدتي؟", + availableObjects: "اذكر كائنات البيانات المتاحة.", + recentActivity: "لخّص نشاطي الأخير.", + }, + editApp: { + addField: "أضف حقلًا إلى أحد الكائنات.", + addObject: "أضف كائنًا جديدًا واربطه بكائن موجود.", + addDashboard: "أضف لوحة معلومات للمؤشرات الرئيسية.", + addAutomation: "أضف أتمتة — موافقة أو سير حالات أو إشعارًا.", + }, + }, changesTitle: "تأكيد التغييرات", changesConfirmed: "تم التأكيد", changesConfirm: "تأكيد", changesConfirmHint: "أجب لتأكيد هذا التغيير أو تعديله.", - changesConfirmMessage: "تم تأكيد التغييرات — طبّق ما اقترحته للتو.", changeVerb: { createObject: "إنشاء كائن", addField: "إضافة حقل", @@ -913,6 +1086,7 @@ const ar = { toggleDarkMode: "تبديل الوضع الداكن", }, commandPalette: { + title: "لوحة الأوامر", placeholder: "اكتب أمراً أو ابحث...", noResults: "لم يتم العثور على نتائج.", objects: "الكائنات", @@ -946,6 +1120,14 @@ const ar = { system: "النظام", }, objectView: { + viewTypeTree: "شجرة", + viewTypeTreeDesc: "يرتّب السجلات ذاتية المرجعية في تسلسل هرمي عبر حقل أب.", + parentField: "الحقل الأب", + parentFieldHelp: "الحقل الذي يشير إلى السجل الأب (الكائن نفسه) ويحدد التسلسل الهرمي. الحقول ذاتية المرجعية فقط هي المؤهلة.", + viewName: "الاسم", + viewNameHelp: "مفتاح برمجي (snake_case). يُملأ تلقائيًا من العنوان — عدّله إن أردت.", + viewNameRequired: "أدخل مفتاحًا (أحرف إنجليزية صغيرة وأرقام وشرطة سفلية). لا يُملأ تلقائيًا للعناوين غير اللاتينية.", + viewNameInvalid: "استخدم أحرفًا إنجليزية صغيرة وأرقامًا وشرطات سفلية؛ وابدأ بحرف أو شرطة سفلية.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "الكائن غير موجود", @@ -1417,10 +1599,54 @@ const ar = { removeFromFavorites: "إزالة {{name}} من المفضلة", }, topbar: { + openAssistant: "فتح مساعد {{name}}", + offline: "غير متصل", + usersOnline: "المستخدمون المتصلون الآن", + switchView: "تبديل العرض", + switchObject: "تبديل الكائن", + connection: { + connected: "متصل", + connecting: "جارٍ الاتصال...", + reconnecting: "جارٍ إعادة الاتصال...", + disconnected: "منقطع", + error: "خطأ في الاتصال", + }, + stage: { + preview: "معاينة", + beta: "إصدار تجريبي", + tooltip: "هذه المنصة في مرحلة المعاينة — وقد تتغير الميزات.", + }, aiAssistant: "مساعد الذكاء الاصطناعي", designInStudio: "التصميم في Studio", }, home: { + build: { + title: "إنشاء تطبيق", + subtitle: "ابدأ من الصفر — صمّم الكائنات والنماذج والأتمتة والواجهات.", + }, + template: { + title: "ابدأ من قالب", + subtitle: "ثبّت تطبيق قالب من السوق وخصّصه.", + }, + welcomeAdminDescription: "صف نشاطك التجاري في جملة واحدة — وسيولّد الذكاء الاصطناعي الكائنات والشاشات وواجهات البرمجة وأدوات الوكيل. أو أعدّها بنفسك من القائمة على اليسار.", + welcomeAdminDescriptionNoBuild: "أعدّ تطبيقك الأول من قائمة الإدارة على اليسار. وبمجرد توفر البيانات، يمكن لمساعد الذكاء الاصطناعي مساعدتك في استكشافها.", + welcomeAdminDescriptionNoAi: "أعدّ تطبيقك الأول من قائمة الإدارة على اليسار.", + noAppsTitle: "لا توجد تطبيقات بعد", + noAppsDescription: "يجري إعداد مساحة عملك — وستظهر هنا التطبيقات التي يشاركها معك المسؤول.", + buildWithAI: "الإنشاء بالذكاء الاصطناعي", + askAI: "اسأل الذكاء الاصطناعي", + recoveryReminder: { + message: "عيّن كلمة مرور للاسترداد كي تتمكن من تسجيل الدخول إذا تعذّر الدخول الموحّد في أي وقت.", + cta: "تعيين كلمة المرور", + dismiss: "تجاهل", + }, + pendingDrafts: { + message: "لديك {{count}} من التغييرات غير المنشورة — انشرها لتصبح فعّالة.", + cta: "نشر", + publishing: "جارٍ النشر…", + published: "تم النشر! تغييراتك فعّالة الآن.", + publishFailed: "فشل النشر", + }, title: "الرئيسية", subtitle: "لوحة تحكم مساحة العمل", nav: "الرئيسية", @@ -1484,7 +1710,21 @@ const ar = { }, }, layout: { + systemNav: { + systemSettings: "إعدادات النظام", + applications: "التطبيقات", + appMarketplace: "سوق التطبيقات", + objectManager: "مدير الكائنات", + users: "المستخدمون", + organizations: "المؤسسات", + roles: "الأدوار", + configuration: "التهيئة", + createApp: "إنشاء تطبيق", + }, appSwitcher: { + switchApplication: "تبديل التطبيق", + appsAvailable: "{{count}} من التطبيقات المتاحة", + editNavigation: "تحرير التنقل", home: "الرئيسية", addApp: "إضافة تطبيق", editApp: "تعديل التطبيق", diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index a0f927210..c9ae22a99 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -854,12 +854,185 @@ const de = { }, }, console: { + settingsHub: { + title: "Einstellungen", + subtitle: "Konfigurieren Sie Ihren Workspace, Integrationen und Feature-Flags.", + loadError: "Einstellungen konnten nicht geladen werden", + empty: "Keine Einstellungen registriert. Plugins können Einstellungsmanifeste über den SettingsService registrieren.", + settingsCount: "{{n}} Einstellungen", + beta: "Beta", + categories: { + Workspace: "Workspace", + Communication: "Kommunikation", + Security: "Sicherheit", + Infrastructure: "Infrastruktur", + Beta: "Beta", + Other: "Sonstiges", + }, + }, + objectData: { + badge: "Daten", + description: "Über die URL definierter Datenausschnitt — nicht an eine gespeicherte Ansicht gebunden.", + filteredBy: "Gefiltert nach", + removeFilter: "Filter {{field}} entfernen", + saveAsView: "Als Ansicht speichern", + noAccessTitle: "Zugriff verweigert", + noAccess: "Sie haben keine Berechtigung, diese Daten anzuzeigen.", + }, + identityImport: { + policyTitle: "Anmelde-Einrichtung für importierte Benutzer", + policy: { + auto: "Automatisch (empfohlen)", + invite: "Einladungen senden", + temporary: "Temporäre Passwörter", + none: "Kein Passwort (nur Identität)", + }, + policyHint: { + auto: "Erreichbare Benutzer erhalten eine Einladung (E-Mail oder SMS); wer nicht erreichbar ist, erhält ein Einmalpasswort, das NUR EINMAL auf dem Ergebnisbildschirm angezeigt wird. Funktioniert mit und ohne E-Mail-/SMS-Dienst.", + invite: "Jeder angelegte Benutzer erhält eine E-Mail zum Setzen des Passworts (oder eine Einladungs-SMS bei Zeilen mit nur Telefonnummer). Erfordert einen konfigurierten E-Mail-/SMS-Dienst — nicht erreichbare Zeilen schlagen fehl.", + temporary: "Für Installationen ohne E-Mail/SMS: Jeder angelegte Benutzer erhält ein Einmalpasswort, das NUR EINMAL auf dem Ergebnisbildschirm angezeigt wird. Die erste Anmeldung erzwingt eine Änderung.", + none: "Benutzer melden sich zuerst mit einem Telefon-OTP, einem Magic Link oder einem Link zum Zurücksetzen des Passworts an und legen dann ihr eigenes Passwort fest.", + }, + passwordsNote: "Temporäre Passwörter — einmalig angezeigt, nie gespeichert. Speichern Sie sie jetzt; jeder Benutzer muss seines bei der ersten Anmeldung ändern.", + passwordsMore: "Weitere Einträge ausgelassen — bitte den Download verwenden.", + passwordsDownload: "CSV herunterladen", + }, ai: { + usage: { + title: "KI-Nutzung", + meterBuild: "Erstellen", + meterAsk: "Fragen", + statusOk: "Reichlich übrig", + statusLow: "Wird knapp", + statusFull: "Limit erreicht", + resetsDaily: "Wird heute Nacht zurückgesetzt", + resetsMonthly: "Wird im nächsten Zyklus zurückgesetzt", + ctaUpgrade: "Upgraden, um weiterzumachen", + ctaTopUp: "Credits hinzufügen, um fortzufahren", + ariaLabel: "KI-Nutzung: {{status}}", + }, + workspaceTitle: "KI-Workspace", + workspaceSubtitle: "Fragen stellen, prüfen und Unterhaltungen fortsetzen", + openChats: "Chats öffnen", + chats: "Chats", + chatsDescription: "KI-Unterhaltungen durchsuchen und verwalten.", + share: "Teilen", + shareTitle: "Diese Unterhaltung teilen", + shareDisabledTitle: "Beginnen Sie zu chatten, um das Teilen zu aktivieren", + newChat: "Neu", + searchChats: "Chats durchsuchen...", + noChatsYet: "Noch keine Chats", + noChatsDescription: "Starten Sie eine neue Unterhaltung, um sie hier zu sehen.", + noMatchingChats: "Keine passenden Chats.", + newConversation: "Neue Unterhaltung", + renameConversation: "Unterhaltung umbenennen", + deleteConversation: "Unterhaltung löschen", + saveRename: "Umbenennung speichern", + cancelRename: "Umbenennung abbrechen", + loadingHistory: "Unterhaltungsverlauf wird geladen...", + conversationReady: "Unterhaltung bereit", + preparingConversation: "Neue Unterhaltung wird vorbereitet", + offlineDemoMode: "Offline-Demomodus — Agentenliste nicht verfügbar", + sendFailedRateLimited: "Sie senden zu schnell Nachrichten. Ihre Nachricht wird unten aufbewahrt — warten Sie einen Moment und versuchen Sie es erneut.", + sendFailedGeneric: "Ihre Nachricht konnte nicht gesendet werden. Sie wird unten aufbewahrt — bitte versuchen Sie es erneut.", + askAgent: "{{agent}} fragen...", + assistant: "Assistent", + liveCanvas: "Live-Vorschau — {{app}} (Entwurf)", + liveCanvasUnlisted: "Live-App — {{app}} (nicht gelistet bis zur Veröffentlichung)", + loadingAgents: "Agenten werden geladen...", + askAnything: "Fragen Sie irgendetwas...", + emptyTitle: "Unterhaltung beginnen", + emptyDescription: "Fragen Sie irgendetwas — der Assistent hat Zugriff auf den Kontext Ihrer aktuellen App.", + switchAssistant: "Assistenten wechseln", + chooseAgent: "Assistenten wählen…", + empty: { + build: { + title: "Mit KI erstellen", + description: "Beschreiben Sie eine App oder einen Workflow in einfachen Worten — ich entwerfe die Objekte, Bildschirme und Automatisierungen, dann prüfen und veröffentlichen Sie.", + }, + ask: { + title: "Ihre Daten fragen", + description: "Stellen Sie Fragen zu Ihren Datensätzen — Anzahlen, Listen und Zusammenfassungen über die Daten, auf die Sie zugreifen können.", + }, + editApp: { + title: "„{{app}}“ wird bearbeitet", + titleGeneric: "Diese App bearbeiten", + description: "Was möchten Sie ändern? Ich passe diese App direkt an — ein Feld, Objekt, eine Ansicht oder Automatisierung hinzufügen oder Vorhandenes anpassen.", + }, + }, + clearConversation: "Leeren", + sendHint: "zum Senden", + agentActivity: "Agentenaktivität", + toolCompleted: "Abgeschlossen", + toolRunning: "Läuft", + toolAwaitingApproval: "Warten auf Freigabe", + toolFailed: "Fehlgeschlagen", + toolDetailsHidden: "Tool-Eingaben und Rohergebnisse sind in dieser Ansicht ausgeblendet.", + copy: "Kopieren", + copied: "Kopiert", + regenerate: "Neu generieren", + model: "Modell", + submit: "Senden", + uploadFiles: "Dateien hochladen", + stopResponse: "Antwort stoppen", + trace: "Trace", + viewTrace: "Trace anzeigen", + nextSteps: "Wie geht es weiter", + publishDrafts: "Veröffentlichen", + publishOk: "Veröffentlicht — die Objekte sind jetzt live.", + seedWarn: "Veröffentlicht, aber einige Beispieldaten konnten nicht geladen werden.", + openBuiltApp: "App öffnen", + designBuiltApp: "In Studio gestalten", + previewDraft: "Vorschau", + previewApp: "App-Vorschau", + resizeSplit: "Chat und Vorschau anpassen", + hideChats: "Chats ausblenden", + showChats: "Chats anzeigen", + planTitle: "Vorgeschlagener Plan", + planQuestions: "Vor dem Erstellen bestätigen", + planAssumptions: "Annahmen", + planApproveHint: "Antworten Sie, um diesen Plan zu genehmigen oder anzupassen.", + planApprove: "Erstellen", + planAdjust: "Anpassen", + justNow: "gerade eben", + minutesAgo: "vor {{count}} Min.", + hoursAgo: "vor {{count}} Std.", + daysAgo: "vor {{count}} T.", + agentLabels: { + ask: "Fragen", + build: "Erstellen", + dataChat: "Assistent", + metadataAssistant: "Metadaten-Assistent", + }, + suggestions: { + dataChat: { + userCount: "Wie viele Benutzer gibt es im System? Liste ihre E-Mail-Adressen auf.", + recentRecords: "Liste die 5 zuletzt erstellten Datensätze auf.", + recordCounts: "Zähle die Datensätze je Objekt.", + }, + metadataAssistant: { + buildCrm: "Erstelle ein Vertriebs-CRM — Kunden, Kontakte und eine Deal-Pipeline, die ich nach Phase summieren kann.", + buildApp: "Erstelle einen Projekt-Tracker — Projekte, Aufgaben mit Verantwortlichen und Fälligkeitsdaten sowie ein Board nach Status.", + buildFlow: "Entwirf einen Support-Desk — Tickets mit Priorität, einen Status-Workflow und Kundenverknüpfungen.", + buildInventory: "Erstelle eine Bestands-App — Produkte, Lagerbestände, Lieferanten und Sichtbarkeit niedriger Bestände.", + buildRecruiting: "Erstelle einen Bewerber-Tracker — Kandidaten, offene Stellen, Interviewphasen und Notizen.", + }, + generic: { + help: "Wobei kannst du mir helfen?", + availableObjects: "Liste die verfügbaren Datenobjekte auf.", + recentActivity: "Fasse meine letzten Aktivitäten zusammen.", + }, + editApp: { + addField: "Füge einem der Objekte ein Feld hinzu.", + addObject: "Füge ein neues Objekt hinzu und verknüpfe es mit einem bestehenden.", + addDashboard: "Füge ein Dashboard für die wichtigsten Kennzahlen hinzu.", + addAutomation: "Füge eine Automatisierung hinzu — eine Freigabe, einen Statusablauf oder eine Benachrichtigung.", + }, + }, changesTitle: "Änderungen bestätigen", changesConfirmed: "Bestätigt", changesConfirm: "Bestätigen", changesConfirmHint: "Antworten Sie, um diese Änderung zu bestätigen oder anzupassen.", - changesConfirmMessage: "Änderungen bestätigt — wende an, was du gerade vorgeschlagen hast.", changeVerb: { createObject: "Objekt erstellen", addField: "Feld hinzufügen", @@ -915,6 +1088,7 @@ const de = { toggleDarkMode: "Dunkelmodus umschalten", }, commandPalette: { + title: "Befehlspalette", placeholder: "Befehl eingeben oder suchen...", noResults: "Keine Ergebnisse gefunden.", objects: "Objekte", @@ -948,6 +1122,14 @@ const de = { system: "System", }, objectView: { + viewTypeTree: "Baum", + viewTypeTreeDesc: "Selbstreferenzierende Datensätze über ein übergeordnetes Feld zu einer Hierarchie verschachteln.", + parentField: "Übergeordnetes Feld", + parentFieldHelp: "Das Feld, das auf den übergeordneten Datensatz (dasselbe Objekt) verweist und die Hierarchie definiert. Nur selbstreferenzierende Felder kommen infrage.", + viewName: "Name", + viewNameHelp: "Technischer Schlüssel (snake_case). Wird aus dem Titel automatisch gefüllt — bei Bedarf anpassen.", + viewNameRequired: "Geben Sie einen Schlüssel ein (Kleinbuchstaben, Ziffern, Unterstrich). Bei nicht-lateinischen Titeln wird er nicht automatisch gefüllt.", + viewNameInvalid: "Verwenden Sie Kleinbuchstaben, Ziffern und Unterstriche; beginnen Sie mit einem Buchstaben oder Unterstrich.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "Objekt nicht gefunden", @@ -1419,10 +1601,54 @@ const de = { removeFromFavorites: "{{name}} aus Favoriten entfernen", }, topbar: { + openAssistant: "Assistent {{name}} öffnen", + offline: "Offline", + usersOnline: "Aktuell online befindliche Benutzer", + switchView: "Ansicht wechseln", + switchObject: "Objekt wechseln", + connection: { + connected: "Verbunden", + connecting: "Verbindung wird hergestellt...", + reconnecting: "Verbindung wird wiederhergestellt...", + disconnected: "Getrennt", + error: "Verbindungsfehler", + }, + stage: { + preview: "Vorschau", + beta: "Beta", + tooltip: "Diese Plattform befindet sich in der Vorschau — Funktionen können sich ändern.", + }, aiAssistant: "KI-Assistent", designInStudio: "Im Studio gestalten", }, home: { + build: { + title: "App erstellen", + subtitle: "Von Grund auf beginnen — Objekte, Formulare, Automatisierungen und Oberflächen gestalten.", + }, + template: { + title: "Mit einer Vorlage starten", + subtitle: "Installieren Sie eine Vorlagen-App aus dem Marktplatz und passen Sie sie an.", + }, + welcomeAdminDescription: "Beschreiben Sie Ihr Geschäft in einem Satz — die KI erzeugt die Objekte, Bildschirme, APIs und Agent-Tools. Oder richten Sie alles selbst über das Menü links ein.", + welcomeAdminDescriptionNoBuild: "Richten Sie Ihre erste Anwendung über das Verwaltungsmenü links ein. Sobald Daten vorhanden sind, kann der KI-Assistent bei der Auswertung helfen.", + welcomeAdminDescriptionNoAi: "Richten Sie Ihre erste Anwendung über das Verwaltungsmenü links ein.", + noAppsTitle: "Noch keine Anwendungen", + noAppsDescription: "Ihr Workspace wird eingerichtet — Apps, die Ihr Administrator für Sie freigibt, erscheinen hier.", + buildWithAI: "Mit KI erstellen", + askAI: "KI fragen", + recoveryReminder: { + message: "Legen Sie ein Wiederherstellungspasswort fest, damit Sie sich auch anmelden können, wenn Single Sign-on einmal nicht verfügbar ist.", + cta: "Passwort festlegen", + dismiss: "Ausblenden", + }, + pendingDrafts: { + message: "Sie haben {{count}} unveröffentlichte Änderung(en) — veröffentlichen Sie sie, um sie live zu schalten.", + cta: "Veröffentlichen", + publishing: "Wird veröffentlicht…", + published: "Veröffentlicht! Ihre Änderungen sind live.", + publishFailed: "Veröffentlichen fehlgeschlagen", + }, title: "Startseite", subtitle: "Ihr Arbeitsbereich-Dashboard", nav: "Startseite", @@ -1486,7 +1712,21 @@ const de = { }, }, layout: { + systemNav: { + systemSettings: "Systemeinstellungen", + applications: "Anwendungen", + appMarketplace: "App-Marktplatz", + objectManager: "Objekt-Manager", + users: "Benutzer", + organizations: "Organisationen", + roles: "Rollen", + configuration: "Konfiguration", + createApp: "App erstellen", + }, appSwitcher: { + switchApplication: "Anwendung wechseln", + appsAvailable: "{{count}} Apps verfügbar", + editNavigation: "Navigation bearbeiten", home: "Startseite", addApp: "App hinzufügen", editApp: "App bearbeiten", diff --git a/packages/i18n/src/locales/es.ts b/packages/i18n/src/locales/es.ts index 570d1eead..f13bfc5e1 100644 --- a/packages/i18n/src/locales/es.ts +++ b/packages/i18n/src/locales/es.ts @@ -854,12 +854,185 @@ const es = { }, }, console: { + settingsHub: { + title: "Configuración", + subtitle: "Configure su espacio de trabajo, las integraciones y los indicadores de funciones.", + loadError: "No se pudo cargar la configuración", + empty: "No hay configuraciones registradas. Los plugins pueden registrar manifiestos de configuración mediante el SettingsService.", + settingsCount: "{{n}} configuraciones", + beta: "Beta", + categories: { + Workspace: "Espacio de trabajo", + Communication: "Comunicación", + Security: "Seguridad", + Infrastructure: "Infraestructura", + Beta: "Beta", + Other: "Otros", + }, + }, + objectData: { + badge: "Datos", + description: "Segmento de datos definido por la URL — no vinculado a ninguna vista guardada.", + filteredBy: "Filtrado por", + removeFilter: "Quitar el filtro {{field}}", + saveAsView: "Guardar como vista", + noAccessTitle: "Acceso denegado", + noAccess: "No tiene permiso para ver estos datos.", + }, + identityImport: { + policyTitle: "Configuración de inicio de sesión para los usuarios importados", + policy: { + auto: "Automático (recomendado)", + invite: "Enviar invitaciones", + temporary: "Contraseñas temporales", + none: "Sin contraseña (solo identidad)", + }, + policyHint: { + auto: "Los usuarios localizables reciben una invitación (correo o SMS); quienes no sean localizables reciben una contraseña de un solo uso, mostrada UNA SOLA VEZ en la pantalla de resultados. Funciona con o sin servicio de correo/SMS.", + invite: "Cada usuario creado recibe un correo para establecer su contraseña (o un SMS de invitación en las filas que solo tienen teléfono). Requiere un servicio de correo/SMS configurado — las filas no localizables fallan.", + temporary: "Para despliegues sin correo/SMS: cada usuario creado recibe una contraseña de un solo uso, mostrada UNA SOLA VEZ en la pantalla de resultados. El primer inicio de sesión obliga a cambiarla.", + none: "Los usuarios inician sesión primero con un OTP por teléfono, un enlace mágico o un enlace de restablecimiento, y luego establecen su propia contraseña.", + }, + passwordsNote: "Contraseñas temporales — se muestran una sola vez y nunca se almacenan. Guárdelas ahora; cada usuario debe cambiar la suya en el primer inicio de sesión.", + passwordsMore: "Se han omitido más entradas — use la descarga.", + passwordsDownload: "Descargar CSV", + }, ai: { + usage: { + title: "Uso de IA", + meterBuild: "Crear", + meterAsk: "Preguntar", + statusOk: "Queda bastante", + statusLow: "Se está agotando", + statusFull: "Límite alcanzado", + resetsDaily: "Se restablece esta noche", + resetsMonthly: "Se restablece en el próximo ciclo", + ctaUpgrade: "Mejore el plan para continuar", + ctaTopUp: "Añada créditos para continuar", + ariaLabel: "Uso de IA: {{status}}", + }, + workspaceTitle: "Espacio de trabajo de IA", + workspaceSubtitle: "Pregunte, inspeccione y retome conversaciones", + openChats: "Abrir chats", + chats: "Chats", + chatsDescription: "Explore y gestione las conversaciones con la IA.", + share: "Compartir", + shareTitle: "Compartir esta conversación", + shareDisabledTitle: "Empiece a chatear para habilitar el uso compartido", + newChat: "Nuevo", + searchChats: "Buscar chats...", + noChatsYet: "Todavía no hay chats", + noChatsDescription: "Inicie una conversación nueva para verla aquí.", + noMatchingChats: "No hay chats coincidentes.", + newConversation: "Nueva conversación", + renameConversation: "Cambiar el nombre de la conversación", + deleteConversation: "Eliminar conversación", + saveRename: "Guardar el nombre", + cancelRename: "Cancelar el cambio de nombre", + loadingHistory: "Cargando el historial de la conversación...", + conversationReady: "Conversación lista", + preparingConversation: "Preparando una nueva conversación", + offlineDemoMode: "Modo de demostración sin conexión — lista de agentes no disponible", + sendFailedRateLimited: "Está enviando mensajes demasiado rápido. Su mensaje se conserva abajo — espere un momento y vuelva a intentarlo.", + sendFailedGeneric: "No se pudo enviar su mensaje. Se conserva abajo — inténtelo de nuevo.", + askAgent: "Pregunte a {{agent}}...", + assistant: "Asistente", + liveCanvas: "Vista previa en vivo — {{app}} (borrador)", + liveCanvasUnlisted: "Aplicación en vivo — {{app}} (no listada hasta su publicación)", + loadingAgents: "Cargando agentes...", + askAnything: "Pregunte lo que quiera...", + emptyTitle: "Iniciar una conversación", + emptyDescription: "Pregunte lo que quiera — el asistente tiene acceso al contexto de su aplicación actual.", + switchAssistant: "Cambiar de asistente", + chooseAgent: "Elegir asistente…", + empty: { + build: { + title: "Crear con IA", + description: "Describa una aplicación o un flujo de trabajo en lenguaje natural — yo redacto los objetos, las pantallas y las automatizaciones, y luego usted revisa y publica.", + }, + ask: { + title: "Pregunte a sus datos", + description: "Haga preguntas sobre sus registros — recuentos, listas y resúmenes de los datos a los que tiene acceso.", + }, + editApp: { + title: "Editando «{{app}}»", + titleGeneric: "Editar esta aplicación", + description: "¿Qué desea cambiar? Modifico esta aplicación sobre la marcha — añadir un campo, un objeto, una vista o una automatización, o ajustar lo que ya existe.", + }, + }, + clearConversation: "Borrar", + sendHint: "para enviar", + agentActivity: "Actividad del agente", + toolCompleted: "Completado", + toolRunning: "En ejecución", + toolAwaitingApproval: "Esperando aprobación", + toolFailed: "Error", + toolDetailsHidden: "Las entradas de las herramientas y los resultados sin procesar están ocultos en esta vista.", + copy: "Copiar", + copied: "Copiado", + regenerate: "Regenerar", + model: "Modelo", + submit: "Enviar", + uploadFiles: "Subir archivos", + stopResponse: "Detener la respuesta", + trace: "traza", + viewTrace: "Ver la traza", + nextSteps: "Qué sigue", + publishDrafts: "Publicar", + publishOk: "Publicado — los objetos ya están activos.", + seedWarn: "Publicado, pero no se pudieron cargar algunos datos de ejemplo.", + openBuiltApp: "Abrir la aplicación", + designBuiltApp: "Diseñar en Studio", + previewDraft: "Vista previa", + previewApp: "Vista previa de la aplicación", + resizeSplit: "Redimensionar el chat y la vista previa", + hideChats: "Ocultar los chats", + showChats: "Mostrar los chats", + planTitle: "Plan propuesto", + planQuestions: "Confirmar antes de crear", + planAssumptions: "Supuestos", + planApproveHint: "Responda para aprobar o ajustar este plan.", + planApprove: "Crearlo", + planAdjust: "Ajustar", + justNow: "ahora mismo", + minutesAgo: "hace {{count}} min", + hoursAgo: "hace {{count}} h", + daysAgo: "hace {{count}} d", + agentLabels: { + ask: "Preguntar", + build: "Crear", + dataChat: "Asistente", + metadataAssistant: "Asistente de metadatos", + }, + suggestions: { + dataChat: { + userCount: "¿Cuántos usuarios hay en el sistema? Enumera sus correos electrónicos.", + recentRecords: "Enumera los 5 registros creados más recientemente.", + recordCounts: "Cuenta los registros de cada objeto.", + }, + metadataAssistant: { + buildCrm: "Crea un CRM de ventas — clientes, contactos y un embudo de oportunidades que pueda totalizar por etapa.", + buildApp: "Crea un seguimiento de proyectos — proyectos, tareas con responsables y fechas de vencimiento, y un tablero por estado.", + buildFlow: "Diseña una mesa de ayuda — tickets con prioridad, un flujo de estados y vínculos con los clientes.", + buildInventory: "Crea una aplicación de inventario — productos, niveles de stock, proveedores y visibilidad de stock bajo.", + buildRecruiting: "Crea un seguimiento de candidaturas — candidatos, vacantes, etapas de entrevista y notas.", + }, + generic: { + help: "¿En qué puedes ayudarme?", + availableObjects: "Enumera los objetos de datos disponibles.", + recentActivity: "Resume mi actividad reciente.", + }, + editApp: { + addField: "Añade un campo a uno de los objetos.", + addObject: "Añade un objeto nuevo y relaciónalo con uno existente.", + addDashboard: "Añade un panel para las métricas clave.", + addAutomation: "Añade una automatización — una aprobación, un flujo de estados o una notificación.", + }, + }, changesTitle: "Confirmar cambios", changesConfirmed: "Confirmado", changesConfirm: "Confirmar", changesConfirmHint: "Responda para confirmar o ajustar este cambio.", - changesConfirmMessage: "Cambios confirmados: aplica lo que acabas de proponer.", changeVerb: { createObject: "Crear objeto", addField: "Añadir campo", @@ -915,6 +1088,7 @@ const es = { toggleDarkMode: "Alternar modo oscuro", }, commandPalette: { + title: "Paleta de comandos", placeholder: "Escriba un comando o busque...", noResults: "No se encontraron resultados.", objects: "Objetos", @@ -948,6 +1122,14 @@ const es = { system: "Sistema", }, objectView: { + viewTypeTree: "Árbol", + viewTypeTreeDesc: "Anida los registros autorreferenciados en una jerarquía mediante un campo principal.", + parentField: "Campo principal", + parentFieldHelp: "El campo que apunta al registro principal (mismo objeto) y define la jerarquía. Solo son válidos los campos autorreferenciados.", + viewName: "Nombre", + viewNameHelp: "Clave técnica (snake_case). Se rellena automáticamente a partir del título — edítela si lo desea.", + viewNameRequired: "Introduzca una clave (minúsculas, números, guion bajo). No se rellena automáticamente con títulos no latinos.", + viewNameInvalid: "Use minúsculas, números y guiones bajos; empiece por una letra o un guion bajo.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "Objeto no encontrado", @@ -1419,10 +1601,54 @@ const es = { removeFromFavorites: "Quitar {{name}} de favoritos", }, topbar: { + openAssistant: "Abrir el asistente {{name}}", + offline: "Sin conexión", + usersOnline: "Usuarios conectados ahora mismo", + switchView: "Cambiar de vista", + switchObject: "Cambiar de objeto", + connection: { + connected: "Conectado", + connecting: "Conectando...", + reconnecting: "Reconectando...", + disconnected: "Desconectado", + error: "Error de conexión", + }, + stage: { + preview: "Vista previa", + beta: "Beta", + tooltip: "Esta plataforma está en versión preliminar — las funciones pueden cambiar.", + }, aiAssistant: "Asistente de IA", designInStudio: "Diseñar en Studio", }, home: { + build: { + title: "Crear una aplicación", + subtitle: "Empiece desde cero — diseñe objetos, formularios, automatizaciones e interfaces.", + }, + template: { + title: "Empezar con una plantilla", + subtitle: "Instale una aplicación de plantilla desde el mercado y personalícela.", + }, + welcomeAdminDescription: "Describa su negocio en una frase — la IA genera los objetos, las pantallas, las API y las herramientas del agente. O configúrelo usted mismo desde el menú de la izquierda.", + welcomeAdminDescriptionNoBuild: "Configure su primera aplicación desde el menú de Administración de la izquierda. Cuando tenga datos, el asistente de IA podrá ayudarle a explorarlos.", + welcomeAdminDescriptionNoAi: "Configure su primera aplicación desde el menú de Administración de la izquierda.", + noAppsTitle: "Todavía no hay aplicaciones", + noAppsDescription: "Su espacio de trabajo se está preparando — las aplicaciones que su administrador comparta aparecerán aquí.", + buildWithAI: "Crear con IA", + askAI: "Preguntar a la IA", + recoveryReminder: { + message: "Establezca una contraseña de recuperación para poder iniciar sesión aunque el inicio de sesión único no esté disponible.", + cta: "Establecer contraseña", + dismiss: "Descartar", + }, + pendingDrafts: { + message: "Tiene {{count}} cambio(s) sin publicar — publíquelos para activarlos.", + cta: "Publicar", + publishing: "Publicando…", + published: "¡Publicado! Sus cambios están activos.", + publishFailed: "Error al publicar", + }, title: "Inicio", subtitle: "Panel de tu espacio de trabajo", nav: "Inicio", @@ -1486,7 +1712,21 @@ const es = { }, }, layout: { + systemNav: { + systemSettings: "Configuración del sistema", + applications: "Aplicaciones", + appMarketplace: "Mercado de aplicaciones", + objectManager: "Gestor de objetos", + users: "Usuarios", + organizations: "Organizaciones", + roles: "Roles", + configuration: "Configuración", + createApp: "Crear aplicación", + }, appSwitcher: { + switchApplication: "Cambiar de aplicación", + appsAvailable: "{{count}} aplicaciones disponibles", + editNavigation: "Editar la navegación", home: "Inicio", addApp: "Agregar aplicación", editApp: "Editar aplicación", diff --git a/packages/i18n/src/locales/fr.ts b/packages/i18n/src/locales/fr.ts index 90f4655e3..f756233b8 100644 --- a/packages/i18n/src/locales/fr.ts +++ b/packages/i18n/src/locales/fr.ts @@ -852,12 +852,185 @@ const fr = { }, }, console: { + settingsHub: { + title: "Paramètres", + subtitle: "Configurez votre espace de travail, vos intégrations et vos indicateurs de fonctionnalité.", + loadError: "Échec du chargement des paramètres", + empty: "Aucun paramètre enregistré. Les plugins peuvent enregistrer des manifestes de paramètres via le SettingsService.", + settingsCount: "{{n}} paramètres", + beta: "Bêta", + categories: { + Workspace: "Espace de travail", + Communication: "Communication", + Security: "Sécurité", + Infrastructure: "Infrastructure", + Beta: "Bêta", + Other: "Autre", + }, + }, + objectData: { + badge: "Données", + description: "Extrait de données défini par l'URL — non lié à une vue enregistrée.", + filteredBy: "Filtré par", + removeFilter: "Supprimer le filtre {{field}}", + saveAsView: "Enregistrer comme vue", + noAccessTitle: "Accès refusé", + noAccess: "Vous n'avez pas l'autorisation de consulter ces données.", + }, + identityImport: { + policyTitle: "Configuration de connexion pour les utilisateurs importés", + policy: { + auto: "Automatique (recommandé)", + invite: "Envoyer des invitations", + temporary: "Mots de passe temporaires", + none: "Aucun mot de passe (identité seulement)", + }, + policyHint: { + auto: "Les utilisateurs joignables reçoivent une invitation (e-mail ou SMS) ; ceux que nous ne pouvons pas joindre reçoivent un mot de passe à usage unique, affiché UNE SEULE FOIS sur l'écran de résultat. Fonctionne avec ou sans service e-mail/SMS.", + invite: "Chaque utilisateur créé reçoit un e-mail de définition de mot de passe (ou un SMS d'invitation pour les lignes avec téléphone uniquement). Nécessite un service e-mail/SMS configuré — les lignes injoignables échouent.", + temporary: "Pour les déploiements sans e-mail/SMS : chaque utilisateur créé reçoit un mot de passe à usage unique, affiché UNE SEULE FOIS sur l'écran de résultat. La première connexion impose un changement.", + none: "Les utilisateurs se connectent d'abord avec un code OTP par téléphone, un lien magique ou un lien de réinitialisation, puis définissent leur propre mot de passe.", + }, + passwordsNote: "Mots de passe temporaires — affichés une seule fois, jamais stockés. Enregistrez-les maintenant ; chaque utilisateur doit changer le sien à la première connexion.", + passwordsMore: "Autres entrées omises — utilisez le téléchargement.", + passwordsDownload: "Télécharger le CSV", + }, ai: { + usage: { + title: "Utilisation de l'IA", + meterBuild: "Créer", + meterAsk: "Demander", + statusOk: "Il en reste beaucoup", + statusLow: "Bientôt épuisé", + statusFull: "Limite atteinte", + resetsDaily: "Réinitialisation ce soir", + resetsMonthly: "Réinitialisation au prochain cycle", + ctaUpgrade: "Passer à l'offre supérieure pour continuer", + ctaTopUp: "Ajouter des crédits pour continuer", + ariaLabel: "Utilisation de l'IA : {{status}}", + }, + workspaceTitle: "Espace de travail IA", + workspaceSubtitle: "Posez des questions, inspectez et reprenez vos conversations", + openChats: "Ouvrir les discussions", + chats: "Discussions", + chatsDescription: "Parcourez et gérez les conversations avec l'IA.", + share: "Partager", + shareTitle: "Partager cette conversation", + shareDisabledTitle: "Commencez à discuter pour activer le partage", + newChat: "Nouveau", + searchChats: "Rechercher des discussions...", + noChatsYet: "Aucune discussion pour l'instant", + noChatsDescription: "Démarrez une nouvelle conversation pour la voir ici.", + noMatchingChats: "Aucune discussion correspondante.", + newConversation: "Nouvelle conversation", + renameConversation: "Renommer la conversation", + deleteConversation: "Supprimer la conversation", + saveRename: "Enregistrer le nom", + cancelRename: "Annuler le changement de nom", + loadingHistory: "Chargement de l'historique de la conversation...", + conversationReady: "Conversation prête", + preparingConversation: "Préparation d'une nouvelle conversation", + offlineDemoMode: "Mode démo hors ligne — liste des agents indisponible", + sendFailedRateLimited: "Vous envoyez des messages trop rapidement. Votre message est conservé ci-dessous — patientez un instant puis réessayez.", + sendFailedGeneric: "Impossible d'envoyer votre message. Il est conservé ci-dessous — veuillez réessayer.", + askAgent: "Demander à {{agent}}...", + assistant: "Assistant", + liveCanvas: "Aperçu en direct — {{app}} (brouillon)", + liveCanvasUnlisted: "Application en direct — {{app}} (non répertoriée jusqu'à publication)", + loadingAgents: "Chargement des agents...", + askAnything: "Posez n'importe quelle question...", + emptyTitle: "Démarrer une conversation", + emptyDescription: "Posez n'importe quelle question — l'assistant a accès au contexte de votre application actuelle.", + switchAssistant: "Changer d'assistant", + chooseAgent: "Choisir un assistant…", + empty: { + build: { + title: "Créer avec l'IA", + description: "Décrivez une application ou un flux de travail en langage courant — je rédige les objets, les écrans et les automatisations, puis vous vérifiez et publiez.", + }, + ask: { + title: "Interroger vos données", + description: "Posez des questions sur vos enregistrements — comptages, listes et synthèses sur les données auxquelles vous avez accès.", + }, + editApp: { + title: "Modification de « {{app}} »", + titleGeneric: "Modifier cette application", + description: "Que souhaitez-vous changer ? Je modifie cette application sur place — ajouter un champ, un objet, une vue ou une automatisation, ou ajuster l'existant.", + }, + }, + clearConversation: "Effacer", + sendHint: "pour envoyer", + agentActivity: "Activité de l'agent", + toolCompleted: "Terminé", + toolRunning: "En cours", + toolAwaitingApproval: "En attente d'approbation", + toolFailed: "Échec", + toolDetailsHidden: "Les entrées des outils et les résultats bruts sont masqués dans cette vue.", + copy: "Copier", + copied: "Copié", + regenerate: "Régénérer", + model: "Modèle", + submit: "Envoyer", + uploadFiles: "Téléverser des fichiers", + stopResponse: "Arrêter la réponse", + trace: "trace", + viewTrace: "Afficher la trace", + nextSteps: "Et ensuite", + publishDrafts: "Publier", + publishOk: "Publié — les objets sont maintenant actifs.", + seedWarn: "Publié, mais certaines données d'exemple n'ont pas pu être chargées.", + openBuiltApp: "Ouvrir l'application", + designBuiltApp: "Concevoir dans Studio", + previewDraft: "Aperçu", + previewApp: "Aperçu de l'application", + resizeSplit: "Redimensionner la discussion et l'aperçu", + hideChats: "Masquer les discussions", + showChats: "Afficher les discussions", + planTitle: "Plan proposé", + planQuestions: "Confirmer avant de créer", + planAssumptions: "Hypothèses", + planApproveHint: "Répondez pour approuver ou ajuster ce plan.", + planApprove: "Créer", + planAdjust: "Ajuster", + justNow: "à l'instant", + minutesAgo: "il y a {{count}} min", + hoursAgo: "il y a {{count}} h", + daysAgo: "il y a {{count}} j", + agentLabels: { + ask: "Demander", + build: "Créer", + dataChat: "Assistant", + metadataAssistant: "Assistant de métadonnées", + }, + suggestions: { + dataChat: { + userCount: "Combien d'utilisateurs y a-t-il dans le système ? Liste leurs adresses e-mail.", + recentRecords: "Liste les 5 enregistrements créés le plus récemment.", + recordCounts: "Compte les enregistrements pour chaque objet.", + }, + metadataAssistant: { + buildCrm: "Crée un CRM commercial — clients, contacts et un pipeline d'affaires que je peux totaliser par étape.", + buildApp: "Crée un suivi de projets — projets, tâches avec responsables et échéances, et un tableau par statut.", + buildFlow: "Conçois un service d'assistance — tickets avec priorité, un flux de statuts et des liens vers les clients.", + buildInventory: "Crée une application de stock — produits, niveaux de stock, fournisseurs et visibilité des stocks faibles.", + buildRecruiting: "Crée un suivi de candidatures — candidats, postes ouverts, étapes d'entretien et notes.", + }, + generic: { + help: "En quoi peux-tu m'aider ?", + availableObjects: "Liste les objets de données disponibles.", + recentActivity: "Résume mon activité récente.", + }, + editApp: { + addField: "Ajoute un champ à l'un des objets.", + addObject: "Ajoute un nouvel objet et relie-le à un objet existant.", + addDashboard: "Ajoute un tableau de bord pour les indicateurs clés.", + addAutomation: "Ajoute une automatisation — une approbation, un flux de statuts ou une notification.", + }, + }, changesTitle: "Confirmer les modifications", changesConfirmed: "Confirmé", changesConfirm: "Confirmer", changesConfirmHint: "Répondez pour confirmer ou ajuster cette modification.", - changesConfirmMessage: "Modifications confirmées — applique ce que tu viens de proposer.", changeVerb: { createObject: "Créer un objet", addField: "Ajouter un champ", @@ -913,6 +1086,7 @@ const fr = { toggleDarkMode: "Basculer le mode sombre", }, commandPalette: { + title: "Palette de commandes", placeholder: "Tapez une commande ou recherchez...", noResults: "Aucun résultat trouvé.", objects: "Objets", @@ -946,6 +1120,14 @@ const fr = { system: "Système", }, objectView: { + viewTypeTree: "Arborescence", + viewTypeTreeDesc: "Imbriquer les enregistrements auto-référencés en hiérarchie via un champ parent.", + parentField: "Champ parent", + parentFieldHelp: "Le champ pointant vers l'enregistrement parent (même objet) qui définit la hiérarchie. Seuls les champs auto-référencés conviennent.", + viewName: "Nom", + viewNameHelp: "Clé technique (snake_case). Remplie automatiquement à partir du titre — modifiable si vous le souhaitez.", + viewNameRequired: "Saisissez une clé (minuscules, chiffres, tiret bas). Non remplie automatiquement pour les titres non latins.", + viewNameInvalid: "Utilisez des minuscules, des chiffres et des tirets bas ; commencez par une lettre ou un tiret bas.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "Objet introuvable", @@ -1417,10 +1599,54 @@ const fr = { removeFromFavorites: "Retirer {{name}} des favoris", }, topbar: { + openAssistant: "Ouvrir l'assistant {{name}}", + offline: "Hors ligne", + usersOnline: "Utilisateurs actuellement en ligne", + switchView: "Changer de vue", + switchObject: "Changer d'objet", + connection: { + connected: "Connecté", + connecting: "Connexion...", + reconnecting: "Reconnexion...", + disconnected: "Déconnecté", + error: "Erreur de connexion", + }, + stage: { + preview: "Aperçu", + beta: "Bêta", + tooltip: "Cette plateforme est en avant-première — les fonctionnalités peuvent changer.", + }, aiAssistant: "Assistant IA", designInStudio: "Concevoir dans Studio", }, home: { + build: { + title: "Créer une application", + subtitle: "Partir de zéro — concevez les objets, formulaires, automatisations et interfaces.", + }, + template: { + title: "Partir d'un modèle", + subtitle: "Installez une application modèle depuis la place de marché et personnalisez-la.", + }, + welcomeAdminDescription: "Décrivez votre activité en une phrase — l'IA génère les objets, les écrans, les API et les outils d'agent. Ou configurez tout vous-même depuis le menu de gauche.", + welcomeAdminDescriptionNoBuild: "Configurez votre première application depuis le menu Administration à gauche. Une fois les données en place, l'assistant IA pourra vous aider à les explorer.", + welcomeAdminDescriptionNoAi: "Configurez votre première application depuis le menu Administration à gauche.", + noAppsTitle: "Aucune application pour l'instant", + noAppsDescription: "Votre espace de travail est en cours de configuration — les applications partagées par votre administrateur apparaîtront ici.", + buildWithAI: "Créer avec l'IA", + askAI: "Demander à l'IA", + recoveryReminder: { + message: "Définissez un mot de passe de secours afin de pouvoir vous connecter même si l'authentification unique est indisponible.", + cta: "Définir le mot de passe", + dismiss: "Ignorer", + }, + pendingDrafts: { + message: "Vous avez {{count}} modification(s) non publiée(s) — publiez-les pour les activer.", + cta: "Publier", + publishing: "Publication…", + published: "Publié ! Vos modifications sont actives.", + publishFailed: "Échec de la publication", + }, title: "Accueil", subtitle: "Tableau de bord de votre espace de travail", nav: "Accueil", @@ -1484,7 +1710,21 @@ const fr = { }, }, layout: { + systemNav: { + systemSettings: "Paramètres système", + applications: "Applications", + appMarketplace: "Place de marché d'applications", + objectManager: "Gestionnaire d'objets", + users: "Utilisateurs", + organizations: "Organisations", + roles: "Rôles", + configuration: "Configuration", + createApp: "Créer une application", + }, appSwitcher: { + switchApplication: "Changer d'application", + appsAvailable: "{{count}} applications disponibles", + editNavigation: "Modifier la navigation", home: "Accueil", addApp: "Ajouter une application", editApp: "Modifier l'application", diff --git a/packages/i18n/src/locales/ja.ts b/packages/i18n/src/locales/ja.ts index 76e6f1378..27d17b1f5 100644 --- a/packages/i18n/src/locales/ja.ts +++ b/packages/i18n/src/locales/ja.ts @@ -854,12 +854,185 @@ const ja = { }, }, console: { + settingsHub: { + title: "設定", + subtitle: "ワークスペース、連携、機能フラグを設定します。", + loadError: "設定の読み込みに失敗しました", + empty: "登録された設定はありません。プラグインは SettingsService 経由で設定マニフェストを登録できます。", + settingsCount: "{{n}} 件の設定", + beta: "ベータ", + categories: { + Workspace: "ワークスペース", + Communication: "コミュニケーション", + Security: "セキュリティ", + Infrastructure: "インフラストラクチャ", + Beta: "ベータ", + Other: "その他", + }, + }, + objectData: { + badge: "データ", + description: "URL で定義されたデータの断面 — 保存済みビューには紐づいていません。", + filteredBy: "絞り込み条件", + removeFilter: "絞り込み {{field}} を解除", + saveAsView: "ビューとして保存", + noAccessTitle: "アクセスが拒否されました", + noAccess: "このデータを閲覧する権限がありません。", + }, + identityImport: { + policyTitle: "インポートしたユーザーのサインイン設定", + policy: { + auto: "自動(推奨)", + invite: "招待を送信", + temporary: "仮パスワード", + none: "パスワードなし(ID のみ)", + }, + policyHint: { + auto: "連絡可能なユーザーには招待(メールまたは SMS)を送信し、連絡できないユーザーにはワンタイムパスワードを発行して結果画面に一度だけ表示します。メール/SMS サービスの有無にかかわらず利用できます。", + invite: "作成された全ユーザーにパスワード設定メール(電話番号のみの行には招待 SMS)を送信します。メール/SMS サービスの設定が必要で、連絡できない行は失敗します。", + temporary: "メール/SMS のない環境向け: 作成された全ユーザーにワンタイムパスワードを発行し、結果画面に一度だけ表示します。初回サインイン時に変更が必須です。", + none: "ユーザーはまず電話 OTP、マジックリンク、またはパスワード再設定リンクでサインインし、その後自分でパスワードを設定します。", + }, + passwordsNote: "仮パスワード — 一度だけ表示され、保存されません。今すぐ保存してください。各ユーザーは初回サインイン時に変更する必要があります。", + passwordsMore: "以降のエントリは省略されました — ダウンロードをご利用ください。", + passwordsDownload: "CSV をダウンロード", + }, ai: { + usage: { + title: "AI 使用状況", + meterBuild: "ビルド", + meterAsk: "質問", + statusOk: "残量に余裕があります", + statusLow: "残りわずかです", + statusFull: "上限に達しました", + resetsDaily: "今夜リセットされます", + resetsMonthly: "次のサイクルでリセットされます", + ctaUpgrade: "アップグレードして続行", + ctaTopUp: "クレジットを追加して続行", + ariaLabel: "AI 使用状況: {{status}}", + }, + workspaceTitle: "AI ワークスペース", + workspaceSubtitle: "質問し、確認し、会話を再開します", + openChats: "チャットを開く", + chats: "チャット", + chatsDescription: "AI の会話を閲覧・管理します。", + share: "共有", + shareTitle: "この会話を共有", + shareDisabledTitle: "共有するにはチャットを開始してください", + newChat: "新規", + searchChats: "チャットを検索...", + noChatsYet: "チャットはまだありません", + noChatsDescription: "新しい会話を開始するとここに表示されます。", + noMatchingChats: "一致するチャットはありません。", + newConversation: "新しい会話", + renameConversation: "会話の名前を変更", + deleteConversation: "会話を削除", + saveRename: "名前を保存", + cancelRename: "名前の変更をキャンセル", + loadingHistory: "会話履歴を読み込んでいます...", + conversationReady: "会話の準備ができました", + preparingConversation: "新しい会話を準備しています", + offlineDemoMode: "オフラインデモモード — エージェント一覧は利用できません", + sendFailedRateLimited: "送信の間隔が短すぎます。メッセージは下に保持されています — 少し待ってから再試行してください。", + sendFailedGeneric: "メッセージを送信できませんでした。下に保持されています — もう一度お試しください。", + askAgent: "{{agent}} に質問...", + assistant: "アシスタント", + liveCanvas: "ライブプレビュー — {{app}}(ドラフト)", + liveCanvasUnlisted: "ライブアプリ — {{app}}(公開するまで非掲載)", + loadingAgents: "エージェントを読み込んでいます...", + askAnything: "何でも質問してください...", + emptyTitle: "会話を始める", + emptyDescription: "何でも質問してください — アシスタントは現在のアプリのコンテキストを参照できます。", + switchAssistant: "アシスタントを切り替え", + chooseAgent: "アシスタントを選択…", + empty: { + build: { + title: "AI でビルド", + description: "アプリやワークフローを普通の言葉で説明してください — オブジェクト、画面、自動化を下書きしますので、確認して公開してください。", + }, + ask: { + title: "データに質問", + description: "レコードについて質問してください — アクセスできるデータの件数、一覧、要約をお答えします。", + }, + editApp: { + title: "「{{app}}」を編集中", + titleGeneric: "このアプリを編集", + description: "何を変更しますか?このアプリをその場で変更します — 項目、オブジェクト、ビュー、自動化の追加や、既存部分の調整ができます。", + }, + }, + clearConversation: "クリア", + sendHint: "で送信", + agentActivity: "エージェントの動作", + toolCompleted: "完了", + toolRunning: "実行中", + toolAwaitingApproval: "承認待ち", + toolFailed: "失敗", + toolDetailsHidden: "このビューではツールの入力と生の結果は非表示です。", + copy: "コピー", + copied: "コピーしました", + regenerate: "再生成", + model: "モデル", + submit: "送信", + uploadFiles: "ファイルをアップロード", + stopResponse: "応答を停止", + trace: "トレース", + viewTrace: "トレースを表示", + nextSteps: "次のステップ", + publishDrafts: "公開", + publishOk: "公開しました — オブジェクトが有効になりました。", + seedWarn: "公開しましたが、一部のサンプルデータを読み込めませんでした。", + openBuiltApp: "アプリを開く", + designBuiltApp: "Studio でデザイン", + previewDraft: "プレビュー", + previewApp: "アプリをプレビュー", + resizeSplit: "チャットとプレビューのサイズを変更", + hideChats: "チャットを隠す", + showChats: "チャットを表示", + planTitle: "提案されたプラン", + planQuestions: "ビルド前に確認", + planAssumptions: "前提", + planApproveHint: "返信してこのプランを承認または調整してください。", + planApprove: "ビルドする", + planAdjust: "調整", + justNow: "たった今", + minutesAgo: "{{count}} 分前", + hoursAgo: "{{count}} 時間前", + daysAgo: "{{count}} 日前", + agentLabels: { + ask: "質問", + build: "ビルド", + dataChat: "アシスタント", + metadataAssistant: "メタデータアシスタント", + }, + suggestions: { + dataChat: { + userCount: "システムには何人のユーザーがいますか?メールアドレスも一覧にしてください。", + recentRecords: "最近作成されたレコードを 5 件表示してください。", + recordCounts: "オブジェクトごとのレコード数を数えてください。", + }, + metadataAssistant: { + buildCrm: "営業 CRM を作って — 顧客、担当者、ステージ別に集計できる商談パイプライン。", + buildApp: "プロジェクト管理を作って — プロジェクト、担当者と期日つきのタスク、ステータス別ボード。", + buildFlow: "サポートデスクを設計して — 優先度つきチケット、ステータスのワークフロー、顧客との紐付け。", + buildInventory: "在庫管理アプリを作って — 商品、在庫数、仕入先、在庫僅少の可視化。", + buildRecruiting: "採用管理を作って — 候補者、募集職種、面接ステージ、メモ。", + }, + generic: { + help: "どんなことを手伝ってもらえますか?", + availableObjects: "利用できるデータオブジェクトを一覧にしてください。", + recentActivity: "最近の自分の活動を要約してください。", + }, + editApp: { + addField: "いずれかのオブジェクトに項目を追加してください。", + addObject: "新しいオブジェクトを追加し、既存のものと関連づけてください。", + addDashboard: "主要指標のダッシュボードを追加してください。", + addAutomation: "自動化を追加してください — 承認、ステータスフロー、または通知。", + }, + }, changesTitle: "変更の確認", changesConfirmed: "確認済み", changesConfirm: "変更を確定", changesConfirmHint: "返信してこの変更を確定または調整してください。", - changesConfirmMessage: "変更を確定します。提案された内容を適用してください。", changeVerb: { createObject: "オブジェクトを作成", addField: "項目を追加", @@ -915,6 +1088,7 @@ const ja = { toggleDarkMode: "ダークモードを切り替え", }, commandPalette: { + title: "コマンドパレット", placeholder: "コマンドを入力または検索...", noResults: "結果が見つかりません。", objects: "オブジェクト", @@ -948,6 +1122,14 @@ const ja = { system: "システム", }, objectView: { + viewTypeTree: "ツリー", + viewTypeTreeDesc: "親項目によって自己参照レコードを階層に入れ子にします。", + parentField: "親項目", + parentFieldHelp: "階層を定義する親レコード(同一オブジェクト)を指す項目です。自己参照の項目のみ指定できます。", + viewName: "名前", + viewNameHelp: "マシンキー(snake_case)。タイトルから自動入力されます — 必要に応じて編集してください。", + viewNameRequired: "キーを入力してください(英小文字、数字、アンダースコア)。ラテン文字以外のタイトルでは自動入力されません。", + viewNameInvalid: "英小文字、数字、アンダースコアを使用し、先頭は文字かアンダースコアにしてください。", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "オブジェクトが見つかりません", @@ -1419,10 +1601,54 @@ const ja = { removeFromFavorites: "お気に入りから {{name}} を削除", }, topbar: { + openAssistant: "{{name}} アシスタントを開く", + offline: "オフライン", + usersOnline: "現在オンラインのユーザー", + switchView: "ビューを切り替え", + switchObject: "オブジェクトを切り替え", + connection: { + connected: "接続済み", + connecting: "接続中...", + reconnecting: "再接続中...", + disconnected: "切断されました", + error: "接続エラー", + }, + stage: { + preview: "プレビュー", + beta: "ベータ", + tooltip: "このプラットフォームはプレビュー版です — 機能は変更される可能性があります。", + }, aiAssistant: "AI アシスタント", designInStudio: "Studio でデザイン", }, home: { + build: { + title: "アプリを作る", + subtitle: "ゼロから始める — オブジェクト、フォーム、自動化、画面を設計します。", + }, + template: { + title: "テンプレートから始める", + subtitle: "マーケットプレイスからテンプレートアプリをインストールしてカスタマイズします。", + }, + welcomeAdminDescription: "ビジネスを一文で説明してください — AI がオブジェクト、画面、API、エージェントツールを生成します。左のメニューから自分で設定することもできます。", + welcomeAdminDescriptionNoBuild: "左の管理メニューから最初のアプリケーションを設定してください。データが入ると、AI アシスタントが分析を手伝えます。", + welcomeAdminDescriptionNoAi: "左の管理メニューから最初のアプリケーションを設定してください。", + noAppsTitle: "アプリケーションがまだありません", + noAppsDescription: "ワークスペースを準備中です — 管理者が共有したアプリがここに表示されます。", + buildWithAI: "AI でビルド", + askAI: "AI に質問", + recoveryReminder: { + message: "シングルサインオンが利用できないときでもサインインできるよう、リカバリーパスワードを設定してください。", + cta: "パスワードを設定", + dismiss: "閉じる", + }, + pendingDrafts: { + message: "未公開の変更が {{count}} 件あります — 公開すると反映されます。", + cta: "公開", + publishing: "公開しています…", + published: "公開しました。変更が反映されています。", + publishFailed: "公開に失敗しました", + }, title: "ホーム", subtitle: "ワークスペースのダッシュボード", nav: "ホーム", @@ -1486,7 +1712,21 @@ const ja = { }, }, layout: { + systemNav: { + systemSettings: "システム設定", + applications: "アプリケーション", + appMarketplace: "アプリマーケットプレイス", + objectManager: "オブジェクトマネージャー", + users: "ユーザー", + organizations: "組織", + roles: "ロール", + configuration: "構成", + createApp: "アプリを作成", + }, appSwitcher: { + switchApplication: "アプリケーションを切り替え", + appsAvailable: "{{count}} 個のアプリが利用可能", + editNavigation: "ナビゲーションを編集", home: "ホーム", addApp: "アプリを追加", editApp: "アプリを編集", diff --git a/packages/i18n/src/locales/ko.ts b/packages/i18n/src/locales/ko.ts index a5be83cf4..45bf11676 100644 --- a/packages/i18n/src/locales/ko.ts +++ b/packages/i18n/src/locales/ko.ts @@ -854,12 +854,185 @@ const ko = { }, }, console: { + settingsHub: { + title: "설정", + subtitle: "워크스페이스, 연동, 기능 플래그를 구성합니다.", + loadError: "설정을 불러오지 못했습니다", + empty: "등록된 설정이 없습니다. 플러그인은 SettingsService를 통해 설정 매니페스트를 등록할 수 있습니다.", + settingsCount: "설정 {{n}}개", + beta: "베타", + categories: { + Workspace: "워크스페이스", + Communication: "커뮤니케이션", + Security: "보안", + Infrastructure: "인프라", + Beta: "베타", + Other: "기타", + }, + }, + objectData: { + badge: "데이터", + description: "URL로 정의된 데이터 구간 — 저장된 뷰에 연결되어 있지 않습니다.", + filteredBy: "필터 조건", + removeFilter: "필터 {{field}} 제거", + saveAsView: "뷰로 저장", + noAccessTitle: "접근이 거부되었습니다", + noAccess: "이 데이터를 볼 권한이 없습니다.", + }, + identityImport: { + policyTitle: "가져온 사용자의 로그인 설정", + policy: { + auto: "자동(권장)", + invite: "초대 보내기", + temporary: "임시 비밀번호", + none: "비밀번호 없음(ID만)", + }, + policyHint: { + auto: "연락 가능한 사용자에게는 초대(이메일 또는 SMS)를 보내고, 연락할 수 없는 사용자에게는 일회용 비밀번호를 발급해 결과 화면에 한 번만 표시합니다. 이메일/SMS 서비스 유무와 관계없이 동작합니다.", + invite: "생성된 모든 사용자에게 비밀번호 설정 이메일(전화번호만 있는 행에는 초대 SMS)을 보냅니다. 이메일/SMS 서비스 구성이 필요하며, 연락할 수 없는 행은 실패합니다.", + temporary: "이메일/SMS가 없는 환경용: 생성된 모든 사용자에게 일회용 비밀번호를 발급해 결과 화면에 한 번만 표시합니다. 첫 로그인 시 변경해야 합니다.", + none: "사용자는 먼저 전화 OTP, 매직 링크 또는 비밀번호 재설정 링크로 로그인한 뒤 직접 비밀번호를 설정합니다.", + }, + passwordsNote: "임시 비밀번호 — 한 번만 표시되며 저장되지 않습니다. 지금 저장하세요. 각 사용자는 첫 로그인 시 변경해야 합니다.", + passwordsMore: "이후 항목은 생략되었습니다 — 다운로드를 이용하세요.", + passwordsDownload: "CSV 다운로드", + }, ai: { + usage: { + title: "AI 사용량", + meterBuild: "빌드", + meterAsk: "질문", + statusOk: "여유가 충분합니다", + statusLow: "얼마 남지 않았습니다", + statusFull: "한도에 도달했습니다", + resetsDaily: "오늘 밤 초기화됩니다", + resetsMonthly: "다음 주기에 초기화됩니다", + ctaUpgrade: "업그레이드하고 계속하기", + ctaTopUp: "크레딧을 추가하고 계속하기", + ariaLabel: "AI 사용량: {{status}}", + }, + workspaceTitle: "AI 워크스페이스", + workspaceSubtitle: "질문하고, 살펴보고, 대화를 이어가세요", + openChats: "채팅 열기", + chats: "채팅", + chatsDescription: "AI 대화를 살펴보고 관리합니다.", + share: "공유", + shareTitle: "이 대화 공유", + shareDisabledTitle: "공유하려면 먼저 대화를 시작하세요", + newChat: "새로 만들기", + searchChats: "채팅 검색...", + noChatsYet: "아직 채팅이 없습니다", + noChatsDescription: "새 대화를 시작하면 여기에 표시됩니다.", + noMatchingChats: "일치하는 채팅이 없습니다.", + newConversation: "새 대화", + renameConversation: "대화 이름 변경", + deleteConversation: "대화 삭제", + saveRename: "이름 저장", + cancelRename: "이름 변경 취소", + loadingHistory: "대화 기록을 불러오는 중...", + conversationReady: "대화 준비 완료", + preparingConversation: "새 대화를 준비하는 중", + offlineDemoMode: "오프라인 데모 모드 — 에이전트 목록을 사용할 수 없습니다", + sendFailedRateLimited: "메시지를 너무 빠르게 보내고 있습니다. 메시지는 아래에 보관되어 있습니다 — 잠시 후 다시 시도하세요.", + sendFailedGeneric: "메시지를 보내지 못했습니다. 아래에 보관되어 있습니다 — 다시 시도해 주세요.", + askAgent: "{{agent}}에게 질문...", + assistant: "어시스턴트", + liveCanvas: "실시간 미리보기 — {{app}}(초안)", + liveCanvasUnlisted: "실시간 앱 — {{app}}(게시 전까지 비공개)", + loadingAgents: "에이전트를 불러오는 중...", + askAnything: "무엇이든 물어보세요...", + emptyTitle: "대화 시작하기", + emptyDescription: "무엇이든 물어보세요 — 어시스턴트는 현재 앱 컨텍스트에 접근할 수 있습니다.", + switchAssistant: "어시스턴트 전환", + chooseAgent: "어시스턴트 선택…", + empty: { + build: { + title: "AI로 빌드", + description: "앱이나 워크플로를 일상 언어로 설명해 주세요 — 객체, 화면, 자동화를 초안으로 만들어 드리면 검토 후 게시하시면 됩니다.", + }, + ask: { + title: "데이터에 질문하기", + description: "레코드에 대해 질문하세요 — 접근 가능한 데이터의 개수, 목록, 요약을 알려 드립니다.", + }, + editApp: { + title: "“{{app}}” 편집 중", + titleGeneric: "이 앱 편집", + description: "무엇을 바꿀까요? 이 앱을 그 자리에서 수정합니다 — 필드, 객체, 뷰, 자동화를 추가하거나 기존 내용을 조정할 수 있습니다.", + }, + }, + clearConversation: "지우기", + sendHint: "눌러 전송", + agentActivity: "에이전트 활동", + toolCompleted: "완료됨", + toolRunning: "실행 중", + toolAwaitingApproval: "승인 대기 중", + toolFailed: "실패", + toolDetailsHidden: "이 보기에서는 도구 입력과 원본 결과가 숨겨집니다.", + copy: "복사", + copied: "복사됨", + regenerate: "다시 생성", + model: "모델", + submit: "보내기", + uploadFiles: "파일 업로드", + stopResponse: "응답 중지", + trace: "추적", + viewTrace: "추적 보기", + nextSteps: "다음 단계", + publishDrafts: "게시", + publishOk: "게시했습니다 — 객체가 이제 활성화되었습니다.", + seedWarn: "게시했지만 일부 샘플 데이터를 불러오지 못했습니다.", + openBuiltApp: "앱 열기", + designBuiltApp: "Studio에서 디자인", + previewDraft: "미리보기", + previewApp: "앱 미리보기", + resizeSplit: "채팅과 미리보기 크기 조정", + hideChats: "채팅 숨기기", + showChats: "채팅 표시", + planTitle: "제안된 계획", + planQuestions: "빌드 전에 확인", + planAssumptions: "가정", + planApproveHint: "회신하여 이 계획을 승인하거나 조정하세요.", + planApprove: "빌드하기", + planAdjust: "조정", + justNow: "방금", + minutesAgo: "{{count}}분 전", + hoursAgo: "{{count}}시간 전", + daysAgo: "{{count}}일 전", + agentLabels: { + ask: "질문", + build: "빌드", + dataChat: "어시스턴트", + metadataAssistant: "메타데이터 어시스턴트", + }, + suggestions: { + dataChat: { + userCount: "시스템에 사용자가 몇 명인가요? 이메일도 나열해 주세요.", + recentRecords: "가장 최근에 생성된 레코드 5건을 보여 주세요.", + recordCounts: "객체별 레코드 수를 세어 주세요.", + }, + metadataAssistant: { + buildCrm: "영업 CRM을 만들어 줘 — 고객, 담당자, 단계별로 합계를 낼 수 있는 거래 파이프라인.", + buildApp: "프로젝트 트래커를 만들어 줘 — 프로젝트, 담당자와 마감일이 있는 작업, 상태별 보드.", + buildFlow: "고객 지원 데스크를 설계해 줘 — 우선순위가 있는 티켓, 상태 워크플로, 고객 연결.", + buildInventory: "재고 앱을 만들어 줘 — 제품, 재고 수량, 공급업체, 재고 부족 표시.", + buildRecruiting: "채용 트래커를 만들어 줘 — 지원자, 채용 중인 직무, 면접 단계, 메모.", + }, + generic: { + help: "무엇을 도와줄 수 있나요?", + availableObjects: "사용 가능한 데이터 객체를 나열해 주세요.", + recentActivity: "내 최근 활동을 요약해 주세요.", + }, + editApp: { + addField: "객체 중 하나에 필드를 추가해 주세요.", + addObject: "새 객체를 추가하고 기존 객체와 연결해 주세요.", + addDashboard: "핵심 지표를 위한 대시보드를 추가해 주세요.", + addAutomation: "자동화를 추가해 주세요 — 승인, 상태 흐름 또는 알림.", + }, + }, changesTitle: "변경 확인", changesConfirmed: "확인됨", changesConfirm: "변경 확정", changesConfirmHint: "회신하여 이 변경을 확정하거나 조정하세요.", - changesConfirmMessage: "변경을 확정합니다. 방금 제안한 내용을 적용해 주세요.", changeVerb: { createObject: "객체 생성", addField: "필드 추가", @@ -915,6 +1088,7 @@ const ko = { toggleDarkMode: "다크 모드 전환", }, commandPalette: { + title: "명령 팔레트", placeholder: "명령어를 입력하거나 검색...", noResults: "결과를 찾을 수 없습니다.", objects: "객체", @@ -948,6 +1122,14 @@ const ko = { system: "시스템", }, objectView: { + viewTypeTree: "트리", + viewTypeTreeDesc: "상위 필드를 기준으로 자기 참조 레코드를 계층 구조로 중첩합니다.", + parentField: "상위 필드", + parentFieldHelp: "계층 구조를 정의하는 상위 레코드(같은 객체)를 가리키는 필드입니다. 자기 참조 필드만 사용할 수 있습니다.", + viewName: "이름", + viewNameHelp: "머신 키(snake_case)입니다. 제목에서 자동으로 채워집니다 — 원하면 수정하세요.", + viewNameRequired: "키를 입력하세요(소문자, 숫자, 밑줄). 비라틴 문자 제목에서는 자동으로 채워지지 않습니다.", + viewNameInvalid: "소문자, 숫자, 밑줄을 사용하고 문자 또는 밑줄로 시작하세요.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "객체를 찾을 수 없음", @@ -1419,10 +1601,54 @@ const ko = { removeFromFavorites: "즐겨찾기에서 {{name}} 제거", }, topbar: { + openAssistant: "{{name}} 어시스턴트 열기", + offline: "오프라인", + usersOnline: "현재 접속 중인 사용자", + switchView: "뷰 전환", + switchObject: "객체 전환", + connection: { + connected: "연결됨", + connecting: "연결 중...", + reconnecting: "다시 연결 중...", + disconnected: "연결 끊김", + error: "연결 오류", + }, + stage: { + preview: "미리보기", + beta: "베타", + tooltip: "이 플랫폼은 미리보기 단계입니다 — 기능이 변경될 수 있습니다.", + }, aiAssistant: "AI 어시스턴트", designInStudio: "Studio에서 디자인", }, home: { + build: { + title: "앱 만들기", + subtitle: "처음부터 시작 — 객체, 폼, 자동화, 인터페이스를 설계합니다.", + }, + template: { + title: "템플릿으로 시작", + subtitle: "마켓플레이스에서 템플릿 앱을 설치하고 원하는 대로 바꾸세요.", + }, + welcomeAdminDescription: "비즈니스를 한 문장으로 설명해 주세요 — AI가 객체, 화면, API, 에이전트 도구를 생성합니다. 왼쪽 메뉴에서 직접 설정할 수도 있습니다.", + welcomeAdminDescriptionNoBuild: "왼쪽 관리 메뉴에서 첫 애플리케이션을 설정하세요. 데이터가 쌓이면 AI 어시스턴트가 살펴보는 것을 도와줍니다.", + welcomeAdminDescriptionNoAi: "왼쪽 관리 메뉴에서 첫 애플리케이션을 설정하세요.", + noAppsTitle: "아직 애플리케이션이 없습니다", + noAppsDescription: "워크스페이스를 준비하고 있습니다 — 관리자가 공유한 앱이 여기에 표시됩니다.", + buildWithAI: "AI로 빌드", + askAI: "AI에게 질문", + recoveryReminder: { + message: "싱글 사인온을 사용할 수 없을 때도 로그인할 수 있도록 복구 비밀번호를 설정하세요.", + cta: "비밀번호 설정", + dismiss: "닫기", + }, + pendingDrafts: { + message: "게시되지 않은 변경이 {{count}}건 있습니다 — 게시하면 반영됩니다.", + cta: "게시", + publishing: "게시하는 중…", + published: "게시했습니다! 변경 사항이 반영되었습니다.", + publishFailed: "게시에 실패했습니다", + }, title: "홈", subtitle: "워크스페이스 대시보드", nav: "홈", @@ -1486,7 +1712,21 @@ const ko = { }, }, layout: { + systemNav: { + systemSettings: "시스템 설정", + applications: "애플리케이션", + appMarketplace: "앱 마켓플레이스", + objectManager: "객체 관리자", + users: "사용자", + organizations: "조직", + roles: "역할", + configuration: "구성", + createApp: "앱 만들기", + }, appSwitcher: { + switchApplication: "애플리케이션 전환", + appsAvailable: "사용 가능한 앱 {{count}}개", + editNavigation: "내비게이션 편집", home: "홈", addApp: "앱 추가", editApp: "앱 편집", diff --git a/packages/i18n/src/locales/pt.ts b/packages/i18n/src/locales/pt.ts index 3a48bfcc8..b97eb17c2 100644 --- a/packages/i18n/src/locales/pt.ts +++ b/packages/i18n/src/locales/pt.ts @@ -852,12 +852,185 @@ const pt = { }, }, console: { + settingsHub: { + title: "Configurações", + subtitle: "Configure seu workspace, integrações e sinalizadores de recursos.", + loadError: "Falha ao carregar as configurações", + empty: "Nenhuma configuração registrada. Os plugins podem registrar manifestos de configuração pelo SettingsService.", + settingsCount: "{{n}} configurações", + beta: "Beta", + categories: { + Workspace: "Workspace", + Communication: "Comunicação", + Security: "Segurança", + Infrastructure: "Infraestrutura", + Beta: "Beta", + Other: "Outros", + }, + }, + objectData: { + badge: "Dados", + description: "Recorte de dados definido pela URL — não vinculado a nenhuma visão salva.", + filteredBy: "Filtrado por", + removeFilter: "Remover o filtro {{field}}", + saveAsView: "Salvar como visão", + noAccessTitle: "Acesso negado", + noAccess: "Você não tem permissão para ver estes dados.", + }, + identityImport: { + policyTitle: "Configuração de acesso para usuários importados", + policy: { + auto: "Automático (recomendado)", + invite: "Enviar convites", + temporary: "Senhas temporárias", + none: "Sem senha (apenas identidade)", + }, + policyHint: { + auto: "Usuários acessíveis recebem um convite (e-mail ou SMS); quem não puder ser contatado recebe uma senha de uso único, exibida UMA ÚNICA VEZ na tela de resultados. Funciona com ou sem serviço de e-mail/SMS.", + invite: "Cada usuário criado recebe um e-mail para definir a senha (ou um SMS de convite nas linhas apenas com telefone). Requer um serviço de e-mail/SMS configurado — linhas inacessíveis falham.", + temporary: "Para implantações sem e-mail/SMS: cada usuário criado recebe uma senha de uso único, exibida UMA ÚNICA VEZ na tela de resultados. O primeiro acesso exige a troca.", + none: "Os usuários entram primeiro com um OTP por telefone, um link mágico ou um link de redefinição, e depois definem a própria senha.", + }, + passwordsNote: "Senhas temporárias — exibidas uma única vez, nunca armazenadas. Salve-as agora; cada usuário deve trocar a sua no primeiro acesso.", + passwordsMore: "Demais entradas omitidas — use o download.", + passwordsDownload: "Baixar CSV", + }, ai: { + usage: { + title: "Uso de IA", + meterBuild: "Criar", + meterAsk: "Perguntar", + statusOk: "Ainda há bastante", + statusLow: "Está acabando", + statusFull: "Limite atingido", + resetsDaily: "Redefine hoje à noite", + resetsMonthly: "Redefine no próximo ciclo", + ctaUpgrade: "Faça upgrade para continuar", + ctaTopUp: "Adicione créditos para continuar", + ariaLabel: "Uso de IA: {{status}}", + }, + workspaceTitle: "Workspace de IA", + workspaceSubtitle: "Pergunte, inspecione e retome conversas", + openChats: "Abrir conversas", + chats: "Conversas", + chatsDescription: "Navegue e gerencie as conversas com a IA.", + share: "Compartilhar", + shareTitle: "Compartilhar esta conversa", + shareDisabledTitle: "Comece a conversar para habilitar o compartilhamento", + newChat: "Nova", + searchChats: "Pesquisar conversas...", + noChatsYet: "Ainda não há conversas", + noChatsDescription: "Inicie uma nova conversa para vê-la aqui.", + noMatchingChats: "Nenhuma conversa correspondente.", + newConversation: "Nova conversa", + renameConversation: "Renomear conversa", + deleteConversation: "Excluir conversa", + saveRename: "Salvar novo nome", + cancelRename: "Cancelar renomeação", + loadingHistory: "Carregando o histórico da conversa...", + conversationReady: "Conversa pronta", + preparingConversation: "Preparando uma nova conversa", + offlineDemoMode: "Modo de demonstração off-line — lista de agentes indisponível", + sendFailedRateLimited: "Você está enviando mensagens rápido demais. Sua mensagem foi mantida abaixo — aguarde um momento e tente novamente.", + sendFailedGeneric: "Não foi possível enviar sua mensagem. Ela foi mantida abaixo — tente novamente.", + askAgent: "Pergunte a {{agent}}...", + assistant: "Assistente", + liveCanvas: "Pré-visualização ao vivo — {{app}} (rascunho)", + liveCanvasUnlisted: "Aplicativo ao vivo — {{app}} (não listado até ser publicado)", + loadingAgents: "Carregando agentes...", + askAnything: "Pergunte qualquer coisa...", + emptyTitle: "Iniciar uma conversa", + emptyDescription: "Pergunte qualquer coisa — o assistente tem acesso ao contexto do seu aplicativo atual.", + switchAssistant: "Trocar de assistente", + chooseAgent: "Escolher assistente…", + empty: { + build: { + title: "Criar com IA", + description: "Descreva um aplicativo ou fluxo de trabalho em linguagem simples — eu rascunho os objetos, telas e automações, e então você revisa e publica.", + }, + ask: { + title: "Pergunte aos seus dados", + description: "Faça perguntas sobre seus registros — contagens, listas e resumos dos dados a que você tem acesso.", + }, + editApp: { + title: "Editando “{{app}}”", + titleGeneric: "Editar este aplicativo", + description: "O que você quer mudar? Eu altero este aplicativo no lugar — adicionar um campo, objeto, visão ou automação, ou ajustar o que já existe.", + }, + }, + clearConversation: "Limpar", + sendHint: "para enviar", + agentActivity: "Atividade do agente", + toolCompleted: "Concluído", + toolRunning: "Em execução", + toolAwaitingApproval: "Aguardando aprovação", + toolFailed: "Falhou", + toolDetailsHidden: "As entradas das ferramentas e os resultados brutos estão ocultos nesta visão.", + copy: "Copiar", + copied: "Copiado", + regenerate: "Gerar novamente", + model: "Modelo", + submit: "Enviar", + uploadFiles: "Enviar arquivos", + stopResponse: "Parar a resposta", + trace: "rastro", + viewTrace: "Ver o rastro", + nextSteps: "Próximos passos", + publishDrafts: "Publicar", + publishOk: "Publicado — os objetos já estão ativos.", + seedWarn: "Publicado, mas alguns dados de exemplo não puderam ser carregados.", + openBuiltApp: "Abrir o aplicativo", + designBuiltApp: "Projetar no Studio", + previewDraft: "Pré-visualizar", + previewApp: "Pré-visualizar o aplicativo", + resizeSplit: "Redimensionar a conversa e a pré-visualização", + hideChats: "Ocultar conversas", + showChats: "Mostrar conversas", + planTitle: "Plano proposto", + planQuestions: "Confirmar antes de criar", + planAssumptions: "Suposições", + planApproveHint: "Responda para aprovar ou ajustar este plano.", + planApprove: "Criar", + planAdjust: "Ajustar", + justNow: "agora mesmo", + minutesAgo: "há {{count}} min", + hoursAgo: "há {{count}} h", + daysAgo: "há {{count}} d", + agentLabels: { + ask: "Perguntar", + build: "Criar", + dataChat: "Assistente", + metadataAssistant: "Assistente de metadados", + }, + suggestions: { + dataChat: { + userCount: "Quantos usuários existem no sistema? Liste os e-mails deles.", + recentRecords: "Liste os 5 registros criados mais recentemente.", + recordCounts: "Conte os registros de cada objeto.", + }, + metadataAssistant: { + buildCrm: "Crie um CRM de vendas — clientes, contatos e um funil de negócios que eu possa totalizar por etapa.", + buildApp: "Crie um controle de projetos — projetos, tarefas com responsáveis e prazos, e um quadro por status.", + buildFlow: "Projete uma central de suporte — chamados com prioridade, um fluxo de status e vínculos com clientes.", + buildInventory: "Crie um aplicativo de estoque — produtos, níveis de estoque, fornecedores e visibilidade de estoque baixo.", + buildRecruiting: "Crie um controle de candidaturas — candidatos, vagas abertas, etapas de entrevista e anotações.", + }, + generic: { + help: "Com o que você pode me ajudar?", + availableObjects: "Liste os objetos de dados disponíveis.", + recentActivity: "Resuma minha atividade recente.", + }, + editApp: { + addField: "Adicione um campo a um dos objetos.", + addObject: "Adicione um novo objeto e relacione-o a um existente.", + addDashboard: "Adicione um painel para as métricas principais.", + addAutomation: "Adicione uma automação — uma aprovação, um fluxo de status ou uma notificação.", + }, + }, changesTitle: "Confirmar alterações", changesConfirmed: "Confirmado", changesConfirm: "Confirmar", changesConfirmHint: "Responda para confirmar ou ajustar esta alteração.", - changesConfirmMessage: "Alterações confirmadas — aplique o que você acabou de propor.", changeVerb: { createObject: "Criar objeto", addField: "Adicionar campo", @@ -913,6 +1086,7 @@ const pt = { toggleDarkMode: "Alternar modo escuro", }, commandPalette: { + title: "Paleta de comandos", placeholder: "Digite um comando ou pesquise...", noResults: "Nenhum resultado encontrado.", objects: "Objetos", @@ -946,6 +1120,14 @@ const pt = { system: "Sistema", }, objectView: { + viewTypeTree: "Árvore", + viewTypeTreeDesc: "Aninha registros autorreferenciados em uma hierarquia por um campo pai.", + parentField: "Campo pai", + parentFieldHelp: "O campo que aponta para o registro pai (mesmo objeto) e define a hierarquia. Apenas campos autorreferenciados são válidos.", + viewName: "Nome", + viewNameHelp: "Chave técnica (snake_case). Preenchida automaticamente a partir do título — edite se quiser.", + viewNameRequired: "Informe uma chave (letras minúsculas, números, sublinhado). Não é preenchida automaticamente para títulos não latinos.", + viewNameInvalid: "Use letras minúsculas, números e sublinhados; comece com uma letra ou sublinhado.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "Objeto não encontrado", @@ -1417,10 +1599,54 @@ const pt = { removeFromFavorites: "Remover {{name}} dos favoritos", }, topbar: { + openAssistant: "Abrir o assistente {{name}}", + offline: "Off-line", + usersOnline: "Usuários on-line no momento", + switchView: "Trocar de visão", + switchObject: "Trocar de objeto", + connection: { + connected: "Conectado", + connecting: "Conectando...", + reconnecting: "Reconectando...", + disconnected: "Desconectado", + error: "Erro de conexão", + }, + stage: { + preview: "Pré-visualização", + beta: "Beta", + tooltip: "Esta plataforma está em pré-visualização — os recursos podem mudar.", + }, aiAssistant: "Assistente de IA", designInStudio: "Projetar no Studio", }, home: { + build: { + title: "Criar um aplicativo", + subtitle: "Comece do zero — projete objetos, formulários, automações e interfaces.", + }, + template: { + title: "Comece com um modelo", + subtitle: "Instale um aplicativo modelo do marketplace e personalize-o.", + }, + welcomeAdminDescription: "Descreva seu negócio em uma frase — a IA gera os objetos, as telas, as APIs e as ferramentas do agente. Ou configure você mesmo pelo menu à esquerda.", + welcomeAdminDescriptionNoBuild: "Configure seu primeiro aplicativo pelo menu de Administração à esquerda. Quando houver dados, o assistente de IA poderá ajudar a explorá-los.", + welcomeAdminDescriptionNoAi: "Configure seu primeiro aplicativo pelo menu de Administração à esquerda.", + noAppsTitle: "Ainda não há aplicativos", + noAppsDescription: "Seu workspace está sendo preparado — os aplicativos que seu administrador compartilhar aparecerão aqui.", + buildWithAI: "Criar com IA", + askAI: "Perguntar à IA", + recoveryReminder: { + message: "Defina uma senha de recuperação para conseguir entrar mesmo que o logon único fique indisponível.", + cta: "Definir senha", + dismiss: "Dispensar", + }, + pendingDrafts: { + message: "Você tem {{count}} alteração(ões) não publicada(s) — publique para ativá-las.", + cta: "Publicar", + publishing: "Publicando…", + published: "Publicado! Suas alterações estão ativas.", + publishFailed: "Falha ao publicar", + }, title: "Início", subtitle: "Painel do seu espaço de trabalho", nav: "Início", @@ -1484,7 +1710,21 @@ const pt = { }, }, layout: { + systemNav: { + systemSettings: "Configurações do sistema", + applications: "Aplicativos", + appMarketplace: "Marketplace de aplicativos", + objectManager: "Gerenciador de objetos", + users: "Usuários", + organizations: "Organizações", + roles: "Perfis", + configuration: "Configuração", + createApp: "Criar aplicativo", + }, appSwitcher: { + switchApplication: "Trocar de aplicativo", + appsAvailable: "{{count}} aplicativos disponíveis", + editNavigation: "Editar a navegação", home: "Início", addApp: "Adicionar aplicativo", editApp: "Editar aplicativo", diff --git a/packages/i18n/src/locales/ru.ts b/packages/i18n/src/locales/ru.ts index ec44e3291..29ed37fde 100644 --- a/packages/i18n/src/locales/ru.ts +++ b/packages/i18n/src/locales/ru.ts @@ -852,12 +852,185 @@ const ru = { }, }, console: { + settingsHub: { + title: "Настройки", + subtitle: "Настройте рабочее пространство, интеграции и флаги функций.", + loadError: "Не удалось загрузить настройки", + empty: "Настройки не зарегистрированы. Плагины могут регистрировать манифесты настроек через SettingsService.", + settingsCount: "Настроек: {{n}}", + beta: "Бета", + categories: { + Workspace: "Рабочее пространство", + Communication: "Коммуникации", + Security: "Безопасность", + Infrastructure: "Инфраструктура", + Beta: "Бета", + Other: "Прочее", + }, + }, + objectData: { + badge: "Данные", + description: "Срез данных, заданный URL — не привязан к сохранённому представлению.", + filteredBy: "Фильтр", + removeFilter: "Убрать фильтр {{field}}", + saveAsView: "Сохранить как представление", + noAccessTitle: "Доступ запрещён", + noAccess: "У вас нет прав на просмотр этих данных.", + }, + identityImport: { + policyTitle: "Настройка входа для импортированных пользователей", + policy: { + auto: "Автоматически (рекомендуется)", + invite: "Отправить приглашения", + temporary: "Временные пароли", + none: "Без пароля (только учётная запись)", + }, + policyHint: { + auto: "Доступным пользователям отправляется приглашение (по почте или SMS); тем, до кого не удалось дозвониться, выдаётся одноразовый пароль, который показывается ОДИН РАЗ на экране результата. Работает как с сервисом почты/SMS, так и без него.", + invite: "Каждый созданный пользователь получает письмо для установки пароля (или SMS-приглашение для строк только с телефоном). Требуется настроенный сервис почты/SMS — недоступные строки завершатся ошибкой.", + temporary: "Для развёртываний без почты/SMS: каждый созданный пользователь получает одноразовый пароль, который показывается ОДИН РАЗ на экране результата. При первом входе потребуется его сменить.", + none: "Пользователи сначала входят по OTP на телефон, магической ссылке или ссылке сброса пароля, а затем задают собственный пароль.", + }, + passwordsNote: "Временные пароли — показываются один раз и нигде не сохраняются. Сохраните их сейчас; каждый пользователь должен сменить свой при первом входе.", + passwordsMore: "Остальные записи опущены — воспользуйтесь загрузкой файла.", + passwordsDownload: "Скачать CSV", + }, ai: { + usage: { + title: "Использование ИИ", + meterBuild: "Сборка", + meterAsk: "Вопрос", + statusOk: "Осталось много", + statusLow: "Заканчивается", + statusFull: "Лимит исчерпан", + resetsDaily: "Сбросится сегодня ночью", + resetsMonthly: "Сбросится в следующем цикле", + ctaUpgrade: "Повысьте тариф, чтобы продолжить", + ctaTopUp: "Добавьте кредиты, чтобы продолжить", + ariaLabel: "Использование ИИ: {{status}}", + }, + workspaceTitle: "Рабочее пространство ИИ", + workspaceSubtitle: "Задавайте вопросы, изучайте и возвращайтесь к диалогам", + openChats: "Открыть чаты", + chats: "Чаты", + chatsDescription: "Просматривайте диалоги с ИИ и управляйте ими.", + share: "Поделиться", + shareTitle: "Поделиться этим диалогом", + shareDisabledTitle: "Начните диалог, чтобы включить публикацию", + newChat: "Создать", + searchChats: "Поиск по чатам...", + noChatsYet: "Чатов пока нет", + noChatsDescription: "Начните новый диалог, и он появится здесь.", + noMatchingChats: "Подходящих чатов нет.", + newConversation: "Новый диалог", + renameConversation: "Переименовать диалог", + deleteConversation: "Удалить диалог", + saveRename: "Сохранить название", + cancelRename: "Отменить переименование", + loadingHistory: "Загрузка истории диалога...", + conversationReady: "Диалог готов", + preparingConversation: "Подготовка нового диалога", + offlineDemoMode: "Автономный демонстрационный режим — список агентов недоступен", + sendFailedRateLimited: "Вы отправляете сообщения слишком часто. Ваше сообщение сохранено ниже — подождите немного и попробуйте снова.", + sendFailedGeneric: "Не удалось отправить сообщение. Оно сохранено ниже — попробуйте ещё раз.", + askAgent: "Спросить {{agent}}...", + assistant: "Ассистент", + liveCanvas: "Живой предпросмотр — {{app}} (черновик)", + liveCanvasUnlisted: "Работающее приложение — {{app}} (скрыто до публикации)", + loadingAgents: "Загрузка агентов...", + askAnything: "Спросите о чём угодно...", + emptyTitle: "Начните диалог", + emptyDescription: "Спросите о чём угодно — ассистент видит контекст вашего текущего приложения.", + switchAssistant: "Сменить ассистента", + chooseAgent: "Выберите ассистента…", + empty: { + build: { + title: "Создать с помощью ИИ", + description: "Опишите приложение или процесс обычными словами — я подготовлю объекты, экраны и автоматизации, а вы проверите и опубликуете.", + }, + ask: { + title: "Спросите свои данные", + description: "Задавайте вопросы о записях — количество, списки и сводки по доступным вам данным.", + }, + editApp: { + title: "Редактирование «{{app}}»", + titleGeneric: "Редактировать это приложение", + description: "Что нужно изменить? Я изменю это приложение на месте — добавлю поле, объект, представление или автоматизацию либо скорректирую существующее.", + }, + }, + clearConversation: "Очистить", + sendHint: "чтобы отправить", + agentActivity: "Активность агента", + toolCompleted: "Завершено", + toolRunning: "Выполняется", + toolAwaitingApproval: "Ожидает подтверждения", + toolFailed: "Ошибка", + toolDetailsHidden: "Входные данные инструментов и необработанные результаты в этом режиме скрыты.", + copy: "Копировать", + copied: "Скопировано", + regenerate: "Сгенерировать заново", + model: "Модель", + submit: "Отправить", + uploadFiles: "Загрузить файлы", + stopResponse: "Остановить ответ", + trace: "трассировка", + viewTrace: "Посмотреть трассировку", + nextSteps: "Что дальше", + publishDrafts: "Опубликовать", + publishOk: "Опубликовано — объекты активны.", + seedWarn: "Опубликовано, но часть примеров данных загрузить не удалось.", + openBuiltApp: "Открыть приложение", + designBuiltApp: "Открыть в Studio", + previewDraft: "Предпросмотр", + previewApp: "Предпросмотр приложения", + resizeSplit: "Изменить размер чата и предпросмотра", + hideChats: "Скрыть чаты", + showChats: "Показать чаты", + planTitle: "Предложенный план", + planQuestions: "Подтвердите перед сборкой", + planAssumptions: "Допущения", + planApproveHint: "Ответьте, чтобы утвердить или скорректировать этот план.", + planApprove: "Собрать", + planAdjust: "Скорректировать", + justNow: "только что", + minutesAgo: "{{count}} мин назад", + hoursAgo: "{{count}} ч назад", + daysAgo: "{{count}} дн назад", + agentLabels: { + ask: "Вопрос", + build: "Сборка", + dataChat: "Ассистент", + metadataAssistant: "Ассистент по метаданным", + }, + suggestions: { + dataChat: { + userCount: "Сколько пользователей в системе? Перечисли их адреса электронной почты.", + recentRecords: "Перечисли 5 последних созданных записей.", + recordCounts: "Посчитай количество записей по каждому объекту.", + }, + metadataAssistant: { + buildCrm: "Создай CRM для продаж — клиенты, контакты и воронка сделок с итогами по этапам.", + buildApp: "Создай трекер проектов — проекты, задачи с ответственными и сроками, доска по статусам.", + buildFlow: "Спроектируй службу поддержки — заявки с приоритетом, процесс статусов и связи с клиентами.", + buildInventory: "Создай приложение для склада — товары, остатки, поставщики и индикация низких остатков.", + buildRecruiting: "Создай трекер кандидатов — кандидаты, открытые вакансии, этапы собеседований и заметки.", + }, + generic: { + help: "Чем ты можешь мне помочь?", + availableObjects: "Перечисли доступные объекты данных.", + recentActivity: "Сделай сводку моей недавней активности.", + }, + editApp: { + addField: "Добавь поле в один из объектов.", + addObject: "Добавь новый объект и свяжи его с существующим.", + addDashboard: "Добавь дашборд с ключевыми показателями.", + addAutomation: "Добавь автоматизацию — согласование, процесс статусов или уведомление.", + }, + }, changesTitle: "Подтвердите изменения", changesConfirmed: "Подтверждено", changesConfirm: "Подтвердить", changesConfirmHint: "Ответьте, чтобы подтвердить или скорректировать это изменение.", - changesConfirmMessage: "Изменения подтверждены — примени то, что ты только что предложил.", changeVerb: { createObject: "Создать объект", addField: "Добавить поле", @@ -913,6 +1086,7 @@ const ru = { toggleDarkMode: "Переключить тёмный режим", }, commandPalette: { + title: "Палитра команд", placeholder: "Введите команду или поиск...", noResults: "Результаты не найдены.", objects: "Объекты", @@ -946,6 +1120,14 @@ const ru = { system: "Системная", }, objectView: { + viewTypeTree: "Дерево", + viewTypeTreeDesc: "Выстраивает самоссылающиеся записи в иерархию по родительскому полю.", + parentField: "Родительское поле", + parentFieldHelp: "Поле, указывающее на родительскую запись (тот же объект) и задающее иерархию. Подходят только самоссылающиеся поля.", + viewName: "Название", + viewNameHelp: "Машинный ключ (snake_case). Заполняется автоматически из заголовка — при желании измените.", + viewNameRequired: "Введите ключ (строчные буквы, цифры, подчёркивание). Для нелатинских заголовков автозаполнение не работает.", + viewNameInvalid: "Используйте строчные латинские буквы, цифры и подчёркивания; начните с буквы или подчёркивания.", systemViewReadonly: 'System view defined in code - duplicate to customize.', expandToPage: 'Open as full page', objectNotFound: "Объект не найден", @@ -1417,10 +1599,54 @@ const ru = { removeFromFavorites: "Убрать {{name}} из избранного", }, topbar: { + openAssistant: "Открыть ассистента {{name}}", + offline: "Не в сети", + usersOnline: "Пользователи сейчас в сети", + switchView: "Сменить представление", + switchObject: "Сменить объект", + connection: { + connected: "Подключено", + connecting: "Подключение...", + reconnecting: "Переподключение...", + disconnected: "Отключено", + error: "Ошибка подключения", + }, + stage: { + preview: "Предварительная версия", + beta: "Бета", + tooltip: "Платформа в предварительной версии — функции могут измениться.", + }, aiAssistant: "ИИ-ассистент", designInStudio: "Дизайн в Studio", }, home: { + build: { + title: "Создать приложение", + subtitle: "Начните с нуля — спроектируйте объекты, формы, автоматизации и интерфейсы.", + }, + template: { + title: "Начать с шаблона", + subtitle: "Установите шаблонное приложение из маркетплейса и настройте его под себя.", + }, + welcomeAdminDescription: "Опишите свой бизнес одним предложением — ИИ создаст объекты, экраны, API и инструменты агента. Либо настройте всё сами через меню слева.", + welcomeAdminDescriptionNoBuild: "Настройте первое приложение через меню «Администрирование» слева. Когда появятся данные, ИИ-ассистент поможет их изучить.", + welcomeAdminDescriptionNoAi: "Настройте первое приложение через меню «Администрирование» слева.", + noAppsTitle: "Приложений пока нет", + noAppsDescription: "Ваше рабочее пространство настраивается — приложения, которыми поделится администратор, появятся здесь.", + buildWithAI: "Создать с помощью ИИ", + askAI: "Спросить ИИ", + recoveryReminder: { + message: "Задайте резервный пароль, чтобы входить в систему даже когда единый вход недоступен.", + cta: "Задать пароль", + dismiss: "Закрыть", + }, + pendingDrafts: { + message: "У вас {{count}} неопубликованных изменений — опубликуйте их, чтобы они вступили в силу.", + cta: "Опубликовать", + publishing: "Публикация…", + published: "Опубликовано! Изменения вступили в силу.", + publishFailed: "Не удалось опубликовать", + }, title: "Главная", subtitle: "Панель вашего рабочего пространства", nav: "Главная", @@ -1484,7 +1710,21 @@ const ru = { }, }, layout: { + systemNav: { + systemSettings: "Системные настройки", + applications: "Приложения", + appMarketplace: "Маркетплейс приложений", + objectManager: "Менеджер объектов", + users: "Пользователи", + organizations: "Организации", + roles: "Роли", + configuration: "Конфигурация", + createApp: "Создать приложение", + }, appSwitcher: { + switchApplication: "Сменить приложение", + appsAvailable: "Доступно приложений: {{count}}", + editNavigation: "Изменить навигацию", home: "Главная", addApp: "Добавить приложение", editApp: "Редактировать приложение",