diff --git a/apps/web/languine.config.ts b/apps/web/languine.config.ts
index 7f081eb..f14ffbb 100644
--- a/apps/web/languine.config.ts
+++ b/apps/web/languine.config.ts
@@ -3,7 +3,7 @@ import { defineConfig } from "languine";
export default defineConfig({
locale: {
source: "en",
- targets: ["es", "fr", "de", "ja", "zh", "ar", "ko", "sv", "no", "fi", "pt"],
+ targets: ["es"],
},
files: {
ts: {
diff --git a/apps/web/src/components/onboarding-steps.tsx b/apps/web/src/components/onboarding-steps.tsx
index 69d773a..b73a3ee 100644
--- a/apps/web/src/components/onboarding-steps.tsx
+++ b/apps/web/src/components/onboarding-steps.tsx
@@ -71,7 +71,7 @@ export function OnboardingSteps() {
diff --git a/apps/web/src/locales/ar.ts b/apps/web/src/locales/ar.ts
deleted file mode 100644
index b91a8d3..0000000
--- a/apps/web/src/locales/ar.ts
+++ /dev/null
@@ -1,302 +0,0 @@
-export default {
- header: {
- pricing: "التسعير",
- docs: "الوثائق",
- signIn: "تسجيل الدخول",
- goToApp: "الذهاب إلى التطبيق",
- },
- hero: {
- title: "ترجمة آلية لتطبيقاتك",
- description:
- "قم بتبسيط عملية الترجمة باستخدام واجهة سطر أوامر وخط أنابيب مدعوم بالذكاء الاصطناعي مصمم لأتمتة الترجمات للمطورين.",
- },
- getStarted: {
- heading: "ابدأ الآن",
- title: "ترجمة آلية لتطبيقاتك",
- description:
- "قم بتبسيط عملية الترجمة باستخدام واجهة سطر أوامر وخط أنابيب مدعوم بالذكاء الاصطناعي مصمم لأتمتة الترجمات للمطورين.",
- button: {
- startAutomating: "ابدأ الأتمتة",
- readDocumentation: "اقرأ الوثائق",
- },
- },
- companies: {
- title: "يستخدم من قبل",
- addYourCompany: "+ أضف شركتك",
- },
- activity: {
- title: "النشاط",
- },
- features: {
- title: "المميزات",
- fullyOpenSource: "مفتوح المصدر بالكامل",
- fullyOpenSourceDescription:
- "الكود الخاص بنا متاح للعموم على GitHub، مما يتيح الشفافية ومساهمات المجتمع.",
- noVendorLockIn: "لا قيود على المزود",
- noVendorLockInDescription:
- "نحن لا نقيدك بخدمة معينة، استخدم نماذج اللغة الكبيرة الخاصة بك.",
- presetsForExpo: "إعدادات مسبقة لـ Expo",
- presetsForExpoDescription:
- "نوفر إعدادات مسبقة لـ Expo، حتى تتمكن من البدء بسرعة.",
- presetForReactNative: "إعداد مسبق لـ React Native",
- presetForReactNativeDescription:
- "نوفر إعداداً مسبقاً لـ React Native، حتى تتمكن من البدء بسرعة.",
- presetForReactEmail: "مكتبة React Email",
- presetForReactEmailDescription: "قمنا بإنشاء مكتبة i18n لـ React Email.",
- readyForI18nLibraries: "جاهز لمكتبات i18n",
- readyForI18nLibrariesDescription:
- "ندعم جميع المكتبات بما في ذلك الأكثر شعبية (next-intl, react-i18next, react-intl, وغيرها).",
- },
- info: {
- title: "يتعامل مع كل جوانب ترجمة تطبيقك بما في ذلك",
- smartTranslation: {
- title: "الترجمة الذكية",
- intelligentTranslation: "ترجمة ذكية مع إدراك السياق",
- brandVoice: "صوت العلامة التجارية واتساق النبرة",
- terminology: "إدارة المصطلحات",
- linguisticFeatures: "ميزات لغوية متقدمة",
- realtimeUpdates: "تحديثات الترجمة في الوقت الفعلي",
- },
- implementation: {
- title: "التنفيذ",
- quickSetup: "إعداد وتكامل سريع",
- fileFormat: "معالجة تنسيق الملفات",
- contentStructure: "تنظيم هيكل المحتوى",
- assetOrganization: "تنظيم الأصول",
- },
- developer: {
- title: "تجربة المطور",
- cli: "واجهة سطر الأوامر",
- cicd: "تكامل CI/CD",
- versionControl: "التحكم في الإصدارات",
- workflow: "سير عمل المطور",
- documentation: "وثائق شاملة",
- },
- },
- login: {
- title: "تسجيل الدخول",
- github: "تسجيل الدخول باستخدام GitHub",
- google: "تسجيل الدخول باستخدام Google",
- footer: "قم بأتمتة الترجمة الخاصة بك.",
- description: "سجل الدخول لبدء أتمتة الترجمة في ثوانٍ.",
- terms: {
- text: "بتسجيل الدخول، فإنك توافق على",
- termsOfService: "شروط الخدمة",
- and: "و",
- privacyPolicy: "سياسة الخصوصية",
- },
- },
- translations: {
- total_keys: "{total} مفتاح في المجموع",
- },
- userMenu: {
- account: "إعدادات الحساب",
- signOut: "تسجيل الخروج",
- createTeam: "إنشاء فريق",
- homepage: "الصفحة الرئيسية",
- team: "إعدادات الفريق",
- },
- teamSelector: {
- addProject: "إضافة مشروع",
- createProjectTitle: "إنشاء مشروع جديد",
- projectNamePlaceholder: "اسم المشروع",
- createProjectButton: "إنشاء مشروع",
- pro: "محترف",
- project: "مشروع",
- teams: "الفرق",
- createTeam: "إنشاء فريق",
- createTeamTitle: "إنشاء فريق جديد",
- teamNamePlaceholder: "اسم الفريق",
- createTeamButton: "إنشاء فريق",
- },
- coming_soon: {
- title: "Languine في الوصول المبكر",
- description: "نحن حالياً في مرحلة الوصول المبكر. تواصل مع",
- cta: "على X للحصول على وصول مبكر.",
- },
- account: {
- fullName: {
- title: "الاسم الكامل",
- description: "اسمك الكامل كما سيظهر عبر المنصة.",
- placeholder: "أدخل اسمك الكامل",
- },
- email: {
- title: "البريد الإلكتروني",
- description: "عنوان البريد الإلكتروني المرتبط بحسابك.",
- placeholder: "أدخل بريدك الإلكتروني",
- },
- apiKey: {
- title: "مفتاح API",
- description: "مفتاح API الشخصي للوصول إلى Languine API.",
- },
- deleteAccount: {
- title: "حذف الحساب",
- description:
- "حذف حسابك وجميع البيانات المرتبطة به بشكل دائم. لا يمكن التراجع عن هذا الإجراء.",
- button: "حذف الحساب",
- },
- },
- copyInstall: {
- copied: "تم النسخ إلى الحافظة",
- },
- dangerZone: {
- dialog: {
- title: "هل أنت متأكد تماماً؟",
- description: "لا يمكن التراجع عن هذا الإجراء. يرجى كتابة DELETE للتأكيد.",
- placeholder: "اكتب DELETE للتأكيد",
- confirm: "تأكيد الحذف",
- },
- },
- pipeline: {
- title: "سير العمل (خط أنابيب CI/CD)",
- pro: "[محترف]",
- description:
- "يتكامل محرك الترجمة لدينا بسلاسة مع خط أنابيب CI/CD الحالي لديك، ويقوم تلقائياً بترجمة قاعدة الكود الخاصة بك مع كل دفع. عندما يتم دفع تغييرات الكود، نقوم بتحليل المحتوى المعدل، والحفاظ على ذاكرة الترجمة، وإنشاء ترجمات دقيقة مع الحفاظ على صوت علامتك التجارية والمصطلحات. ثم يتم تقديم الترجمات كطلبات سحب، مما يتيح المراجعة قبل دمجها في الفرع الرئيسي ونشرها. يضمن سير العمل الآلي هذا بقاء المحتوى المترجم متزامناً مع التطوير.",
- },
- settings: {
- saved: "تم حفظ الإعدادات",
- savedDescription: "تم حفظ تغييراتك بنجاح",
- tabs: {
- project: "المشروع",
- account: "الحساب",
- team: "الفريق",
- },
- project: {
- name: {
- title: "اسم المشروع",
- description: "اسم مشروعك",
- placeholder: "أدخل اسم المشروع",
- },
- id: {
- title: "معرف المشروع",
- description: "معرف مشروعك الفريد",
- placeholder: "معرف المشروع",
- },
- delete: {
- title: "حذف المشروع",
- description: "حذف هذا المشروع وجميع بياناته بشكل دائم",
- button: "حذف المشروع",
- },
- },
- team: {
- name: {
- title: "اسم الفريق",
- description: "اسم فريقك",
- placeholder: "أدخل اسم الفريق",
- },
- billing: {
- title: "خطة الفوترة",
- description: "إدارة خطة فوترة فريقك",
- free: "مجاني",
- pro: "محترف",
- },
- apiKey: {
- title: "مفتاح API للفريق",
- description: "مفتاح API للوصول إلى الفريق",
- placeholder: "مفتاح API للفريق",
- },
- members: {
- title: "الأعضاء",
- pendingInvitations: "الدعوات المعلقة",
- filterPlaceholder: "تصفية الأعضاء...",
- allRoles: "جميع الأدوار",
- date: "التاريخ",
- selectAll: "تم تحديد {count}",
- noPendingInvitations: "لا توجد دعوات معلقة",
- inviteMembers: "دعوة أعضاء الفريق للتعاون",
- roles: {
- owner: "مالك",
- admin: "مدير",
- member: "عضو",
- },
- dateSort: {
- newest: "الأحدث",
- oldest: "الأقدم",
- },
- },
- },
- },
- tuning: {
- general: "عام",
- translationMemory: {
- title: "ذاكرة الترجمة",
- description: "استخدم ذاكرة الترجمة لتحسين الاتساق والكفاءة",
- },
- qualityChecks: {
- title: "فحوصات الجودة",
- description: "تمكين فحوصات الجودة الآلية للترجمات",
- },
- contextDetection: {
- title: "اكتشاف السياق",
- description: "اكتشاف وحفظ السياق في الترجمات تلقائياً",
- },
- styleGuide: "دليل الأسلوب",
- lengthControl: {
- title: "التحكم في الطول",
- description: "التحكم في طول النص المترجم",
- options: {
- flexible: "مرن",
- strict: "صارم",
- exact: "دقيق",
- loose: "فضفاض",
- },
- },
- inclusiveLanguage: {
- title: "لغة شاملة",
- description: "ضمان استخدام الترجمات للغة شاملة",
- },
- formality: {
- title: "الرسمية",
- description: "التحكم في مستوى رسمية الترجمات",
- },
- brandName: {
- title: "اسم العلامة التجارية",
- description: "تعيين اسم علامتك التجارية للاستخدام المتسق",
- placeholder: "أدخل اسم علامتك التجارية",
- },
- brandVoice: {
- title: "صوت العلامة التجارية",
- description: "تحديد صوت ونبرة علامتك التجارية",
- placeholder: "صف صوت علامتك التجارية...",
- },
- localization: "الترجمة",
- idioms: {
- title: "التعابير الاصطلاحية",
- description: "التعامل مع التعابير الاصطلاحية بشكل مناسب",
- },
- terminology: {
- title: "المصطلحات",
- description: "إدارة المصطلحات المتخصصة والمسارد",
- },
- culturalAdaptation: {
- title: "التكيف الثقافي",
- description: "تكييف المحتوى للملاءمة الثقافية",
- },
- },
- pricing: {
- title: "تسعير بسيط",
- free: {
- title: "مجاني (100 مفتاح)",
- price: "مجاني",
- keys_limit: "حتى 100 مفتاح",
- features: {
- unlimited_projects: "مشاريع غير محدودة",
- fine_tuning: "خيارات الضبط الدقيق",
- overrides: "تجاوزات الترجمة",
- analytics: "التحليلات",
- context_memory: "ذاكرة السياق",
- community_support: "دعم المجتمع",
- },
- },
- pro: {
- title: "احترافي",
- includes_free: "كل ما في النسخة المجانية، بالإضافة إلى:",
- features: {
- github_action: "تكامل GitHub Action",
- latest_features: "وصول مبكر لأحدث الميزات",
- priority_support: "دعم ذو أولوية",
- },
- },
- cta: "ابدأ الأتمتة",
- },
-} as const;
diff --git a/apps/web/src/locales/client.ts b/apps/web/src/locales/client.ts
index 965b266..a99dcc1 100644
--- a/apps/web/src/locales/client.ts
+++ b/apps/web/src/locales/client.ts
@@ -10,15 +10,15 @@ export const {
useCurrentLocale,
} = createI18nClient({
en: () => import("./en"),
- fr: () => import("./fr"),
- es: () => import("./es"),
- de: () => import("./de"),
- no: () => import("./no"),
- sv: () => import("./sv"),
- fi: () => import("./fi"),
- pt: () => import("./pt"),
- ar: () => import("./ar"),
- ja: () => import("./ja"),
- ko: () => import("./ko"),
- zh: () => import("./zh"),
+ // fr: () => import("./fr"),
+ // es: () => import("./es"),
+ // de: () => import("./de"),
+ // no: () => import("./no"),
+ // sv: () => import("./sv"),
+ // fi: () => import("./fi"),
+ // pt: () => import("./pt"),
+ // ar: () => import("./ar"),
+ // ja: () => import("./ja"),
+ // ko: () => import("./ko"),
+ // zh: () => import("./zh"),
});
diff --git a/apps/web/src/locales/de.ts b/apps/web/src/locales/de.ts
deleted file mode 100644
index 500d548..0000000
--- a/apps/web/src/locales/de.ts
+++ /dev/null
@@ -1,313 +0,0 @@
-export default {
- header: {
- pricing: "Preise",
- docs: "Dokumentation",
- signIn: "Anmelden",
- goToApp: "Zur App",
- },
- hero: {
- title: "Automatisierte Lokalisierung für Ihre Anwendungen",
- description:
- "Optimieren Sie Ihren Lokalisierungsprozess mit einer KI-gestützten CLI und Pipeline, die für die Automatisierung von Übersetzungen für Entwickler konzipiert ist.",
- },
- getStarted: {
- heading: "Loslegen",
- title: "Automatisierte Lokalisierung für Ihre Anwendungen",
- description:
- "Optimieren Sie Ihren Lokalisierungsprozess mit einer KI-gestützten CLI und Pipeline, die für die Automatisierung von Übersetzungen für Entwickler konzipiert ist.",
- button: {
- startAutomating: "Automatisierung starten",
- readDocumentation: "Dokumentation lesen",
- },
- },
- companies: {
- title: "Verwendet von",
- addYourCompany: "+ Fügen Sie Ihr Unternehmen hinzu",
- },
- activity: {
- title: "Aktivität",
- },
- features: {
- title: "Funktionen",
- fullyOpenSource: "Vollständig Open Source",
- fullyOpenSourceDescription:
- "Unser Code ist öffentlich auf GitHub verfügbar und ermöglicht Transparenz und Community-Beiträge.",
- noVendorLockIn: "Keine Herstellerbindung",
- noVendorLockInDescription:
- "Wir binden Sie nicht an einen bestimmten Dienst, nutzen Sie Ihre eigenen LLMs.",
- presetsForExpo: "Voreinstellungen für Expo",
- presetsForExpoDescription:
- "Wir bieten Voreinstellungen für Expo, damit Sie schnell loslegen können.",
- presetForReactNative: "Voreinstellung für React Native",
- presetForReactNativeDescription:
- "Wir bieten eine Voreinstellung für React Native, damit Sie schnell loslegen können.",
- presetForReactEmail: "React Email Bibliothek",
- presetForReactEmailDescription:
- "Wir haben eine i18n-Bibliothek für React Email erstellt.",
- readyForI18nLibraries: "Bereit für i18n-Bibliotheken",
- readyForI18nLibrariesDescription:
- "Wir unterstützen alle Bibliotheken einschließlich der beliebtesten (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title: "Behandelt jeden Aspekt der Lokalisierung Ihrer App, einschließlich",
- smartTranslation: {
- title: "Intelligente Übersetzung",
- intelligentTranslation: "Intelligente Übersetzung mit Kontextbewusstsein",
- brandVoice: "Markensprache und Tonkonsistenz",
- terminology: "Terminologieverwaltung",
- linguisticFeatures: "Erweiterte sprachliche Funktionen",
- realtimeUpdates: "Echtzeit-Übersetzungsaktualisierungen",
- },
- implementation: {
- title: "Implementierung",
- quickSetup: "Schnelle Einrichtung und Integration",
- fileFormat: "Dateiformatverarbeitung",
- contentStructure: "Inhaltsstrukturorganisation",
- assetOrganization: "Asset-Organisation",
- },
- developer: {
- title: "Entwicklererfahrung",
- cli: "Kommandozeilenschnittstelle",
- cicd: "CI/CD-Integration",
- versionControl: "Versionskontrolle",
- workflow: "Entwickler-Workflow",
- documentation: "Umfassende Dokumentation",
- },
- },
- login: {
- title: "Anmelden",
- github: "Mit GitHub anmelden",
- google: "Mit Google anmelden",
- footer: "Automatisieren Sie Ihre Lokalisierung.",
- description:
- "Melden Sie sich an, um Ihre Lokalisierung in Sekunden zu automatisieren.",
- terms: {
- text: "Mit der Anmeldung stimmen Sie unseren",
- termsOfService: "Nutzungsbedingungen",
- and: "und der",
- privacyPolicy: "Datenschutzerklärung",
- },
- },
- translations: {
- total_keys: "Insgesamt {total} Schlüssel",
- },
- userMenu: {
- account: "Kontoeinstellungen",
- signOut: "Abmelden",
- createTeam: "Team erstellen",
- homepage: "Startseite",
- team: "Team-Einstellungen",
- },
- teamSelector: {
- addProject: "Projekt hinzufügen",
- createProjectTitle: "Neues Projekt erstellen",
- projectNamePlaceholder: "Projektname",
- createProjectButton: "Projekt erstellen",
- pro: "Pro",
- project: "Projekt",
- teams: "Teams",
- createTeam: "Team erstellen",
- createTeamTitle: "Neues Team erstellen",
- teamNamePlaceholder: "Teamname",
- createTeamButton: "Team erstellen",
- },
- coming_soon: {
- title: "Languine ist im Early Access",
- description: "Wir befinden uns derzeit im Early Access. Kontaktieren Sie",
- cta: "auf X, um frühen Zugang zu erhalten.",
- },
- account: {
- fullName: {
- title: "Vollständiger Name",
- description:
- "Ihr vollständiger Name, wie er auf der Plattform erscheinen wird.",
- placeholder: "Geben Sie Ihren vollständigen Namen ein",
- },
- email: {
- title: "E-Mail-Adresse",
- description: "Die mit Ihrem Konto verknüpfte E-Mail-Adresse.",
- placeholder: "Geben Sie Ihre E-Mail-Adresse ein",
- },
- apiKey: {
- title: "API-Schlüssel",
- description:
- "Ihr persönlicher API-Schlüssel für den Zugriff auf die Languine API.",
- },
- deleteAccount: {
- title: "Konto löschen",
- description:
- "Löschen Sie Ihr Konto und alle zugehörigen Daten permanent. Diese Aktion kann nicht rückgängig gemacht werden.",
- button: "Konto löschen",
- },
- },
- copyInstall: {
- copied: "In die Zwischenablage kopiert",
- },
- dangerZone: {
- dialog: {
- title: "Sind Sie absolut sicher?",
- description:
- "Diese Aktion kann nicht rückgängig gemacht werden. Bitte geben Sie DELETE ein zur Bestätigung.",
- placeholder: "Geben Sie DELETE ein zur Bestätigung",
- confirm: "Löschen bestätigen",
- },
- },
- pipeline: {
- title: "Workflow (CI/CD-Pipeline)",
- pro: "[pro]",
- description:
- "Unsere Übersetzungs-Engine integriert sich nahtlos in Ihre bestehende CI/CD-Pipeline und übersetzt Ihre Codebasis bei jedem Push automatisch. Wenn Code-Änderungen gepusht werden, analysieren wir die geänderten Inhalte, pflegen Ihren Übersetzungsspeicher und generieren genaue Übersetzungen unter Beibehaltung Ihrer Markensprache und Terminologie. Die Übersetzungen werden dann als Pull Requests eingereicht, die vor der Zusammenführung in Ihren Hauptzweig und der Bereitstellung überprüft werden können. Dieser automatisierte Workflow stellt sicher, dass Ihre lokalisierten Inhalte mit der Entwicklung synchron bleiben.",
- },
- settings: {
- saved: "Einstellungen gespeichert",
- savedDescription: "Ihre Änderungen wurden erfolgreich gespeichert",
- tabs: {
- project: "Projekt",
- account: "Konto",
- team: "Team",
- },
- project: {
- name: {
- title: "Projektname",
- description: "Der Name Ihres Projekts",
- placeholder: "Projektname eingeben",
- },
- id: {
- title: "Projekt-ID",
- description: "Ihre eindeutige Projekt-Kennung",
- placeholder: "Projekt-ID",
- },
- delete: {
- title: "Projekt löschen",
- description:
- "Dieses Projekt und alle zugehörigen Daten permanent löschen",
- button: "Projekt löschen",
- },
- },
- team: {
- name: {
- title: "Teamname",
- description: "Der Name Ihres Teams",
- placeholder: "Teamname eingeben",
- },
- billing: {
- title: "Abrechnungsplan",
- description: "Verwalten Sie den Abrechnungsplan Ihres Teams",
- free: "Kostenlos",
- pro: "Pro",
- },
- apiKey: {
- title: "Team-API-Schlüssel",
- description: "API-Schlüssel für Team-Zugriff",
- placeholder: "Team-API-Schlüssel",
- },
- members: {
- title: "Mitglieder",
- pendingInvitations: "Ausstehende Einladungen",
- filterPlaceholder: "Mitglieder filtern...",
- allRoles: "Alle Rollen",
- date: "Datum",
- selectAll: "{count} ausgewählt",
- noPendingInvitations: "Keine ausstehenden Einladungen",
- inviteMembers: "Teammitglieder zur Zusammenarbeit einladen",
- roles: {
- owner: "Eigentümer",
- admin: "Administrator",
- member: "Mitglied",
- },
- dateSort: {
- newest: "Neueste",
- oldest: "Älteste",
- },
- },
- },
- },
- tuning: {
- general: "Allgemein",
- translationMemory: {
- title: "Übersetzungsspeicher",
- description:
- "Nutzen Sie den Übersetzungsspeicher zur Verbesserung von Konsistenz und Effizienz",
- },
- qualityChecks: {
- title: "Qualitätsprüfungen",
- description:
- "Aktivieren Sie automatisierte Qualitätsprüfungen für Übersetzungen",
- },
- contextDetection: {
- title: "Kontexterkennung",
- description:
- "Automatische Erkennung und Bewahrung des Kontexts in Übersetzungen",
- },
- styleGuide: "Styleguide",
- lengthControl: {
- title: "Längenkontrolle",
- description: "Steuern Sie die Länge des übersetzten Texts",
- options: {
- flexible: "Flexibel",
- strict: "Streng",
- exact: "Exakt",
- loose: "Locker",
- },
- },
- inclusiveLanguage: {
- title: "Inklusive Sprache",
- description:
- "Stellen Sie sicher, dass Übersetzungen inklusive Sprache verwenden",
- },
- formality: {
- title: "Formalität",
- description: "Steuern Sie den Formalitätsgrad der Übersetzungen",
- },
- brandName: {
- title: "Markenname",
- description:
- "Legen Sie Ihren Markennamen für konsistente Verwendung fest",
- placeholder: "Geben Sie Ihren Markennamen ein",
- },
- brandVoice: {
- title: "Markenstimme",
- description: "Definieren Sie Ihre Markenstimme und den Ton",
- placeholder: "Beschreiben Sie Ihre Markenstimme...",
- },
- localization: "Lokalisierung",
- idioms: {
- title: "Redewendungen",
- description: "Behandeln Sie idiomatische Ausdrücke angemessen",
- },
- terminology: {
- title: "Terminologie",
- description: "Verwalten Sie spezialisierte Terminologie und Glossare",
- },
- culturalAdaptation: {
- title: "Kulturelle Anpassung",
- description: "Passen Sie Inhalte für kulturelle Angemessenheit an",
- },
- },
- pricing: {
- title: "Einfache Preisgestaltung",
- free: {
- title: "Kostenlos (100 Schlüssel)",
- price: "Kostenlos",
- keys_limit: "Bis zu 100 Schlüssel",
- features: {
- unlimited_projects: "Unbegrenzte Projekte",
- fine_tuning: "Feinabstimmungsoptionen",
- overrides: "Übersetzungsüberschreibungen",
- analytics: "Analysen",
- context_memory: "Kontextspeicher",
- community_support: "Community-Support",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Alles aus der kostenlosen Version, plus:",
- features: {
- github_action: "GitHub Action Integration",
- latest_features: "Frühzeitiger Zugang zu neuen Funktionen",
- priority_support: "Prioritäts-Support",
- },
- },
- cta: "Automatisierung starten",
- },
-} as const;
diff --git a/apps/web/src/locales/es.ts b/apps/web/src/locales/es.ts
deleted file mode 100644
index bc01b77..0000000
--- a/apps/web/src/locales/es.ts
+++ /dev/null
@@ -1,309 +0,0 @@
-export default {
- header: {
- pricing: "Precios",
- docs: "Documentación",
- signIn: "Iniciar sesión",
- goToApp: "Ir a la app",
- },
- hero: {
- title: "Localización automatizada para tus aplicaciones",
- description:
- "Optimiza tu proceso de localización con una CLI y pipeline impulsados por IA, diseñados para automatizar traducciones para desarrolladores.",
- },
- getStarted: {
- heading: "Comenzar",
- title: "Localización automatizada para tus aplicaciones",
- description:
- "Optimiza tu proceso de localización con una CLI y pipeline impulsados por IA, diseñados para automatizar traducciones para desarrolladores.",
- button: {
- startAutomating: "Empezar a automatizar",
- readDocumentation: "Leer documentación",
- },
- },
- companies: {
- title: "Usado por",
- addYourCompany: "+ Añade tu empresa",
- },
- activity: {
- title: "Actividad",
- },
- features: {
- title: "Características",
- fullyOpenSource: "Completamente código abierto",
- fullyOpenSourceDescription:
- "Nuestro código está disponible públicamente en GitHub, permitiendo transparencia y contribuciones de la comunidad.",
- noVendorLockIn: "Sin dependencia de proveedor",
- noVendorLockInDescription:
- "No te atamos a un servicio específico, usa tus propios LLMs.",
- presetsForExpo: "Preajustes para Expo",
- presetsForExpoDescription:
- "Proporcionamos preajustes para Expo, para que puedas empezar rápidamente.",
- presetForReactNative: "Preajuste para React Native",
- presetForReactNativeDescription:
- "Proporcionamos un preajuste para React Native, para que puedas empezar rápidamente.",
- presetForReactEmail: "Biblioteca React Email",
- presetForReactEmailDescription:
- "Hemos creado una biblioteca i18n para React Email.",
- readyForI18nLibraries: "Listo para bibliotecas i18n",
- readyForI18nLibrariesDescription:
- "Soportamos todas las bibliotecas, incluyendo las más populares (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title: "Maneja todos los aspectos de la localización de tu app, incluyendo",
- smartTranslation: {
- title: "Traducción Inteligente",
- intelligentTranslation:
- "Traducción inteligente con conciencia del contexto",
- brandVoice: "Consistencia de voz y tono de marca",
- terminology: "Gestión de terminología",
- linguisticFeatures: "Características lingüísticas avanzadas",
- realtimeUpdates: "Actualizaciones de traducción en tiempo real",
- },
- implementation: {
- title: "Implementación",
- quickSetup: "Configuración e integración rápida",
- fileFormat: "Manejo de formatos de archivo",
- contentStructure: "Organización de estructura de contenido",
- assetOrganization: "Organización de recursos",
- },
- developer: {
- title: "Experiencia del Desarrollador",
- cli: "Interfaz de línea de comandos",
- cicd: "Integración CI/CD",
- versionControl: "Control de versiones",
- workflow: "Flujo de trabajo del desarrollador",
- documentation: "Documentación completa",
- },
- },
- login: {
- title: "Iniciar sesión",
- github: "Iniciar sesión con GitHub",
- google: "Iniciar sesión con Google",
- footer: "Automatiza tu localización.",
- description:
- "Inicia sesión para comenzar a automatizar tu localización en segundos.",
- terms: {
- text: "Al iniciar sesión, aceptas nuestros",
- termsOfService: "Términos de Servicio",
- and: "y",
- privacyPolicy: "Política de Privacidad",
- },
- },
- translations: {
- total_keys: "{total} claves en total",
- },
- userMenu: {
- account: "Configuración de cuenta",
- signOut: "Cerrar sesión",
- createTeam: "Crear equipo",
- homepage: "Página principal",
- team: "Configuración del equipo",
- },
- teamSelector: {
- addProject: "Añadir proyecto",
- createProjectTitle: "Crear un nuevo proyecto",
- projectNamePlaceholder: "Nombre del proyecto",
- createProjectButton: "Crear proyecto",
- pro: "Pro",
- project: "Proyecto",
- teams: "Equipos",
- createTeam: "Crear equipo",
- createTeamTitle: "Crear un nuevo equipo",
- teamNamePlaceholder: "Nombre del equipo",
- createTeamButton: "Crear equipo",
- },
- coming_soon: {
- title: "Languine está en Acceso Anticipado",
- description: "Actualmente estamos en acceso anticipado. Contacta a",
- cta: "en X para obtener acceso anticipado.",
- },
- account: {
- fullName: {
- title: "Nombre completo",
- description: "Tu nombre completo como aparecerá en toda la plataforma.",
- placeholder: "Ingresa tu nombre completo",
- },
- email: {
- title: "Correo electrónico",
- description: "El correo electrónico asociado a tu cuenta.",
- placeholder: "Ingresa tu correo electrónico",
- },
- apiKey: {
- title: "Clave API",
- description: "Tu clave API personal para acceder a la API de Languine.",
- },
- deleteAccount: {
- title: "Eliminar cuenta",
- description:
- "Eliminar permanentemente tu cuenta y todos los datos asociados. Esta acción no se puede deshacer.",
- button: "Eliminar cuenta",
- },
- },
- copyInstall: {
- copied: "Copiado al portapapeles",
- },
- dangerZone: {
- dialog: {
- title: "¿Estás completamente seguro?",
- description:
- "Esta acción no se puede deshacer. Por favor, escribe DELETE para confirmar.",
- placeholder: "Escribe DELETE para confirmar",
- confirm: "Confirmar eliminación",
- },
- },
- pipeline: {
- title: "Flujo de trabajo (Pipeline CI/CD)",
- pro: "[pro]",
- description:
- "Nuestro motor de traducción se integra perfectamente en tu pipeline CI/CD existente, traduciendo automáticamente tu código base en cada push. Cuando se envían cambios de código, analizamos el contenido modificado, mantenemos tu memoria de traducción y generamos traducciones precisas mientras preservamos la voz y terminología de tu marca. Las traducciones se envían como pull requests, permitiendo su revisión antes de ser fusionadas en tu rama principal y desplegadas. Este flujo de trabajo automatizado asegura que tu contenido localizado se mantenga sincronizado con el desarrollo.",
- },
- settings: {
- saved: "Configuración guardada",
- savedDescription: "Tus cambios se han guardado correctamente",
- tabs: {
- project: "Proyecto",
- account: "Cuenta",
- team: "Equipo",
- },
- project: {
- name: {
- title: "Nombre del proyecto",
- description: "El nombre de tu proyecto",
- placeholder: "Ingresa el nombre del proyecto",
- },
- id: {
- title: "ID del proyecto",
- description: "Tu identificador único de proyecto",
- placeholder: "ID del proyecto",
- },
- delete: {
- title: "Eliminar proyecto",
- description: "Eliminar permanentemente este proyecto y todos sus datos",
- button: "Eliminar proyecto",
- },
- },
- team: {
- name: {
- title: "Nombre del equipo",
- description: "El nombre de tu equipo",
- placeholder: "Ingresa el nombre del equipo",
- },
- billing: {
- title: "Plan de facturación",
- description: "Gestiona el plan de facturación de tu equipo",
- free: "Gratuito",
- pro: "Pro",
- },
- apiKey: {
- title: "Clave API del equipo",
- description: "Clave API para acceso del equipo",
- placeholder: "Clave API del equipo",
- },
- members: {
- title: "Miembros",
- pendingInvitations: "Invitaciones pendientes",
- filterPlaceholder: "Filtrar miembros...",
- allRoles: "Todos los roles",
- date: "Fecha",
- selectAll: "{count} seleccionados",
- noPendingInvitations: "No hay invitaciones pendientes",
- inviteMembers: "Invitar miembros del equipo a colaborar",
- roles: {
- owner: "Propietario",
- admin: "Administrador",
- member: "Miembro",
- },
- dateSort: {
- newest: "Más reciente",
- oldest: "Más antiguo",
- },
- },
- },
- },
- tuning: {
- general: "General",
- translationMemory: {
- title: "Memoria de traducción",
- description:
- "Usar memoria de traducción para mejorar la consistencia y eficiencia",
- },
- qualityChecks: {
- title: "Controles de calidad",
- description:
- "Habilitar controles de calidad automatizados para traducciones",
- },
- contextDetection: {
- title: "Detección de contexto",
- description:
- "Detectar y preservar automáticamente el contexto en las traducciones",
- },
- styleGuide: "Guía de estilo",
- lengthControl: {
- title: "Control de longitud",
- description: "Controlar la longitud del texto traducido",
- options: {
- flexible: "Flexible",
- strict: "Estricto",
- exact: "Exacto",
- loose: "Suelto",
- },
- },
- inclusiveLanguage: {
- title: "Lenguaje inclusivo",
- description: "Asegurar que las traducciones usen lenguaje inclusivo",
- },
- formality: {
- title: "Formalidad",
- description: "Controlar el nivel de formalidad de las traducciones",
- },
- brandName: {
- title: "Nombre de marca",
- description: "Establece tu nombre de marca para un uso consistente",
- placeholder: "Ingresa el nombre de tu marca",
- },
- brandVoice: {
- title: "Voz de marca",
- description: "Define la voz y el tono de tu marca",
- placeholder: "Describe la voz de tu marca...",
- },
- localization: "Localización",
- idioms: {
- title: "Modismos",
- description: "Manejar expresiones idiomáticas apropiadamente",
- },
- terminology: {
- title: "Terminología",
- description: "Gestionar terminología especializada y glosarios",
- },
- culturalAdaptation: {
- title: "Adaptación cultural",
- description: "Adaptar contenido para la adecuación cultural",
- },
- },
- pricing: {
- title: "Precios simples",
- free: {
- title: "Gratis (100 claves)",
- price: "Gratis",
- keys_limit: "Hasta 100 claves",
- features: {
- unlimited_projects: "Proyectos ilimitados",
- fine_tuning: "Opciones de ajuste fino",
- overrides: "Anulaciones de traducción",
- analytics: "Análisis",
- context_memory: "Memoria de contexto",
- community_support: "Soporte comunitario",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Todo lo incluido en Gratis, más:",
- features: {
- github_action: "Integración con GitHub Action",
- latest_features: "Acceso anticipado a nuevas funciones",
- priority_support: "Soporte prioritario",
- },
- },
- cta: "Comenzar a automatizar",
- },
-} as const;
diff --git a/apps/web/src/locales/fi.ts b/apps/web/src/locales/fi.ts
deleted file mode 100644
index 192ef90..0000000
--- a/apps/web/src/locales/fi.ts
+++ /dev/null
@@ -1,308 +0,0 @@
-export default {
- header: {
- pricing: "Hinnoittelu",
- docs: "Dokumentaatio",
- signIn: "Kirjaudu sisään",
- goToApp: "Siirry sovellukseen",
- },
- hero: {
- title: "Automatisoitu lokalisointi sovelluksillesi",
- description:
- "Virtaviivaista lokalisointiprosessisi tekoälypohjaisella CLI:llä ja putkistolla, joka on suunniteltu automatisoimaan käännökset kehittäjille.",
- },
- getStarted: {
- heading: "Aloita",
- title: "Automatisoitu lokalisointi sovelluksillesi",
- description:
- "Virtaviivaista lokalisointiprosessisi tekoälypohjaisella CLI:llä ja putkistolla, joka on suunniteltu automatisoimaan käännökset kehittäjille.",
- button: {
- startAutomating: "Aloita automatisointi",
- readDocumentation: "Lue dokumentaatio",
- },
- },
- companies: {
- title: "Käyttäjinä",
- addYourCompany: "+ Lisää yrityksesi",
- },
- activity: {
- title: "Aktiviteetti",
- },
- features: {
- title: "Ominaisuudet",
- fullyOpenSource: "Täysin avointa lähdekoodia",
- fullyOpenSourceDescription:
- "Koodimme on julkisesti saatavilla GitHubissa, mahdollistaen läpinäkyvyyden ja yhteisön osallistumisen.",
- noVendorLockIn: "Ei toimittajalukkiutumista",
- noVendorLockInDescription:
- "Emme lukitse sinua tiettyyn palveluun, käytä omia kielimalleja.",
- presetsForExpo: "Esiasetukset Expolle",
- presetsForExpoDescription:
- "Tarjoamme esiasetukset Expolle, jotta pääset nopeasti alkuun.",
- presetForReactNative: "Esiasetus React Nativelle",
- presetForReactNativeDescription:
- "Tarjoamme esiasetuksen React Nativelle, jotta pääset nopeasti alkuun.",
- presetForReactEmail: "React Email -kirjasto",
- presetForReactEmailDescription:
- "Olemme luoneet i18n-kirjaston React Emailille.",
- readyForI18nLibraries: "Valmis i18n-kirjastoille",
- readyForI18nLibrariesDescription:
- "Tuemme kaikkia kirjastoja, mukaan lukien suosituimmat (next-intl, react-i18next, react-intl, jne).",
- },
- info: {
- title:
- "Käsittelee sovelluksesi lokalisoinnin kaikki osa-alueet, mukaan lukien",
- smartTranslation: {
- title: "Älykäs käännös",
- intelligentTranslation: "Älykäs käännös kontekstitietoisuudella",
- brandVoice: "Brändiäänen ja -sävyn johdonmukaisuus",
- terminology: "Terminologian hallinta",
- linguisticFeatures: "Edistyneet kielelliset ominaisuudet",
- realtimeUpdates: "Reaaliaikaiset käännöspäivitykset",
- },
- implementation: {
- title: "Toteutus",
- quickSetup: "Nopea asennus ja integrointi",
- fileFormat: "Tiedostomuotojen käsittely",
- contentStructure: "Sisältörakenteen organisointi",
- assetOrganization: "Resurssien organisointi",
- },
- developer: {
- title: "Kehittäjäkokemus",
- cli: "Komentorivityökalu",
- cicd: "CI/CD-integraatio",
- versionControl: "Versionhallinta",
- workflow: "Kehittäjän työnkulku",
- documentation: "Kattava dokumentaatio",
- },
- },
- login: {
- title: "Kirjaudu sisään",
- github: "Kirjaudu GitHubilla",
- google: "Kirjaudu Googlella",
- footer: "Automatisoi lokalisointisi.",
- description:
- "Kirjaudu sisään aloittaaksesi lokalisoinnin automatisoinnin sekunneissa.",
- terms: {
- text: "Kirjautumalla hyväksyt meidän",
- termsOfService: "Käyttöehdot",
- and: "ja",
- privacyPolicy: "Tietosuojakäytännön",
- },
- },
- translations: {
- total_keys: "Yhteensä {total} avainta",
- },
- userMenu: {
- account: "Tiliasetukset",
- signOut: "Kirjaudu ulos",
- createTeam: "Luo tiimi",
- homepage: "Etusivu",
- team: "Tiimiasetukset",
- },
- teamSelector: {
- addProject: "Lisää projekti",
- createProjectTitle: "Luo uusi projekti",
- projectNamePlaceholder: "Projektin nimi",
- createProjectButton: "Luo projekti",
- pro: "Pro",
- project: "Projekti",
- teams: "Tiimit",
- createTeam: "Luo tiimi",
- createTeamTitle: "Luo uusi tiimi",
- teamNamePlaceholder: "Tiimin nimi",
- createTeamButton: "Luo tiimi",
- },
- coming_soon: {
- title: "Languine on varhaisessa käyttövaiheessa",
- description:
- "Olemme tällä hetkellä varhaisessa käyttövaiheessa. Ota yhteyttä",
- cta: "X:ssä saadaksesi varhaisen pääsyn.",
- },
- account: {
- fullName: {
- title: "Koko nimi",
- description: "Koko nimesi sellaisena kuin se näkyy alustalla.",
- placeholder: "Syötä koko nimesi",
- },
- email: {
- title: "Sähköpostiosoite",
- description: "Tiliisi liitetty sähköpostiosoite.",
- placeholder: "Syötä sähköpostiosoitteesi",
- },
- apiKey: {
- title: "API-avain",
- description: "Henkilökohtainen API-avaimesi Languine API:n käyttöön.",
- },
- deleteAccount: {
- title: "Poista tili",
- description:
- "Poista pysyvästi tilisi ja kaikki siihen liittyvät tiedot. Tätä toimintoa ei voi kumota.",
- button: "Poista tili",
- },
- },
- copyInstall: {
- copied: "Kopioitu leikepöydälle",
- },
- dangerZone: {
- dialog: {
- title: "Oletko aivan varma?",
- description:
- "Tätä toimintoa ei voi kumota. Kirjoita DELETE vahvistaaksesi.",
- placeholder: "Kirjoita DELETE vahvistaaksesi",
- confirm: "Vahvista poisto",
- },
- },
- pipeline: {
- title: "Työnkulku (CI/CD-putki)",
- pro: "[pro]",
- description:
- "Käännösmoottorimme integroituu saumattomasti olemassa olevaan CI/CD-putkistoosi, kääntäen koodipohjan automaattisesti jokaisen pushin yhteydessä. Kun koodimuutoksia pusketaan, analysoimme muutetun sisällön, ylläpidämme käännösmuistia ja tuotamme tarkkoja käännöksiä säilyttäen brändiäänesi ja terminologian. Käännökset lähetetään sitten pull requesteina, mahdollistaen tarkistuksen ennen päähaaran yhdistämistä ja käyttöönottoa. Tämä automatisoitu työnkulku varmistaa, että lokalisoitu sisältösi pysyy synkronoituna kehityksen kanssa.",
- },
- settings: {
- saved: "Asetukset tallennettu",
- savedDescription: "Muutoksesi on tallennettu onnistuneesti",
- tabs: {
- project: "Projekti",
- account: "Tili",
- team: "Tiimi",
- },
- project: {
- name: {
- title: "Projektin nimi",
- description: "Projektisi nimi",
- placeholder: "Syötä projektin nimi",
- },
- id: {
- title: "Projektin ID",
- description: "Yksilöllinen projektin tunniste",
- placeholder: "Projektin ID",
- },
- delete: {
- title: "Poista projekti",
- description: "Poista pysyvästi tämä projekti ja kaikki sen tiedot",
- button: "Poista projekti",
- },
- },
- team: {
- name: {
- title: "Tiimin nimi",
- description: "Tiimisi nimi",
- placeholder: "Syötä tiimin nimi",
- },
- billing: {
- title: "Laskutussuunnitelma",
- description: "Hallitse tiimisi laskutussuunnitelmaa",
- free: "Ilmainen",
- pro: "Pro",
- },
- apiKey: {
- title: "Tiimin API-avain",
- description: "API-avain tiimin käyttöön",
- placeholder: "Tiimin API-avain",
- },
- members: {
- title: "Jäsenet",
- pendingInvitations: "Odottavat kutsut",
- filterPlaceholder: "Suodata jäseniä...",
- allRoles: "Kaikki roolit",
- date: "Päivämäärä",
- selectAll: "{count} valittu",
- noPendingInvitations: "Ei odottavia kutsuja",
- inviteMembers: "Kutsu tiimin jäseniä yhteistyöhön",
- roles: {
- owner: "Omistaja",
- admin: "Ylläpitäjä",
- member: "Jäsen",
- },
- dateSort: {
- newest: "Uusimmat",
- oldest: "Vanhimmat",
- },
- },
- },
- },
- tuning: {
- general: "Yleinen",
- translationMemory: {
- title: "Käännösmuisti",
- description:
- "Käytä käännösmuistia parantaaksesi johdonmukaisuutta ja tehokkuutta",
- },
- qualityChecks: {
- title: "Laatutarkistukset",
- description: "Ota käyttöön automaattiset laatutarkistukset käännöksille",
- },
- contextDetection: {
- title: "Kontekstintunnistus",
- description: "Tunnista ja säilytä konteksti käännöksissä automaattisesti",
- },
- styleGuide: "Tyyliopas",
- lengthControl: {
- title: "Pituuden hallinta",
- description: "Hallitse käännetyn tekstin pituutta",
- options: {
- flexible: "Joustava",
- strict: "Tarkka",
- exact: "Täsmällinen",
- loose: "Väljä",
- },
- },
- inclusiveLanguage: {
- title: "Inklusiivinen kieli",
- description: "Varmista, että käännökset käyttävät inklusiivista kieltä",
- },
- formality: {
- title: "Muodollisuus",
- description: "Hallitse käännösten muodollisuustasoa",
- },
- brandName: {
- title: "Brändin nimi",
- description: "Aseta brändisi nimi johdonmukaista käyttöä varten",
- placeholder: "Syötä brändisi nimi",
- },
- brandVoice: {
- title: "Brändin ääni",
- description: "Määritä brändisi ääni ja sävy",
- placeholder: "Kuvaile brändisi ääntä...",
- },
- localization: "Lokalisointi",
- idioms: {
- title: "Idiomit",
- description: "Käsittele idiomeja asianmukaisesti",
- },
- terminology: {
- title: "Terminologia",
- description: "Hallitse erikoisterminologiaa ja sanastoja",
- },
- culturalAdaptation: {
- title: "Kulttuurinen sovitus",
- description: "Sovita sisältö kulttuurisesti sopivaksi",
- },
- },
- pricing: {
- title: "Yksinkertainen hinnoittelu",
- free: {
- title: "Ilmainen (100 avainta)",
- price: "Ilmainen",
- keys_limit: "Jopa 100 avainta",
- features: {
- unlimited_projects: "Rajattomat projektit",
- fine_tuning: "Hienosäätöasetukset",
- overrides: "Käännösten ohitukset",
- analytics: "Analytiikka",
- context_memory: "Kontekstimuisti",
- community_support: "Yhteisötuki",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Kaikki ilmaisessa versiossa, plus:",
- features: {
- github_action: "GitHub Action -integraatio",
- latest_features: "Varhainen pääsy uusiin ominaisuuksiin",
- priority_support: "Prioriteettituki",
- },
- },
- cta: "Aloita automatisointi",
- },
-} as const;
diff --git a/apps/web/src/locales/fr.ts b/apps/web/src/locales/fr.ts
deleted file mode 100644
index afb28af..0000000
--- a/apps/web/src/locales/fr.ts
+++ /dev/null
@@ -1,311 +0,0 @@
-export default {
- header: {
- pricing: "Tarifs",
- docs: "Documentation",
- signIn: "Se connecter",
- goToApp: "Accéder à l'app",
- },
- hero: {
- title: "Localisation automatisée pour vos applications",
- description:
- "Simplifiez votre processus de localisation grâce à une CLI et un pipeline alimentés par l'IA, conçus pour automatiser les traductions pour les développeurs.",
- },
- getStarted: {
- heading: "Commencer",
- title: "Localisation automatisée pour vos applications",
- description:
- "Simplifiez votre processus de localisation grâce à une CLI et un pipeline alimentés par l'IA, conçus pour automatiser les traductions pour les développeurs.",
- button: {
- startAutomating: "Commencer l'automatisation",
- readDocumentation: "Lire la documentation",
- },
- },
- companies: {
- title: "Utilisé par",
- addYourCompany: "+ Ajouter votre entreprise",
- },
- activity: {
- title: "Activité",
- },
- features: {
- title: "Fonctionnalités",
- fullyOpenSource: "Entièrement open source",
- fullyOpenSourceDescription:
- "Notre code est disponible publiquement sur GitHub, permettant la transparence et les contributions de la communauté.",
- noVendorLockIn: "Pas de dépendance fournisseur",
- noVendorLockInDescription:
- "Nous ne vous enfermons pas dans un service spécifique, utilisez vos propres LLMs.",
- presetsForExpo: "Préréglages pour Expo",
- presetsForExpoDescription:
- "Nous fournissons des préréglages pour Expo, pour vous permettre de démarrer rapidement.",
- presetForReactNative: "Préréglage pour React Native",
- presetForReactNativeDescription:
- "Nous fournissons un préréglage pour React Native, pour vous permettre de démarrer rapidement.",
- presetForReactEmail: "Bibliothèque React Email",
- presetForReactEmailDescription:
- "Nous avons créé une bibliothèque i18n pour React Email.",
- readyForI18nLibraries: "Compatible avec les bibliothèques i18n",
- readyForI18nLibrariesDescription:
- "Nous prenons en charge toutes les bibliothèques, y compris les plus populaires (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title:
- "Gère tous les aspects de la localisation de votre application, notamment",
- smartTranslation: {
- title: "Traduction Intelligente",
- intelligentTranslation:
- "Traduction intelligente avec conscience du contexte",
- brandVoice: "Cohérence de la voix et du ton de la marque",
- terminology: "Gestion de la terminologie",
- linguisticFeatures: "Fonctionnalités linguistiques avancées",
- realtimeUpdates: "Mises à jour des traductions en temps réel",
- },
- implementation: {
- title: "Implémentation",
- quickSetup: "Configuration et intégration rapides",
- fileFormat: "Gestion des formats de fichiers",
- contentStructure: "Organisation de la structure du contenu",
- assetOrganization: "Organisation des ressources",
- },
- developer: {
- title: "Expérience Développeur",
- cli: "Interface en ligne de commande",
- cicd: "Intégration CI/CD",
- versionControl: "Contrôle de version",
- workflow: "Flux de travail développeur",
- documentation: "Documentation complète",
- },
- },
- login: {
- title: "Connexion",
- github: "Se connecter avec GitHub",
- google: "Se connecter avec Google",
- footer: "Automatisez votre localisation.",
- description:
- "Connectez-vous pour commencer à automatiser votre localisation en quelques secondes.",
- terms: {
- text: "En vous connectant, vous acceptez nos",
- termsOfService: "Conditions d'Utilisation",
- and: "et",
- privacyPolicy: "Politique de Confidentialité",
- },
- },
- translations: {
- total_keys: "{total} clés au total",
- },
- userMenu: {
- account: "Paramètres du compte",
- signOut: "Se déconnecter",
- createTeam: "Créer une équipe",
- homepage: "Page d'accueil",
- team: "Paramètres d'équipe",
- },
- teamSelector: {
- addProject: "Ajouter un projet",
- createProjectTitle: "Créer un nouveau projet",
- projectNamePlaceholder: "Nom du projet",
- createProjectButton: "Créer le projet",
- pro: "Pro",
- project: "Projet",
- teams: "Équipes",
- createTeam: "Créer une équipe",
- createTeamTitle: "Créer une nouvelle équipe",
- teamNamePlaceholder: "Nom de l'équipe",
- createTeamButton: "Créer l'équipe",
- },
- coming_soon: {
- title: "Languine est en Accès Anticipé",
- description: "Nous sommes actuellement en accès anticipé. Contactez",
- cta: "sur X pour obtenir un accès anticipé.",
- },
- account: {
- fullName: {
- title: "Nom complet",
- description: "Votre nom complet tel qu'il apparaîtra sur la plateforme.",
- placeholder: "Entrez votre nom complet",
- },
- email: {
- title: "Adresse e-mail",
- description: "L'adresse e-mail associée à votre compte.",
- placeholder: "Entrez votre adresse e-mail",
- },
- apiKey: {
- title: "Clé API",
- description: "Votre clé API personnelle pour accéder à l'API Languine.",
- },
- deleteAccount: {
- title: "Supprimer le compte",
- description:
- "Supprimez définitivement votre compte et toutes les données associées. Cette action est irréversible.",
- button: "Supprimer le compte",
- },
- },
- copyInstall: {
- copied: "Copié dans le presse-papiers",
- },
- dangerZone: {
- dialog: {
- title: "Êtes-vous absolument sûr ?",
- description:
- "Cette action ne peut pas être annulée. Veuillez taper SUPPRIMER pour confirmer.",
- placeholder: "Tapez SUPPRIMER pour confirmer",
- confirm: "Confirmer la suppression",
- },
- },
- pipeline: {
- title: "Workflow (Pipeline CI/CD)",
- pro: "[pro]",
- description:
- "Notre moteur de traduction s'intègre parfaitement à votre pipeline CI/CD existant, traduisant automatiquement votre code à chaque push. Lorsque des modifications de code sont poussées, nous analysons le contenu modifié, maintenons votre mémoire de traduction et générons des traductions précises tout en préservant la voix et la terminologie de votre marque. Les traductions sont ensuite soumises sous forme de pull requests, permettant une révision avant d'être fusionnées dans votre branche principale et déployées. Ce workflow automatisé garantit que votre contenu localisé reste synchronisé avec le développement.",
- },
- settings: {
- saved: "Paramètres enregistrés",
- savedDescription: "Vos modifications ont été enregistrées avec succès",
- tabs: {
- project: "Projet",
- account: "Compte",
- team: "Équipe",
- },
- project: {
- name: {
- title: "Nom du projet",
- description: "Le nom de votre projet",
- placeholder: "Entrez le nom du projet",
- },
- id: {
- title: "ID du projet",
- description: "Votre identifiant unique de projet",
- placeholder: "ID du projet",
- },
- delete: {
- title: "Supprimer le projet",
- description: "Supprimer définitivement ce projet et toutes ses données",
- button: "Supprimer le projet",
- },
- },
- team: {
- name: {
- title: "Nom de l'équipe",
- description: "Le nom de votre équipe",
- placeholder: "Entrez le nom de l'équipe",
- },
- billing: {
- title: "Plan de facturation",
- description: "Gérer le plan de facturation de votre équipe",
- free: "Gratuit",
- pro: "Pro",
- },
- apiKey: {
- title: "Clé API d'équipe",
- description: "Clé API pour l'accès d'équipe",
- placeholder: "Clé API d'équipe",
- },
- members: {
- title: "Membres",
- pendingInvitations: "Invitations en attente",
- filterPlaceholder: "Filtrer les membres...",
- allRoles: "Tous les rôles",
- date: "Date",
- selectAll: "{count} sélectionnés",
- noPendingInvitations: "Aucune invitation en attente",
- inviteMembers: "Inviter des membres d'équipe à collaborer",
- roles: {
- owner: "Propriétaire",
- admin: "Administrateur",
- member: "Membre",
- },
- dateSort: {
- newest: "Plus récent",
- oldest: "Plus ancien",
- },
- },
- },
- },
- tuning: {
- general: "Général",
- translationMemory: {
- title: "Mémoire de traduction",
- description:
- "Utiliser la mémoire de traduction pour améliorer la cohérence et l'efficacité",
- },
- qualityChecks: {
- title: "Contrôles qualité",
- description:
- "Activer les contrôles qualité automatisés pour les traductions",
- },
- contextDetection: {
- title: "Détection du contexte",
- description:
- "Détecter et préserver automatiquement le contexte dans les traductions",
- },
- styleGuide: "Guide de style",
- lengthControl: {
- title: "Contrôle de longueur",
- description: "Contrôler la longueur du texte traduit",
- options: {
- flexible: "Flexible",
- strict: "Strict",
- exact: "Exact",
- loose: "Souple",
- },
- },
- inclusiveLanguage: {
- title: "Langage inclusif",
- description:
- "Assurer l'utilisation d'un langage inclusif dans les traductions",
- },
- formality: {
- title: "Formalité",
- description: "Contrôler le niveau de formalité des traductions",
- },
- brandName: {
- title: "Nom de marque",
- description: "Définir votre nom de marque pour une utilisation cohérente",
- placeholder: "Entrez votre nom de marque",
- },
- brandVoice: {
- title: "Voix de marque",
- description: "Définir la voix et le ton de votre marque",
- placeholder: "Décrivez la voix de votre marque...",
- },
- localization: "Localisation",
- idioms: {
- title: "Expressions idiomatiques",
- description: "Gérer les expressions idiomatiques de manière appropriée",
- },
- terminology: {
- title: "Terminologie",
- description: "Gérer la terminologie spécialisée et les glossaires",
- },
- culturalAdaptation: {
- title: "Adaptation culturelle",
- description: "Adapter le contenu pour la pertinence culturelle",
- },
- },
- pricing: {
- title: "Tarification simple",
- free: {
- title: "Gratuit (100 clés)",
- price: "Gratuit",
- keys_limit: "Jusqu'à 100 clés",
- features: {
- unlimited_projects: "Projets illimités",
- fine_tuning: "Options de réglage fin",
- overrides: "Substitutions de traduction",
- analytics: "Analyses",
- context_memory: "Mémoire contextuelle",
- community_support: "Support communautaire",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Tout ce qui est inclus dans la version gratuite, plus :",
- features: {
- github_action: "Intégration GitHub Action",
- latest_features: "Accès anticipé aux nouvelles fonctionnalités",
- priority_support: "Support prioritaire",
- },
- },
- cta: "Commencer l'automatisation",
- },
-} as const;
diff --git a/apps/web/src/locales/ja.ts b/apps/web/src/locales/ja.ts
deleted file mode 100644
index 59b83d4..0000000
--- a/apps/web/src/locales/ja.ts
+++ /dev/null
@@ -1,305 +0,0 @@
-export default {
- header: {
- pricing: "料金",
- docs: "ドキュメント",
- signIn: "ログイン",
- goToApp: "アプリへ",
- },
- hero: {
- title: "アプリケーションのための自動ローカライゼーション",
- description:
- "開発者向けに設計されたAI搭載のCLIとパイプラインで、ローカライゼーションプロセスを効率化し、翻訳を自動化します。",
- },
- getStarted: {
- heading: "はじめる",
- title: "アプリケーションのための自動ローカライゼーション",
- description:
- "開発者向けに設計されたAI搭載のCLIとパイプラインで、ローカライゼーションプロセスを効率化し、翻訳を自動化します。",
- button: {
- startAutomating: "自動化を開始",
- readDocumentation: "ドキュメントを読む",
- },
- },
- companies: {
- title: "利用企業",
- addYourCompany: "+ 企業を追加",
- },
- activity: {
- title: "アクティビティ",
- },
- features: {
- title: "機能",
- fullyOpenSource: "完全オープンソース",
- fullyOpenSourceDescription:
- "コードはGitHubで公開されており、透明性とコミュニティの貢献を可能にしています。",
- noVendorLockIn: "ベンダーロックインなし",
- noVendorLockInDescription:
- "特定のサービスにロックインされることなく、独自のLLMを使用できます。",
- presetsForExpo: "Expo用プリセット",
- presetsForExpoDescription:
- "Expo用のプリセットを提供しており、すぐに始められます。",
- presetForReactNative: "React Native用プリセット",
- presetForReactNativeDescription:
- "React Native用のプリセットを提供しており、すぐに始められます。",
- presetForReactEmail: "React Emailライブラリ",
- presetForReactEmailDescription:
- "React Email用のi18nライブラリを作成しました。",
- readyForI18nLibraries: "i18nライブラリ対応",
- readyForI18nLibrariesDescription:
- "最も人気のあるライブラリ(next-intl、react-i18next、react-intlなど)を含むすべてのライブラリをサポートしています。",
- },
- info: {
- title: "アプリのローカライゼーションに関するあらゆる側面に対応",
- smartTranslation: {
- title: "スマート翻訳",
- intelligentTranslation: "コンテキストを理解したインテリジェントな翻訳",
- brandVoice: "ブランドボイスとトーンの一貫性",
- terminology: "用語管理",
- linguisticFeatures: "高度な言語機能",
- realtimeUpdates: "リアルタイム翻訳更新",
- },
- implementation: {
- title: "実装",
- quickSetup: "クイックセットアップと統合",
- fileFormat: "ファイル形式の処理",
- contentStructure: "コンテンツ構造の整理",
- assetOrganization: "アセットの整理",
- },
- developer: {
- title: "開発者エクスペリエンス",
- cli: "コマンドラインインターフェース",
- cicd: "CI/CD統合",
- versionControl: "バージョン管理",
- workflow: "開発者ワークフロー",
- documentation: "包括的なドキュメント",
- },
- },
- login: {
- title: "ログイン",
- github: "GitHubでログイン",
- google: "Googleでログイン",
- footer: "ローカライゼーションを自動化。",
- description: "ログインして数秒でローカライゼーションの自動化を開始。",
- terms: {
- text: "ログインすることで、以下に同意したことになります",
- termsOfService: "利用規約",
- and: "および",
- privacyPolicy: "プライバシーポリシー",
- },
- },
- translations: {
- total_keys: "合計{total}個のキー",
- },
- userMenu: {
- account: "アカウント設定",
- signOut: "ログアウト",
- createTeam: "チームを作成",
- homepage: "ホームページ",
- team: "チーム設定",
- },
- teamSelector: {
- addProject: "プロジェクトを追加",
- createProjectTitle: "新規プロジェクトを作成",
- projectNamePlaceholder: "プロジェクト名",
- createProjectButton: "プロジェクトを作成",
- pro: "プロ",
- project: "プロジェクト",
- teams: "チーム",
- createTeam: "チームを作成",
- createTeamTitle: "新規チームを作成",
- teamNamePlaceholder: "チーム名",
- createTeamButton: "チームを作成",
- },
- coming_soon: {
- title: "Languineはアーリーアクセス中です",
- description:
- "現在アーリーアクセス段階です。アーリーアクセスを希望される方は",
- cta: "までXでご連絡ください。",
- },
- account: {
- fullName: {
- title: "氏名",
- description: "プラットフォーム全体で表示される氏名です。",
- placeholder: "氏名を入力",
- },
- email: {
- title: "メールアドレス",
- description: "アカウントに関連付けられたメールアドレスです。",
- placeholder: "メールアドレスを入力",
- },
- apiKey: {
- title: "APIキー",
- description: "Languine APIにアクセスするための個人APIキーです。",
- },
- deleteAccount: {
- title: "アカウント削除",
- description:
- "アカウントと関連するすべてのデータを完全に削除します。この操作は取り消せません。",
- button: "アカウントを削除",
- },
- },
- copyInstall: {
- copied: "クリップボードにコピーしました",
- },
- dangerZone: {
- dialog: {
- title: "本当によろしいですか?",
- description:
- "この操作は取り消せません。確認のため「DELETE」と入力してください。",
- placeholder: "確認のため「DELETE」と入力",
- confirm: "削除を確認",
- },
- },
- pipeline: {
- title: "ワークフロー(CI/CDパイプライン)",
- pro: "[プロ]",
- description:
- "翻訳エンジンは既存のCI/CDパイプラインにシームレスに統合され、プッシュごとにコードベースを自動的に翻訳します。コードの変更がプッシュされると、変更されたコンテンツを分析し、翻訳メモリを維持し、ブランドボイスと用語を保持しながら正確な翻訳を生成します。翻訳はプルリクエストとして提出され、メインブランチへのマージとデプロイ前にレビューが可能です。この自動化されたワークフローにより、ローカライズされたコンテンツが開発と同期を保ちます。",
- },
- settings: {
- saved: "設定を保存しました",
- savedDescription: "変更が正常に保存されました",
- tabs: {
- project: "プロジェクト",
- account: "アカウント",
- team: "チーム",
- },
- project: {
- name: {
- title: "プロジェクト名",
- description: "プロジェクトの名前",
- placeholder: "プロジェクト名を入力",
- },
- id: {
- title: "プロジェクトID",
- description: "ユニークなプロジェクト識別子",
- placeholder: "プロジェクトID",
- },
- delete: {
- title: "プロジェクトの削除",
- description: "このプロジェクトとそのすべてのデータを完全に削除します",
- button: "プロジェクトを削除",
- },
- },
- team: {
- name: {
- title: "チーム名",
- description: "チームの名前",
- placeholder: "チーム名を入力",
- },
- billing: {
- title: "プラン",
- description: "チームの請求プランを管理",
- free: "無料",
- pro: "プロ",
- },
- apiKey: {
- title: "チームAPIキー",
- description: "チームアクセス用のAPIキー",
- placeholder: "チームAPIキー",
- },
- members: {
- title: "メンバー",
- pendingInvitations: "保留中の招待",
- filterPlaceholder: "メンバーを検索...",
- allRoles: "すべての役割",
- date: "日付",
- selectAll: "{count}件選択",
- noPendingInvitations: "保留中の招待はありません",
- inviteMembers: "コラボレーションのためにチームメンバーを招待",
- roles: {
- owner: "オーナー",
- admin: "管理者",
- member: "メンバー",
- },
- dateSort: {
- newest: "最新順",
- oldest: "古い順",
- },
- },
- },
- },
- tuning: {
- general: "一般",
- translationMemory: {
- title: "翻訳メモリ",
- description: "翻訳メモリを使用して一貫性と効率性を向上",
- },
- qualityChecks: {
- title: "品質チェック",
- description: "翻訳の自動品質チェックを有効化",
- },
- contextDetection: {
- title: "コンテキスト検出",
- description: "翻訳でのコンテキストを自動検出して保持",
- },
- styleGuide: "スタイルガイド",
- lengthControl: {
- title: "長さの制御",
- description: "翻訳テキストの長さを制御",
- options: {
- flexible: "柔軟",
- strict: "厳格",
- exact: "完全一致",
- loose: "緩和",
- },
- },
- inclusiveLanguage: {
- title: "インクルーシブな言語",
- description: "翻訳でインクルーシブな言語を使用",
- },
- formality: {
- title: "フォーマリティ",
- description: "翻訳の丁寧さレベルを制御",
- },
- brandName: {
- title: "ブランド名",
- description: "一貫した使用のためのブランド名を設定",
- placeholder: "ブランド名を入力",
- },
- brandVoice: {
- title: "ブランドボイス",
- description: "ブランドボイスとトーンを定義",
- placeholder: "ブランドボイスを説明...",
- },
- localization: "ローカライゼーション",
- idioms: {
- title: "慣用句",
- description: "慣用表現を適切に処理",
- },
- terminology: {
- title: "用語",
- description: "専門用語と用語集を管理",
- },
- culturalAdaptation: {
- title: "文化的適応",
- description: "文化的に適切なコンテンツに適応",
- },
- },
- pricing: {
- title: "シンプルな料金プラン",
- free: {
- title: "無料プラン(100キー)",
- price: "無料",
- keys_limit: "最大100キーまで",
- features: {
- unlimited_projects: "無制限のプロジェクト",
- fine_tuning: "微調整オプション",
- overrides: "翻訳の上書き",
- analytics: "分析機能",
- context_memory: "コンテキストメモリ",
- community_support: "コミュニティサポート",
- },
- },
- pro: {
- title: "プロプラン",
- includes_free: "無料プランのすべての機能に加えて:",
- features: {
- github_action: "GitHub Action連携",
- latest_features: "新機能への早期アクセス",
- priority_support: "優先サポート",
- },
- },
- cta: "自動化を始める",
- },
-} as const;
diff --git a/apps/web/src/locales/ko.ts b/apps/web/src/locales/ko.ts
deleted file mode 100644
index bce94a6..0000000
--- a/apps/web/src/locales/ko.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-export default {
- header: {
- pricing: "가격",
- docs: "문서",
- signIn: "로그인",
- goToApp: "앱으로 이동",
- },
- hero: {
- title: "애플리케이션을 위한 자동화된 현지화",
- description:
- "개발자를 위해 설계된 AI 기반 CLI와 파이프라인으로 현지화 프로세스를 간소화하고 번역을 자동화하세요.",
- },
- getStarted: {
- heading: "시작하기",
- title: "애플리케이션을 위한 자동화된 현지화",
- description:
- "개발자를 위해 설계된 AI 기반 CLI와 파이프라인으로 현지화 프로세스를 간소화하고 번역을 자동화하세요.",
- button: {
- startAutomating: "자동화 시작하기",
- readDocumentation: "문서 읽기",
- },
- },
- companies: {
- title: "사용 기업",
- addYourCompany: "+ 회사 추가하기",
- },
- activity: {
- title: "활동",
- },
- features: {
- title: "기능",
- fullyOpenSource: "완전한 오픈소스",
- fullyOpenSourceDescription:
- "우리의 코드는 GitHub에 공개되어 있어 투명성과 커뮤니티 기여를 가능하게 합니다.",
- noVendorLockIn: "벤더 종속성 없음",
- noVendorLockInDescription:
- "특정 서비스에 종속되지 않고 자신만의 LLM을 사용할 수 있습니다.",
- presetsForExpo: "Expo용 프리셋",
- presetsForExpoDescription:
- "Expo용 프리셋을 제공하여 빠르게 시작할 수 있습니다.",
- presetForReactNative: "React Native용 프리셋",
- presetForReactNativeDescription:
- "React Native용 프리셋을 제공하여 빠르게 시작할 수 있습니다.",
- presetForReactEmail: "React Email 라이브러리",
- presetForReactEmailDescription:
- "React Email을 위한 i18n 라이브러리를 만들었습니다.",
- readyForI18nLibraries: "i18n 라이브러리 지원",
- readyForI18nLibrariesDescription:
- "가장 인기 있는 라이브러리(next-intl, react-i18next, react-intl 등)를 포함한 모든 라이브러리를 지원합니다.",
- },
- info: {
- title: "앱 현지화의 모든 측면을 처리합니다",
- smartTranslation: {
- title: "스마트 번역",
- intelligentTranslation: "문맥을 인식하는 지능형 번역",
- brandVoice: "브랜드 톤앤매너 일관성",
- terminology: "용어 관리",
- linguisticFeatures: "고급 언어 기능",
- realtimeUpdates: "실시간 번역 업데이트",
- },
- implementation: {
- title: "구현",
- quickSetup: "빠른 설정 및 통합",
- fileFormat: "파일 형식 처리",
- contentStructure: "콘텐츠 구조 구성",
- assetOrganization: "자산 구성",
- },
- developer: {
- title: "개발자 경험",
- cli: "명령줄 인터페이스",
- cicd: "CI/CD 통합",
- versionControl: "버전 관리",
- workflow: "개발자 워크플로우",
- documentation: "포괄적인 문서",
- },
- },
- login: {
- title: "로그인",
- github: "GitHub로 로그인",
- google: "Google로 로그인",
- footer: "현지화를 자동화하세요.",
- description: "로그인하여 몇 초 만에 현지화 자동화를 시작하세요.",
- terms: {
- text: "로그인함으로써 다음에 동의합니다",
- termsOfService: "서비스 약관",
- and: "및",
- privacyPolicy: "개인정보 처리방침",
- },
- },
- translations: {
- total_keys: "총 {total}개의 키",
- },
- userMenu: {
- account: "계정 설정",
- signOut: "로그아웃",
- createTeam: "팀 만들기",
- homepage: "홈페이지",
- team: "팀 설정",
- },
- teamSelector: {
- addProject: "프로젝트 추가",
- createProjectTitle: "새 프로젝트 만들기",
- projectNamePlaceholder: "프로젝트 이름",
- createProjectButton: "프로젝트 만들기",
- pro: "프로",
- project: "프로젝트",
- teams: "팀",
- createTeam: "팀 만들기",
- createTeamTitle: "새 팀 만들기",
- teamNamePlaceholder: "팀 이름",
- createTeamButton: "팀 만들기",
- },
- coming_soon: {
- title: "Languine은 얼리 액세스 중입니다",
- description: "현재 얼리 액세스 중입니다. 연락주세요",
- cta: "X에서 얼리 액세스를 받으세요.",
- },
- account: {
- fullName: {
- title: "이름",
- description: "플랫폼 전체에 표시될 이름입니다.",
- placeholder: "이름을 입력하세요",
- },
- email: {
- title: "이메일 주소",
- description: "계정과 연결된 이메일 주소입니다.",
- placeholder: "이메일 주소를 입력하세요",
- },
- apiKey: {
- title: "API 키",
- description: "Languine API 접근을 위한 개인 API 키입니다.",
- },
- deleteAccount: {
- title: "계정 삭제",
- description:
- "계정과 관련된 모든 데이터를 영구적으로 삭제합니다. 이 작업은 취소할 수 없습니다.",
- button: "계정 삭제",
- },
- },
- copyInstall: {
- copied: "클립보드에 복사됨",
- },
- dangerZone: {
- dialog: {
- title: "정말 확실합니까?",
- description:
- "이 작업은 취소할 수 없습니다. 확인을 위해 DELETE를 입력하세요.",
- placeholder: "DELETE를 입력하여 확인",
- confirm: "삭제 확인",
- },
- },
- pipeline: {
- title: "워크플로우 (CI/CD 파이프라인)",
- pro: "[프로]",
- description:
- "우리의 번역 엔진은 기존 CI/CD 파이프라인에 원활하게 통합되어 모든 푸시에서 코드베이스를 자동으로 번역합니다. 코드 변경이 푸시되면 수정된 내용을 분석하고, 번역 메모리를 유지하며, 브랜드 톤앤매너와 용어를 보존하면서 정확한 번역을 생성합니다. 번역은 풀 리퀘스트로 제출되어 메인 브랜치에 병합되고 배포되기 전에 검토할 수 있습니다. 이 자동화된 워크플로우는 현지화된 콘텐츠가 개발과 동기화되도록 보장합니다.",
- },
- settings: {
- saved: "설정 저장됨",
- savedDescription: "변경사항이 성공적으로 저장되었습니다",
- tabs: {
- project: "프로젝트",
- account: "계정",
- team: "팀",
- },
- project: {
- name: {
- title: "프로젝트 이름",
- description: "프로젝트의 이름",
- placeholder: "프로젝트 이름 입력",
- },
- id: {
- title: "프로젝트 ID",
- description: "고유한 프로젝트 식별자",
- placeholder: "프로젝트 ID",
- },
- delete: {
- title: "프로젝트 삭제",
- description: "이 프로젝트와 모든 데이터를 영구적으로 삭제",
- button: "프로젝트 삭제",
- },
- },
- team: {
- name: {
- title: "팀 이름",
- description: "팀의 이름",
- placeholder: "팀 이름 입력",
- },
- billing: {
- title: "결제 플랜",
- description: "팀의 결제 플랜 관리",
- free: "무료",
- pro: "프로",
- },
- apiKey: {
- title: "팀 API 키",
- description: "팀 접근을 위한 API 키",
- placeholder: "팀 API 키",
- },
- members: {
- title: "멤버",
- pendingInvitations: "대기 중인 초대",
- filterPlaceholder: "멤버 필터링...",
- allRoles: "모든 역할",
- date: "날짜",
- selectAll: "{count}개 선택됨",
- noPendingInvitations: "대기 중인 초대 없음",
- inviteMembers: "협업할 팀 멤버 초대",
- roles: {
- owner: "소유자",
- admin: "관리자",
- member: "멤버",
- },
- dateSort: {
- newest: "최신순",
- oldest: "오래된순",
- },
- },
- },
- },
- tuning: {
- general: "일반",
- translationMemory: {
- title: "번역 메모리",
- description: "번역 메모리를 사용하여 일관성과 효율성을 향상시킵니다",
- },
- qualityChecks: {
- title: "품질 검사",
- description: "번역에 대한 자동화된 품질 검사 활성화",
- },
- contextDetection: {
- title: "문맥 감지",
- description: "번역에서 문맥을 자동으로 감지하고 보존",
- },
- styleGuide: "스타일 가이드",
- lengthControl: {
- title: "길이 제어",
- description: "번역된 텍스트의 길이 제어",
- options: {
- flexible: "유연",
- strict: "엄격",
- exact: "정확",
- loose: "느슨",
- },
- },
- inclusiveLanguage: {
- title: "포용적 언어",
- description: "번역에서 포용적 언어 사용 보장",
- },
- formality: {
- title: "격식",
- description: "번역의 격식 수준 제어",
- },
- brandName: {
- title: "브랜드 이름",
- description: "일관된 사용을 위한 브랜드 이름 설정",
- placeholder: "브랜드 이름 입력",
- },
- brandVoice: {
- title: "브랜드 톤앤매너",
- description: "브랜드의 톤앤매너 정의",
- placeholder: "브랜드 톤앤매너 설명...",
- },
- localization: "현지화",
- idioms: {
- title: "관용구",
- description: "관용적 표현의 적절한 처리",
- },
- terminology: {
- title: "용어",
- description: "전문 용어 및 용어집 관리",
- },
- culturalAdaptation: {
- title: "문화적 적응",
- description: "문화적 적절성을 위한 콘텐츠 조정",
- },
- },
- pricing: {
- title: "심플한 가격",
- free: {
- title: "무료 (100개 키)",
- price: "무료",
- keys_limit: "최대 100개 키",
- features: {
- unlimited_projects: "무제한 프로젝트",
- fine_tuning: "미세 조정 옵션",
- overrides: "번역 재정의",
- analytics: "분석",
- context_memory: "문맥 메모리",
- community_support: "커뮤니티 지원",
- },
- },
- pro: {
- title: "프로",
- includes_free: "무료 버전의 모든 기능에 추가로:",
- features: {
- github_action: "GitHub Action 통합",
- latest_features: "최신 기능 조기 액세스",
- priority_support: "우선 지원",
- },
- },
- cta: "자동화 시작하기",
- },
-} as const;
diff --git a/apps/web/src/locales/no.ts b/apps/web/src/locales/no.ts
deleted file mode 100644
index 6d19104..0000000
--- a/apps/web/src/locales/no.ts
+++ /dev/null
@@ -1,307 +0,0 @@
-export default {
- header: {
- pricing: "Priser",
- docs: "Dokumentasjon",
- signIn: "Logg inn",
- goToApp: "Gå til app",
- },
- hero: {
- title: "Automatisert lokalisering for dine applikasjoner",
- description:
- "Effektiviser lokaliseringsprosessen med en AI-drevet CLI og pipeline designet for å automatisere oversettelser for utviklere.",
- },
- getStarted: {
- heading: "Kom i gang",
- title: "Automatisert lokalisering for dine applikasjoner",
- description:
- "Effektiviser lokaliseringsprosessen med en AI-drevet CLI og pipeline designet for å automatisere oversettelser for utviklere.",
- button: {
- startAutomating: "Start automatisering",
- readDocumentation: "Les dokumentasjon",
- },
- },
- companies: {
- title: "Brukt av",
- addYourCompany: "+ Legg til din bedrift",
- },
- activity: {
- title: "Aktivitet",
- },
- features: {
- title: "Funksjoner",
- fullyOpenSource: "Helt åpen kildekode",
- fullyOpenSourceDescription:
- "Vår kode er offentlig tilgjengelig på GitHub, som muliggjør åpenhet og bidrag fra fellesskapet.",
- noVendorLockIn: "Ingen leverandørlås",
- noVendorLockInDescription:
- "Vi låser deg ikke til en bestemt tjeneste, bruk dine egne LLMs.",
- presetsForExpo: "Forhåndsinnstillinger for Expo",
- presetsForExpoDescription:
- "Vi tilbyr forhåndsinnstillinger for Expo, slik at du kan komme raskt i gang.",
- presetForReactNative: "Forhåndsinnstilling for React Native",
- presetForReactNativeDescription:
- "Vi tilbyr en forhåndsinnstilling for React Native, slik at du kan komme raskt i gang.",
- presetForReactEmail: "React Email-bibliotek",
- presetForReactEmailDescription:
- "Vi har laget et i18n-bibliotek for React Email.",
- readyForI18nLibraries: "Klar for i18n-biblioteker",
- readyForI18nLibrariesDescription:
- "Vi støtter alle biblioteker inkludert de mest populære (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title: "Håndterer alle aspekter ved lokalisering av appen din, inkludert",
- smartTranslation: {
- title: "Smart oversettelse",
- intelligentTranslation: "Intelligent oversettelse med kontekstbevissthet",
- brandVoice: "Merkevareidentitet og tonekonsekvens",
- terminology: "Terminologihåndtering",
- linguisticFeatures: "Avanserte språkfunksjoner",
- realtimeUpdates: "Sanntidsoppdateringer av oversettelser",
- },
- implementation: {
- title: "Implementering",
- quickSetup: "Rask oppsett og integrasjon",
- fileFormat: "Filformathåndtering",
- contentStructure: "Innholdsstrukturorganisering",
- assetOrganization: "Ressursorganisering",
- },
- developer: {
- title: "Utvikleropplevelse",
- cli: "Kommandolinjegrensesnitt",
- cicd: "CI/CD-integrasjon",
- versionControl: "Versjonskontroll",
- workflow: "Utviklerarbeidsflyt",
- documentation: "Omfattende dokumentasjon",
- },
- },
- login: {
- title: "Logg inn",
- github: "Logg inn med GitHub",
- google: "Logg inn med Google",
- footer: "Automatiser lokaliseringen din.",
- description:
- "Logg inn for å begynne å automatisere lokaliseringen din på sekunder.",
- terms: {
- text: "Ved å logge inn godtar du våre",
- termsOfService: "Tjenestevilkår",
- and: "og",
- privacyPolicy: "Personvernregler",
- },
- },
- translations: {
- total_keys: "{total} nøkler totalt",
- },
- userMenu: {
- account: "Kontoinnstillinger",
- signOut: "Logg ut",
- createTeam: "Opprett team",
- homepage: "Hjemmeside",
- team: "Teaminnstillinger",
- },
- teamSelector: {
- addProject: "Legg til prosjekt",
- createProjectTitle: "Opprett et nytt prosjekt",
- projectNamePlaceholder: "Prosjektnavn",
- createProjectButton: "Opprett prosjekt",
- pro: "Pro",
- project: "Prosjekt",
- teams: "Team",
- createTeam: "Opprett team",
- createTeamTitle: "Opprett et nytt team",
- teamNamePlaceholder: "Teamnavn",
- createTeamButton: "Opprett team",
- },
- coming_soon: {
- title: "Languine er i tidlig tilgang",
- description: "Vi er for tiden i tidlig tilgang. Ta kontakt med",
- cta: "på X for å få tidlig tilgang.",
- },
- account: {
- fullName: {
- title: "Fullt navn",
- description: "Ditt fulle navn som vil vises på tvers av plattformen.",
- placeholder: "Skriv inn ditt fulle navn",
- },
- email: {
- title: "E-postadresse",
- description: "E-postadressen tilknyttet kontoen din.",
- placeholder: "Skriv inn din e-postadresse",
- },
- apiKey: {
- title: "API-nøkkel",
- description: "Din personlige API-nøkkel for tilgang til Languine API.",
- },
- deleteAccount: {
- title: "Slett konto",
- description:
- "Slett kontoen din permanent og alle tilknyttede data. Denne handlingen kan ikke angres.",
- button: "Slett konto",
- },
- },
- copyInstall: {
- copied: "Kopiert til utklippstavlen",
- },
- dangerZone: {
- dialog: {
- title: "Er du helt sikker?",
- description:
- "Denne handlingen kan ikke angres. Vennligst skriv DELETE for å bekrefte.",
- placeholder: "Skriv DELETE for å bekrefte",
- confirm: "Bekreft sletting",
- },
- },
- pipeline: {
- title: "Arbeidsflyt (CI/CD-pipeline)",
- pro: "[pro]",
- description:
- "Vår oversettelsesmotor integreres sømløst i din eksisterende CI/CD-pipeline og oversetter automatisk kodebasen din ved hver push. Når kodeendringer pushes, analyserer vi det modifiserte innholdet, vedlikeholder oversettelsesminnet ditt og genererer nøyaktige oversettelser mens vi bevarer din merkevareidentitet og terminologi. Oversettelsene sendes deretter som pull requests, som tillater gjennomgang før de flettes inn i hovedgrenen din og distribueres. Denne automatiserte arbeidsflyten sikrer at det lokaliserte innholdet ditt holder seg synkronisert med utviklingen.",
- },
- settings: {
- saved: "Innstillinger lagret",
- savedDescription: "Endringene dine har blitt lagret",
- tabs: {
- project: "Prosjekt",
- account: "Konto",
- team: "Team",
- },
- project: {
- name: {
- title: "Prosjektnavn",
- description: "Navnet på prosjektet ditt",
- placeholder: "Skriv inn prosjektnavn",
- },
- id: {
- title: "Prosjekt-ID",
- description: "Din unike prosjektidentifikator",
- placeholder: "Prosjekt-ID",
- },
- delete: {
- title: "Slett prosjekt",
- description: "Slett dette prosjektet permanent og alle dets data",
- button: "Slett prosjekt",
- },
- },
- team: {
- name: {
- title: "Teamnavn",
- description: "Navnet på teamet ditt",
- placeholder: "Skriv inn teamnavn",
- },
- billing: {
- title: "Fakturaplan",
- description: "Administrer teamets fakturaplan",
- free: "Gratis",
- pro: "Pro",
- },
- apiKey: {
- title: "Team API-nøkkel",
- description: "API-nøkkel for teamtilgang",
- placeholder: "Team API-nøkkel",
- },
- members: {
- title: "Medlemmer",
- pendingInvitations: "Ventende invitasjoner",
- filterPlaceholder: "Filtrer medlemmer...",
- allRoles: "Alle roller",
- date: "Dato",
- selectAll: "{count} valgt",
- noPendingInvitations: "Ingen ventende invitasjoner",
- inviteMembers: "Inviter teammedlemmer til å samarbeide",
- roles: {
- owner: "Eier",
- admin: "Administrator",
- member: "Medlem",
- },
- dateSort: {
- newest: "Nyeste",
- oldest: "Eldste",
- },
- },
- },
- },
- tuning: {
- general: "Generelt",
- translationMemory: {
- title: "Oversettelsesminne",
- description:
- "Bruk oversettelsesminne for å forbedre konsistens og effektivitet",
- },
- qualityChecks: {
- title: "Kvalitetskontroller",
- description:
- "Aktiver automatiserte kvalitetskontroller for oversettelser",
- },
- contextDetection: {
- title: "Kontekstoppdagelse",
- description: "Automatisk oppdage og bevare kontekst i oversettelser",
- },
- styleGuide: "Stilguide",
- lengthControl: {
- title: "Lengdekontroll",
- description: "Kontroller lengden på oversatt tekst",
- options: {
- flexible: "Fleksibel",
- strict: "Streng",
- exact: "Eksakt",
- loose: "Løs",
- },
- },
- inclusiveLanguage: {
- title: "Inkluderende språk",
- description: "Sikre at oversettelser bruker inkluderende språk",
- },
- formality: {
- title: "Formalitet",
- description: "Kontroller formalitetsnivået i oversettelser",
- },
- brandName: {
- title: "Merkenavn",
- description: "Angi merkenavnet ditt for konsistent bruk",
- placeholder: "Skriv inn merkenavnet ditt",
- },
- brandVoice: {
- title: "Merkevareidentitet",
- description: "Definer din merkevareidentitet og tone",
- placeholder: "Beskriv din merkevareidentitet...",
- },
- localization: "Lokalisering",
- idioms: {
- title: "Idiomer",
- description: "Håndter idiomatiske uttrykk på riktig måte",
- },
- terminology: {
- title: "Terminologi",
- description: "Administrer spesialisert terminologi og ordlister",
- },
- culturalAdaptation: {
- title: "Kulturell tilpasning",
- description: "Tilpass innhold for kulturell egnethet",
- },
- },
- pricing: {
- title: "Enkel prising",
- free: {
- title: "Gratis (100 nøkler)",
- price: "Gratis",
- keys_limit: "Opptil 100 nøkler",
- features: {
- unlimited_projects: "Ubegrensede prosjekter",
- fine_tuning: "Finjusteringsalternativer",
- overrides: "Oversettelsesoverskrivinger",
- analytics: "Analyser",
- context_memory: "Kontekstminne",
- community_support: "Fellesskapsstøtte",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Alt i Gratis, pluss:",
- features: {
- github_action: "GitHub Action-integrasjon",
- latest_features: "Tidlig tilgang til nye funksjoner",
- priority_support: "Prioritert støtte",
- },
- },
- cta: "Start automatisering",
- },
-} as const;
diff --git a/apps/web/src/locales/pt.ts b/apps/web/src/locales/pt.ts
deleted file mode 100644
index 8115e67..0000000
--- a/apps/web/src/locales/pt.ts
+++ /dev/null
@@ -1,310 +0,0 @@
-export default {
- header: {
- pricing: "Preços",
- docs: "Documentação",
- signIn: "Entrar",
- goToApp: "Ir para o app",
- },
- hero: {
- title: "Localização automatizada para suas aplicações",
- description:
- "Simplifique seu processo de localização com uma CLI e pipeline alimentados por IA, projetados para automatizar traduções para desenvolvedores.",
- },
- getStarted: {
- heading: "Começar",
- title: "Localização automatizada para suas aplicações",
- description:
- "Simplifique seu processo de localização com uma CLI e pipeline alimentados por IA, projetados para automatizar traduções para desenvolvedores.",
- button: {
- startAutomating: "Começar a automatizar",
- readDocumentation: "Ler documentação",
- },
- },
- companies: {
- title: "Usado por",
- addYourCompany: "+ Adicione sua empresa",
- },
- activity: {
- title: "Atividade",
- },
- features: {
- title: "Recursos",
- fullyOpenSource: "Totalmente código aberto",
- fullyOpenSourceDescription:
- "Nosso código está disponível publicamente no GitHub, permitindo transparência e contribuições da comunidade.",
- noVendorLockIn: "Sem bloqueio de fornecedor",
- noVendorLockInDescription:
- "Não te prendemos a um serviço específico, use seus próprios LLMs.",
- presetsForExpo: "Predefinições para Expo",
- presetsForExpoDescription:
- "Fornecemos predefinições para Expo, para que você possa começar rapidamente.",
- presetForReactNative: "Predefinição para React Native",
- presetForReactNativeDescription:
- "Fornecemos uma predefinição para React Native, para que você possa começar rapidamente.",
- presetForReactEmail: "Biblioteca React Email",
- presetForReactEmailDescription:
- "Criamos uma biblioteca i18n para React Email.",
- readyForI18nLibraries: "Pronto para bibliotecas i18n",
- readyForI18nLibrariesDescription:
- "Suportamos todas as bibliotecas, incluindo as mais populares (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title: "Lida com todos os aspectos da localização do seu app, incluindo",
- smartTranslation: {
- title: "Tradução Inteligente",
- intelligentTranslation:
- "Tradução inteligente com consciência de contexto",
- brandVoice: "Consistência de voz e tom da marca",
- terminology: "Gestão de terminologia",
- linguisticFeatures: "Recursos linguísticos avançados",
- realtimeUpdates: "Atualizações de tradução em tempo real",
- },
- implementation: {
- title: "Implementação",
- quickSetup: "Configuração e integração rápidas",
- fileFormat: "Manipulação de formato de arquivo",
- contentStructure: "Organização da estrutura de conteúdo",
- assetOrganization: "Organização de recursos",
- },
- developer: {
- title: "Experiência do Desenvolvedor",
- cli: "Interface de linha de comando",
- cicd: "Integração CI/CD",
- versionControl: "Controle de versão",
- workflow: "Fluxo de trabalho do desenvolvedor",
- documentation: "Documentação abrangente",
- },
- },
- login: {
- title: "Entrar",
- github: "Entrar com GitHub",
- google: "Entrar com Google",
- footer: "Automatize sua localização.",
- description:
- "Entre para começar a automatizar sua localização em segundos.",
- terms: {
- text: "Ao entrar, você concorda com nossos",
- termsOfService: "Termos de Serviço",
- and: "e",
- privacyPolicy: "Política de Privacidade",
- },
- },
- translations: {
- total_keys: "{total} chaves no total",
- },
- userMenu: {
- account: "Configurações da Conta",
- signOut: "Sair",
- createTeam: "Criar equipe",
- homepage: "Página inicial",
- team: "Configurações da Equipe",
- },
- teamSelector: {
- addProject: "Adicionar projeto",
- createProjectTitle: "Criar um novo projeto",
- projectNamePlaceholder: "Nome do projeto",
- createProjectButton: "Criar projeto",
- pro: "Pro",
- project: "Projeto",
- teams: "Equipes",
- createTeam: "Criar equipe",
- createTeamTitle: "Criar uma nova equipe",
- teamNamePlaceholder: "Nome da equipe",
- createTeamButton: "Criar equipe",
- },
- coming_soon: {
- title: "Languine está em Acesso Antecipado",
- description:
- "Atualmente estamos em acesso antecipado. Entre em contato com",
- cta: "no X para obter acesso antecipado.",
- },
- account: {
- fullName: {
- title: "Nome Completo",
- description: "Seu nome completo como aparecerá em toda a plataforma.",
- placeholder: "Digite seu nome completo",
- },
- email: {
- title: "Endereço de Email",
- description: "O endereço de email associado à sua conta.",
- placeholder: "Digite seu endereço de email",
- },
- apiKey: {
- title: "Chave API",
- description: "Sua chave API pessoal para acessar a API do Languine.",
- },
- deleteAccount: {
- title: "Excluir Conta",
- description:
- "Exclua permanentemente sua conta e todos os dados associados. Esta ação não pode ser desfeita.",
- button: "Excluir Conta",
- },
- },
- copyInstall: {
- copied: "Copiado para a área de transferência",
- },
- dangerZone: {
- dialog: {
- title: "Você tem certeza absoluta?",
- description:
- "Esta ação não pode ser desfeita. Digite DELETE para confirmar.",
- placeholder: "Digite DELETE para confirmar",
- confirm: "Confirmar Exclusão",
- },
- },
- pipeline: {
- title: "Fluxo de Trabalho (Pipeline CI/CD)",
- pro: "[pro]",
- description:
- "Nosso mecanismo de tradução se integra perfeitamente ao seu pipeline CI/CD existente, traduzindo automaticamente sua base de código a cada push. Quando as alterações de código são enviadas, analisamos o conteúdo modificado, mantemos sua memória de tradução e geramos traduções precisas, preservando a voz e terminologia da sua marca. As traduções são então enviadas como pull requests, permitindo revisão antes de serem mescladas em seu branch principal e implantadas. Este fluxo de trabalho automatizado garante que seu conteúdo localizado permaneça sincronizado com o desenvolvimento.",
- },
- settings: {
- saved: "Configurações salvas",
- savedDescription: "Suas alterações foram salvas com sucesso",
- tabs: {
- project: "Projeto",
- account: "Conta",
- team: "Equipe",
- },
- project: {
- name: {
- title: "Nome do Projeto",
- description: "O nome do seu projeto",
- placeholder: "Digite o nome do projeto",
- },
- id: {
- title: "ID do Projeto",
- description: "Seu identificador único de projeto",
- placeholder: "ID do Projeto",
- },
- delete: {
- title: "Excluir Projeto",
- description:
- "Excluir permanentemente este projeto e todos os seus dados",
- button: "Excluir Projeto",
- },
- },
- team: {
- name: {
- title: "Nome da Equipe",
- description: "O nome da sua equipe",
- placeholder: "Digite o nome da equipe",
- },
- billing: {
- title: "Plano de Cobrança",
- description: "Gerencie o plano de cobrança da sua equipe",
- free: "Gratuito",
- pro: "Pro",
- },
- apiKey: {
- title: "Chave API da Equipe",
- description: "Chave API para acesso da equipe",
- placeholder: "Chave API da Equipe",
- },
- members: {
- title: "Membros",
- pendingInvitations: "Convites Pendentes",
- filterPlaceholder: "Filtrar membros...",
- allRoles: "Todas as Funções",
- date: "Data",
- selectAll: "{count} selecionados",
- noPendingInvitations: "Sem convites pendentes",
- inviteMembers: "Convide membros da equipe para colaborar",
- roles: {
- owner: "Proprietário",
- admin: "Administrador",
- member: "Membro",
- },
- dateSort: {
- newest: "Mais recente",
- oldest: "Mais antigo",
- },
- },
- },
- },
- tuning: {
- general: "Geral",
- translationMemory: {
- title: "Memória de Tradução",
- description:
- "Use memória de tradução para melhorar consistência e eficiência",
- },
- qualityChecks: {
- title: "Verificações de Qualidade",
- description: "Ative verificações automáticas de qualidade para traduções",
- },
- contextDetection: {
- title: "Detecção de Contexto",
- description:
- "Detecte e preserve automaticamente o contexto nas traduções",
- },
- styleGuide: "Guia de Estilo",
- lengthControl: {
- title: "Controle de Comprimento",
- description: "Controle o comprimento do texto traduzido",
- options: {
- flexible: "Flexível",
- strict: "Rigoroso",
- exact: "Exato",
- loose: "Livre",
- },
- },
- inclusiveLanguage: {
- title: "Linguagem Inclusiva",
- description: "Garanta que as traduções usem linguagem inclusiva",
- },
- formality: {
- title: "Formalidade",
- description: "Controle o nível de formalidade das traduções",
- },
- brandName: {
- title: "Nome da Marca",
- description: "Defina o nome da sua marca para uso consistente",
- placeholder: "Digite o nome da sua marca",
- },
- brandVoice: {
- title: "Voz da Marca",
- description: "Defina a voz e o tom da sua marca",
- placeholder: "Descreva a voz da sua marca...",
- },
- localization: "Localização",
- idioms: {
- title: "Expressões Idiomáticas",
- description: "Lide apropriadamente com expressões idiomáticas",
- },
- terminology: {
- title: "Terminologia",
- description: "Gerencie terminologia especializada e glossários",
- },
- culturalAdaptation: {
- title: "Adaptação Cultural",
- description: "Adapte o conteúdo para adequação cultural",
- },
- },
- pricing: {
- title: "Preços simples",
- free: {
- title: "Gratuito (100 chaves)",
- price: "Gratuito",
- keys_limit: "Até 100 chaves",
- features: {
- unlimited_projects: "Projetos ilimitados",
- fine_tuning: "Opções de ajuste fino",
- overrides: "Substituições de tradução",
- analytics: "Análises",
- context_memory: "Memória de contexto",
- community_support: "Suporte da comunidade",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Tudo do plano Gratuito, mais:",
- features: {
- github_action: "Integração com GitHub Action",
- latest_features: "Acesso antecipado a novos recursos",
- priority_support: "Suporte prioritário",
- },
- },
- cta: "Começar a automatizar",
- },
-} as const;
diff --git a/apps/web/src/locales/server.ts b/apps/web/src/locales/server.ts
index 95014df..762c8bc 100644
--- a/apps/web/src/locales/server.ts
+++ b/apps/web/src/locales/server.ts
@@ -2,15 +2,15 @@ import { createI18nServer } from "next-international/server";
export const { getI18n, getScopedI18n, getStaticParams } = createI18nServer({
en: () => import("./en"),
- fr: () => import("./fr"),
- es: () => import("./es"),
- de: () => import("./de"),
- no: () => import("./no"),
- sv: () => import("./sv"),
- fi: () => import("./fi"),
- pt: () => import("./pt"),
- ar: () => import("./ar"),
- ja: () => import("./ja"),
- ko: () => import("./ko"),
- zh: () => import("./zh"),
+ // fr: () => import("./fr"),
+ // es: () => import("./es"),
+ // de: () => import("./de"),
+ // no: () => import("./no"),
+ // sv: () => import("./sv"),
+ // fi: () => import("./fi"),
+ // pt: () => import("./pt"),
+ // ar: () => import("./ar"),
+ // ja: () => import("./ja"),
+ // ko: () => import("./ko"),
+ // zh: () => import("./zh"),
});
diff --git a/apps/web/src/locales/sv.ts b/apps/web/src/locales/sv.ts
deleted file mode 100644
index bc1d7f6..0000000
--- a/apps/web/src/locales/sv.ts
+++ /dev/null
@@ -1,308 +0,0 @@
-export default {
- header: {
- pricing: "Priser",
- docs: "Dokumentation",
- signIn: "Logga in",
- goToApp: "Gå till appen",
- },
- hero: {
- title: "Automatiserad lokalisering för dina applikationer",
- description:
- "Effektivisera din lokaliseringsprocess med en AI-driven CLI och pipeline utformad för att automatisera översättningar för utvecklare.",
- },
- getStarted: {
- heading: "Kom igång",
- title: "Automatiserad lokalisering för dina applikationer",
- description:
- "Effektivisera din lokaliseringsprocess med en AI-driven CLI och pipeline utformad för att automatisera översättningar för utvecklare.",
- button: {
- startAutomating: "Börja automatisera",
- readDocumentation: "Läs dokumentationen",
- },
- },
- companies: {
- title: "Används av",
- addYourCompany: "+ Lägg till ditt företag",
- },
- activity: {
- title: "Aktivitet",
- },
- features: {
- title: "Funktioner",
- fullyOpenSource: "Helt öppen källkod",
- fullyOpenSourceDescription:
- "Vår kod är offentligt tillgänglig på GitHub, vilket möjliggör transparens och bidrag från communityn.",
- noVendorLockIn: "Ingen leverantörsinlåsning",
- noVendorLockInDescription:
- "Vi låser inte in dig i en specifik tjänst, använd dina egna LLMs.",
- presetsForExpo: "Förinställningar för Expo",
- presetsForExpoDescription:
- "Vi tillhandahåller förinställningar för Expo, så att du snabbt kan komma igång.",
- presetForReactNative: "Förinställning för React Native",
- presetForReactNativeDescription:
- "Vi tillhandahåller en förinställning för React Native, så att du snabbt kan komma igång.",
- presetForReactEmail: "React Email-bibliotek",
- presetForReactEmailDescription:
- "Vi har skapat ett i18n-bibliotek för React Email.",
- readyForI18nLibraries: "Redo för i18n-bibliotek",
- readyForI18nLibrariesDescription:
- "Vi stödjer alla bibliotek inklusive de mest populära (next-intl, react-i18next, react-intl, etc).",
- },
- info: {
- title: "Hanterar alla aspekter av lokalisering av din app inklusive",
- smartTranslation: {
- title: "Smart översättning",
- intelligentTranslation: "Intelligent översättning med kontextmedvetenhet",
- brandVoice: "Varumärkesröst och tonkonsistens",
- terminology: "Terminologihantering",
- linguisticFeatures: "Avancerade språkfunktioner",
- realtimeUpdates: "Översättningsuppdateringar i realtid",
- },
- implementation: {
- title: "Implementering",
- quickSetup: "Snabb installation och integration",
- fileFormat: "Filformatshantering",
- contentStructure: "Innehållsstrukturorganisation",
- assetOrganization: "Tillgångsorganisation",
- },
- developer: {
- title: "Utvecklarupplevelse",
- cli: "Kommandoradsgränssnitt",
- cicd: "CI/CD-integration",
- versionControl: "Versionskontroll",
- workflow: "Utvecklararbetsflöde",
- documentation: "Omfattande dokumentation",
- },
- },
- login: {
- title: "Logga in",
- github: "Logga in med GitHub",
- google: "Logga in med Google",
- footer: "Automatisera din lokalisering.",
- description:
- "Logga in för att börja automatisera din lokalisering på några sekunder.",
- terms: {
- text: "Genom att logga in godkänner du våra",
- termsOfService: "Användarvillkor",
- and: "och",
- privacyPolicy: "Integritetspolicy",
- },
- },
- translations: {
- total_keys: "{total} nycklar totalt",
- },
- userMenu: {
- account: "Kontoinställningar",
- signOut: "Logga ut",
- createTeam: "Skapa team",
- homepage: "Hemsida",
- team: "Teaminställningar",
- },
- teamSelector: {
- addProject: "Lägg till projekt",
- createProjectTitle: "Skapa ett nytt projekt",
- projectNamePlaceholder: "Projektnamn",
- createProjectButton: "Skapa projekt",
- pro: "Pro",
- project: "Projekt",
- teams: "Team",
- createTeam: "Skapa team",
- createTeamTitle: "Skapa ett nytt team",
- teamNamePlaceholder: "Teamnamn",
- createTeamButton: "Skapa team",
- },
- coming_soon: {
- title: "Languine är i tidig åtkomst",
- description: "Vi är för närvarande i tidig åtkomst. Kontakta",
- cta: "på X för att få tidig åtkomst.",
- },
- account: {
- fullName: {
- title: "Fullständigt namn",
- description:
- "Ditt fullständiga namn som det kommer att visas på plattformen.",
- placeholder: "Ange ditt fullständiga namn",
- },
- email: {
- title: "E-postadress",
- description: "E-postadressen som är kopplad till ditt konto.",
- placeholder: "Ange din e-postadress",
- },
- apiKey: {
- title: "API-nyckel",
- description: "Din personliga API-nyckel för åtkomst till Languine API.",
- },
- deleteAccount: {
- title: "Radera konto",
- description:
- "Radera permanent ditt konto och all tillhörande data. Denna åtgärd kan inte ångras.",
- button: "Radera konto",
- },
- },
- copyInstall: {
- copied: "Kopierat till urklipp",
- },
- dangerZone: {
- dialog: {
- title: "Är du helt säker?",
- description:
- "Denna åtgärd kan inte ångras. Skriv DELETE för att bekräfta.",
- placeholder: "Skriv DELETE för att bekräfta",
- confirm: "Bekräfta radering",
- },
- },
- pipeline: {
- title: "Arbetsflöde (CI/CD Pipeline)",
- pro: "[pro]",
- description:
- "Vår översättningsmotor integreras sömlöst i din befintliga CI/CD-pipeline och översätter automatiskt din kodbas vid varje push. När kodändringar pushas analyserar vi det modifierade innehållet, upprätthåller ditt översättningsminne och genererar korrekta översättningar samtidigt som vi bevarar din varumärkesröst och terminologi. Översättningarna skickas sedan som pull requests, vilket möjliggör granskning innan de slås samman med din huvudgren och distribueras. Detta automatiserade arbetsflöde säkerställer att ditt lokaliserade innehåll hålls synkroniserat med utvecklingen.",
- },
- settings: {
- saved: "Inställningar sparade",
- savedDescription: "Dina ändringar har sparats",
- tabs: {
- project: "Projekt",
- account: "Konto",
- team: "Team",
- },
- project: {
- name: {
- title: "Projektnamn",
- description: "Namnet på ditt projekt",
- placeholder: "Ange projektnamn",
- },
- id: {
- title: "Projekt-ID",
- description: "Din unika projektidentifierare",
- placeholder: "Projekt-ID",
- },
- delete: {
- title: "Radera projekt",
- description: "Radera permanent detta projekt och all dess data",
- button: "Radera projekt",
- },
- },
- team: {
- name: {
- title: "Teamnamn",
- description: "Namnet på ditt team",
- placeholder: "Ange teamnamn",
- },
- billing: {
- title: "Fakturaplan",
- description: "Hantera ditt teams fakturaplan",
- free: "Gratis",
- pro: "Pro",
- },
- apiKey: {
- title: "Team API-nyckel",
- description: "API-nyckel för teamåtkomst",
- placeholder: "Team API-nyckel",
- },
- members: {
- title: "Medlemmar",
- pendingInvitations: "Väntande inbjudningar",
- filterPlaceholder: "Filtrera medlemmar...",
- allRoles: "Alla roller",
- date: "Datum",
- selectAll: "{count} valda",
- noPendingInvitations: "Inga väntande inbjudningar",
- inviteMembers: "Bjud in teammedlemmar att samarbeta",
- roles: {
- owner: "Ägare",
- admin: "Admin",
- member: "Medlem",
- },
- dateSort: {
- newest: "Nyast",
- oldest: "Äldst",
- },
- },
- },
- },
- tuning: {
- general: "Allmänt",
- translationMemory: {
- title: "Översättningsminne",
- description:
- "Använd översättningsminne för att förbättra konsekvens och effektivitet",
- },
- qualityChecks: {
- title: "Kvalitetskontroller",
- description:
- "Aktivera automatiserade kvalitetskontroller för översättningar",
- },
- contextDetection: {
- title: "Kontextdetektering",
- description: "Upptäck och bevara kontext automatiskt i översättningar",
- },
- styleGuide: "Stilguide",
- lengthControl: {
- title: "Längdkontroll",
- description: "Kontrollera längden på översatt text",
- options: {
- flexible: "Flexibel",
- strict: "Strikt",
- exact: "Exakt",
- loose: "Lös",
- },
- },
- inclusiveLanguage: {
- title: "Inkluderande språk",
- description: "Säkerställ att översättningar använder inkluderande språk",
- },
- formality: {
- title: "Formalitet",
- description: "Kontrollera formalitetsnivån i översättningar",
- },
- brandName: {
- title: "Varumärkesnamn",
- description: "Ställ in ditt varumärkesnamn för konsekvent användning",
- placeholder: "Ange ditt varumärkesnamn",
- },
- brandVoice: {
- title: "Varumärkesröst",
- description: "Definiera din varumärkesröst och ton",
- placeholder: "Beskriv din varumärkesröst...",
- },
- localization: "Lokalisering",
- idioms: {
- title: "Idiom",
- description: "Hantera idiomatiska uttryck på lämpligt sätt",
- },
- terminology: {
- title: "Terminologi",
- description: "Hantera specialiserad terminologi och ordlistor",
- },
- culturalAdaptation: {
- title: "Kulturell anpassning",
- description: "Anpassa innehåll för kulturell lämplighet",
- },
- },
- pricing: {
- title: "Enkel prissättning",
- free: {
- title: "Gratis (100 nycklar)",
- price: "Gratis",
- keys_limit: "Upp till 100 nycklar",
- features: {
- unlimited_projects: "Obegränsade projekt",
- fine_tuning: "Finjusteringsalternativ",
- overrides: "Översättningsåsidosättningar",
- analytics: "Analys",
- context_memory: "Kontextminne",
- community_support: "Community-support",
- },
- },
- pro: {
- title: "Pro",
- includes_free: "Allt i Gratis, plus:",
- features: {
- github_action: "GitHub Action-integration",
- latest_features: "Tidig tillgång till nya funktioner",
- priority_support: "Prioriterad support",
- },
- },
- cta: "Börja automatisera",
- },
-} as const;
diff --git a/apps/web/src/locales/zh.ts b/apps/web/src/locales/zh.ts
deleted file mode 100644
index 5fabd2b..0000000
--- a/apps/web/src/locales/zh.ts
+++ /dev/null
@@ -1,300 +0,0 @@
-export default {
- header: {
- pricing: "定价",
- docs: "文档",
- signIn: "登录",
- goToApp: "进入应用",
- },
- hero: {
- title: "为您的应用程序提供自动化本地化",
- description:
- "通过人工智能驱动的命令行界面和流程简化您的本地化过程,为开发人员自动化翻译。",
- },
- getStarted: {
- heading: "开始使用",
- title: "为您的应用程序提供自动化本地化",
- description:
- "通过人工智能驱动的命令行界面和流程简化您的本地化过程,为开发人员自动化翻译。",
- button: {
- startAutomating: "开始自动化",
- readDocumentation: "阅读文档",
- },
- },
- companies: {
- title: "使用者",
- addYourCompany: "+ 添加您的公司",
- },
- activity: {
- title: "活动",
- },
- features: {
- title: "功能特点",
- fullyOpenSource: "完全开源",
- fullyOpenSourceDescription:
- "我们的代码在GitHub上公开可用,确保透明度并支持社区贡献。",
- noVendorLockIn: "无供应商锁定",
- noVendorLockInDescription:
- "我们不会将您锁定在特定服务中,您可以使用自己的大语言模型。",
- presetsForExpo: "Expo预设",
- presetsForExpoDescription: "我们为Expo提供预设,让您可以快速开始。",
- presetForReactNative: "React Native预设",
- presetForReactNativeDescription:
- "我们为React Native提供预设,让您可以快速开始。",
- presetForReactEmail: "React Email库",
- presetForReactEmailDescription: "我们为React Email创建了一个国际化库。",
- readyForI18nLibraries: "支持i18n库",
- readyForI18nLibrariesDescription:
- "我们支持所有库,包括最流行的库(next-intl、react-i18next、react-intl等)。",
- },
- info: {
- title: "处理应用本地化的各个方面,包括",
- smartTranslation: {
- title: "智能翻译",
- intelligentTranslation: "具有上下文感知的智能翻译",
- brandVoice: "品牌声音和语气一致性",
- terminology: "术语管理",
- linguisticFeatures: "高级语言功能",
- realtimeUpdates: "实时翻译更新",
- },
- implementation: {
- title: "实施",
- quickSetup: "快速设置和集成",
- fileFormat: "文件格式处理",
- contentStructure: "内容结构组织",
- assetOrganization: "资源组织",
- },
- developer: {
- title: "开发者体验",
- cli: "命令行界面",
- cicd: "CI/CD集成",
- versionControl: "版本控制",
- workflow: "开发者工作流程",
- documentation: "全面的文档",
- },
- },
- login: {
- title: "登录",
- github: "使用GitHub登录",
- google: "使用Google登录",
- footer: "自动化您的本地化。",
- description: "登录以开始在几秒钟内自动化您的本地化。",
- terms: {
- text: "登录即表示您同意我们的",
- termsOfService: "服务条款",
- and: "和",
- privacyPolicy: "隐私政策",
- },
- },
- translations: {
- total_keys: "共{total}个键",
- },
- userMenu: {
- account: "账户设置",
- signOut: "退出登录",
- createTeam: "创建团队",
- homepage: "主页",
- team: "团队设置",
- },
- teamSelector: {
- addProject: "添加项目",
- createProjectTitle: "创建新项目",
- projectNamePlaceholder: "项目名称",
- createProjectButton: "创建项目",
- pro: "专业版",
- project: "项目",
- teams: "团队",
- createTeam: "创建团队",
- createTeamTitle: "创建新团队",
- teamNamePlaceholder: "团队名称",
- createTeamButton: "创建团队",
- },
- coming_soon: {
- title: "Languine正在早期访问阶段",
- description: "我们目前处于早期访问阶段。请联系",
- cta: "在X上获取早期访问权限。",
- },
- account: {
- fullName: {
- title: "全名",
- description: "您的全名将在平台上显示。",
- placeholder: "输入您的全名",
- },
- email: {
- title: "电子邮件地址",
- description: "与您账户关联的电子邮件地址。",
- placeholder: "输入您的电子邮件地址",
- },
- apiKey: {
- title: "API密钥",
- description: "用于访问Languine API的个人API密钥。",
- },
- deleteAccount: {
- title: "删除账户",
- description: "永久删除您的账户和所有相关数据。此操作无法撤消。",
- button: "删除账户",
- },
- },
- copyInstall: {
- copied: "已复制到剪贴板",
- },
- dangerZone: {
- dialog: {
- title: "您确定吗?",
- description: "此操作无法撤消。请输入DELETE以确认。",
- placeholder: "输入DELETE以确认",
- confirm: "确认删除",
- },
- },
- pipeline: {
- title: "工作流程(CI/CD流水线)",
- pro: "[专业版]",
- description:
- "我们的翻译引擎无缝集成到您现有的CI/CD流水线中,在每次推送时自动翻译您的代码库。当代码更改被推送时,我们会分析修改的内容,维护您的翻译记忆,并生成准确的翻译,同时保持您的品牌声音和术语。翻译然后以拉取请求的形式提交,在合并到主分支并部署之前允许审查。这种自动化工作流程确保您的本地化内容与开发保持同步。",
- },
- settings: {
- saved: "设置已保存",
- savedDescription: "您的更改已成功保存",
- tabs: {
- project: "项目",
- account: "账户",
- team: "团队",
- },
- project: {
- name: {
- title: "项目名称",
- description: "您的项目名称",
- placeholder: "输入项目名称",
- },
- id: {
- title: "项目ID",
- description: "您的唯一项目标识符",
- placeholder: "项目ID",
- },
- delete: {
- title: "删除项目",
- description: "永久删除此项目及其所有数据",
- button: "删除项目",
- },
- },
- team: {
- name: {
- title: "团队名称",
- description: "您的团队名称",
- placeholder: "输入团队名称",
- },
- billing: {
- title: "计费方案",
- description: "管理您的团队计费方案",
- free: "免费版",
- pro: "专业版",
- },
- apiKey: {
- title: "团队API密钥",
- description: "用于团队访问的API密钥",
- placeholder: "团队API密钥",
- },
- members: {
- title: "成员",
- pendingInvitations: "待处理邀请",
- filterPlaceholder: "筛选成员...",
- allRoles: "所有角色",
- date: "日期",
- selectAll: "已选择{count}个",
- noPendingInvitations: "没有待处理的邀请",
- inviteMembers: "邀请团队成员协作",
- roles: {
- owner: "所有者",
- admin: "管理员",
- member: "成员",
- },
- dateSort: {
- newest: "最新",
- oldest: "最早",
- },
- },
- },
- },
- tuning: {
- general: "常规",
- translationMemory: {
- title: "翻译记忆",
- description: "使用翻译记忆来提高一致性和效率",
- },
- qualityChecks: {
- title: "质量检查",
- description: "启用自动化翻译质量检查",
- },
- contextDetection: {
- title: "上下文检测",
- description: "自动检测并保留翻译中的上下文",
- },
- styleGuide: "风格指南",
- lengthControl: {
- title: "长度控制",
- description: "控制翻译文本的长度",
- options: {
- flexible: "灵活",
- strict: "严格",
- exact: "精确",
- loose: "宽松",
- },
- },
- inclusiveLanguage: {
- title: "包容性语言",
- description: "确保翻译使用包容性语言",
- },
- formality: {
- title: "正式程度",
- description: "控制翻译的正式程度",
- },
- brandName: {
- title: "品牌名称",
- description: "设置您的品牌名称以保持一致使用",
- placeholder: "输入您的品牌名称",
- },
- brandVoice: {
- title: "品牌声音",
- description: "定义您的品牌声音和语气",
- placeholder: "描述您的品牌声音...",
- },
- localization: "本地化",
- idioms: {
- title: "习语",
- description: "适当处理习语表达",
- },
- terminology: {
- title: "术语",
- description: "管理专业术语和词汇表",
- },
- culturalAdaptation: {
- title: "文化适应",
- description: "适应文化适当性的内容",
- },
- },
- pricing: {
- title: "简单定价",
- free: {
- title: "免费版(100个键)",
- price: "免费",
- keys_limit: "最多100个键",
- features: {
- unlimited_projects: "无限项目",
- fine_tuning: "微调选项",
- overrides: "翻译覆盖",
- analytics: "分析功能",
- context_memory: "上下文记忆",
- community_support: "社区支持",
- },
- },
- pro: {
- title: "专业版",
- includes_free: "包含免费版的所有功能,以及:",
- features: {
- github_action: "GitHub Action集成",
- latest_features: "抢先体验最新功能",
- priority_support: "优先支持",
- },
- },
- cta: "开始自动化",
- },
-} as const;
diff --git a/bun.lockb b/bun.lockb
index 95f410a..7a0c38f 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/examples/next-international/locales/en.ts b/examples/next-international/locales/en.ts
index 4a9b009..9234e66 100644
--- a/examples/next-international/locales/en.ts
+++ b/examples/next-international/locales/en.ts
@@ -12,4 +12,7 @@ export default {
"cows#one": "A cow",
"cows#other": "{count} cows",
"languine.hello": "Hello Languine",
+ test: {
+ hello: "Hello",
+ },
} as const;
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 37c393c..9f61d29 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -13,7 +13,8 @@
"typecheck": "tsc --noEmit",
"build": "tsup --clean",
"dev": "tsup --watch --clean",
- "start": "node dist/index.js"
+ "start": "node dist/index.js",
+ "test": "bun test"
},
"files": [
"dist",
@@ -24,13 +25,29 @@
"@trpc/client": "11.0.0-rc.700",
"@trpc/server": "11.0.0-rc.700",
"chalk": "^5.4.1",
+ "csv-parse": "^5.5.5",
+ "csv-stringify": "^6.4.6",
"dedent": "^1.5.3",
"dotenv": "^16.4.7",
+ "fast-glob": "^3.3.3",
+ "fast-xml-parser": "^4.3.6",
+ "gettext-parser": "^7.0.1",
+ "jiti": "^2.4.2",
+ "marked": "^12.0.1",
+ "node-html-parser": "^6.1.12",
"open": "^10.1.0",
+ "plist": "^3.1.0",
+ "properties": "^1.2.1",
"simple-git": "^3.27.0",
- "superjson": "^2.2.2"
+ "sucrase": "^3.35.0",
+ "superjson": "^2.2.2",
+ "yaml": "^2.4.1",
+ "zod": "^3.22.4"
},
"devDependencies": {
+ "@types/node": "^20.11.30",
+ "@types/plist": "^3.0.5",
+ "@types/gettext-parser": "^4.0.4",
"tsup": "^8.3.5",
"typescript": "^5.7.3"
}
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
index 9305ace..5d3fda6 100644
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -1,13 +1,207 @@
-import { select } from "@clack/prompts";
+import { existsSync } from "node:fs";
+import { intro, isCancel, outro, select, text } from "@clack/prompts";
+import chalk from "chalk";
+import type { Config } from "../types.js";
+import { loadSession } from "../utils/session.js";
+import { commands as authCommands } from "./auth/index.js";
+
+type Format =
+ | "json"
+ | "yaml"
+ | "properties"
+ | "android"
+ | "ios-strings"
+ | "md"
+ | "html"
+ | "txt"
+ | "ts";
+
+const SUPPORTED_FORMATS = [
+ { value: "json" as const, label: "JSON (.json)" },
+ { value: "yaml" as const, label: "YAML (.yml, .yaml)" },
+ { value: "properties" as const, label: "Java Properties (.properties)" },
+ { value: "android" as const, label: "Android XML (.xml)" },
+ { value: "ios-strings" as const, label: "iOS Strings (.strings)" },
+ { value: "md" as const, label: "Markdown (.md)" },
+ { value: "html" as const, label: "HTML (.html)" },
+ { value: "txt" as const, label: "Text (.txt)" },
+ { value: "ts" as const, label: "TypeScript (.ts)" },
+];
+
+const FORMAT_EXAMPLES: Record = {
+ json: "src/locales/[locale].json",
+ yaml: "src/locales/[locale].yaml",
+ properties: "src/locales/messages_[locale].properties",
+ android: "res/values-[locale]/strings.xml",
+ "ios-strings": "[locale].lproj/Localizable.strings",
+ md: "src/docs/[locale]/*.md",
+ html: "src/content/[locale]/**/*.html",
+ txt: "src/content/[locale]/**/*.txt",
+ ts: "src/locales/[locale].ts",
+};
export async function commands() {
- const command = await select({
- message: "What would you like to do?",
+ intro("Initialize a new Languine configuration");
+
+ // Check authentication first
+ const session = loadSession();
+ if (!session) {
+ console.log(
+ chalk.yellow("You need to be logged in to initialize a project."),
+ );
+ console.log();
+ await authCommands("login");
+
+ // Verify login was successful
+ const newSession = loadSession();
+ if (!newSession) {
+ outro("Please try initializing again after logging in.");
+ process.exit(1);
+ }
+ }
+
+ // Get source language
+ const sourceLanguage = (await select({
+ message: "What is your source language?",
options: [
- { value: "init", label: "Initialize a new Languine configuration" },
- { value: "auth", label: "Manage authentication" },
+ { value: "en", label: "English", hint: "recommended" },
+ { value: "es", label: "Spanish" },
+ { value: "fr", label: "French" },
+ { value: "de", label: "German" },
],
+ })) as string;
+
+ if (isCancel(sourceLanguage)) {
+ outro("Configuration cancelled");
+ process.exit(0);
+ }
+
+ const targetLanguages = (await text({
+ message: "What languages do you want to translate to?",
+ placeholder: "es, fr, de, zh, ja, pt",
+ validate: (value) => {
+ if (!value) return "Please enter at least one language";
+ return;
+ },
+ })) as string;
+
+ if (isCancel(targetLanguages)) {
+ outro("Configuration cancelled");
+ process.exit(0);
+ }
+
+ // Get file configurations
+ const fileConfigs: Config["files"] = {};
+
+ // Select format
+ const format = await select({
+ message: "Select file format",
+ options: SUPPORTED_FORMATS,
});
- return command;
+ if (isCancel(format)) {
+ outro("Configuration cancelled");
+ process.exit(0);
+ }
+
+ const formatKey = format as keyof typeof FORMAT_EXAMPLES;
+
+ // Get file pattern
+ const pattern = await text({
+ message: "Enter the file pattern for translations",
+ placeholder: FORMAT_EXAMPLES[formatKey],
+ defaultValue: FORMAT_EXAMPLES[formatKey],
+ validate(value) {
+ if (!value) return;
+
+ if (!value.includes("[locale]")) {
+ return "Path must include [locale] placeholder (e.g. src/locales/[locale].json)";
+ }
+ },
+ });
+
+ if (isCancel(pattern)) {
+ outro("Configuration cancelled");
+ process.exit(0);
+ }
+
+ // Add to file configs
+ fileConfigs[format] = {
+ include: [pattern],
+ };
+
+ // Check if project has TypeScript support
+ const hasTypeScript =
+ existsSync("tsconfig.json") || existsSync("package.json");
+
+ let configFormat = "json";
+ if (hasTypeScript) {
+ const format = await select({
+ message: "Select configuration format",
+ options: [
+ { value: "typescript", label: "TypeScript (languine.config.ts)" },
+ { value: "json", label: "JSON (languine.config.json)" },
+ ],
+ });
+
+ if (isCancel(format)) {
+ outro("Configuration cancelled");
+ process.exit(0);
+ }
+ configFormat = format;
+ }
+
+ // Create config file
+ const config: Config = {
+ projectId: "",
+ locale: {
+ source: sourceLanguage,
+ targets: targetLanguages.split(",").map((lang) => lang.trim()),
+ },
+ files: fileConfigs,
+ };
+
+ try {
+ const fs = await import("node:fs/promises");
+
+ if (configFormat === "typescript") {
+ const tsConfig = `import { defineConfig } from "languine";
+
+export default defineConfig({
+ locale: {
+ source: "${sourceLanguage}",
+ targets: ["${targetLanguages
+ .split(",")
+ .map((lang) => lang.trim())
+ .join('", "')}"],
+ },
+ files: {
+ ${format}: {
+ include: [${JSON.stringify(pattern)}],
+ },
+ },
+});
+`;
+ await fs.writeFile("languine.config.ts", tsConfig, "utf-8");
+ } else {
+ await fs.writeFile(
+ "languine.config.json",
+ JSON.stringify(config, null, 2),
+ "utf-8",
+ );
+ }
+
+ outro(chalk.green("Configuration file created successfully!"));
+ console.log();
+ console.log("Next steps:");
+ console.log(
+ `1. Review your languine.config.${configFormat === "typescript" ? "ts" : "json"} file`,
+ );
+ console.log("2. Run 'languine translate' to start translating your files");
+ console.log();
+ } catch (error) {
+ outro(chalk.red("Failed to create configuration file"));
+ console.error(error);
+ process.exit(1);
+ }
}
diff --git a/packages/cli/src/commands/run.ts b/packages/cli/src/commands/run.ts
index 73b3979..d21f9ba 100644
--- a/packages/cli/src/commands/run.ts
+++ b/packages/cli/src/commands/run.ts
@@ -1,9 +1,10 @@
-import { isCancel } from "@clack/prompts";
+import { isCancel, select } from "@clack/prompts";
import { commands as authCommands } from "./auth/index.js";
import { commands as initCommands } from "./init.js";
+import { translateCommand } from "./translate.js";
export async function runCommands() {
- const [mainCommand, subCommand] = process.argv.slice(2);
+ const [mainCommand, subCommand, ...args] = process.argv.slice(2);
if (mainCommand) {
switch (mainCommand) {
@@ -13,13 +14,24 @@ export async function runCommands() {
case "init":
await initCommands();
break;
+ case "translate": {
+ await translateCommand();
+ break;
+ }
default:
process.exit(1);
}
return;
}
- const command = await initCommands();
+ const command = await select({
+ message: "What would you like to do?",
+ options: [
+ { value: "init", label: "Initialize a new Languine configuration" },
+ { value: "auth", label: "Manage authentication" },
+ { value: "translate", label: "Translate files" },
+ ],
+ });
if (isCancel(command)) {
process.exit(0);
@@ -32,5 +44,9 @@ export async function runCommands() {
case "init":
await initCommands();
break;
+ case "translate": {
+ await translateCommand();
+ break;
+ }
}
}
diff --git a/packages/cli/src/commands/translate.ts b/packages/cli/src/commands/translate.ts
new file mode 100644
index 0000000..4958525
--- /dev/null
+++ b/packages/cli/src/commands/translate.ts
@@ -0,0 +1,126 @@
+import { readFile, writeFile } from "node:fs/promises";
+import { type ParserType, createParser } from "@/parsers/index.js";
+import type { Config } from "@/types.js";
+import { client } from "@/utils/api.js";
+import { outro, spinner } from "@clack/prompts";
+import chalk from "chalk";
+import glob from "fast-glob";
+import { loadConfig } from "../utils/config.js";
+
+// Map our parser types to the API's source format types
+const sourceFormatMap = {
+ json: "json",
+ javascript: "json",
+ typescript: "json",
+} as const;
+
+export async function translateCommand() {
+ const s = spinner();
+
+ try {
+ // Load config file
+ const config = await loadConfig();
+
+ if (!config) {
+ throw new Error(
+ "No config file found. Run `languine init` to create one.",
+ );
+ }
+
+ const { source: sourceLocale, targets: targetLocales } = config.locale;
+
+ // Process each file configuration
+ for (const [type, fileConfig] of Object.entries(config.files)) {
+ const parserType = type as ParserType;
+ const { include } = fileConfig as Config["files"][string];
+
+ // Process each file pattern
+ for (const pattern of include) {
+ const globPattern =
+ typeof pattern === "string" ? pattern : pattern.glob;
+ const sourcePattern = globPattern.replace("[locale]", sourceLocale);
+
+ // Find all matching source files
+ const sourceFiles = await glob(sourcePattern, { absolute: true });
+
+ for (const sourceFilePath of sourceFiles) {
+ const parser = createParser({
+ type: parserType,
+ });
+
+ // Read and parse the source file
+ const sourceFile = await readFile(sourceFilePath, "utf-8");
+ const sourceContent = await parser.parse(sourceFile);
+
+ // Translate to each target locale
+ for (const targetLocale of targetLocales) {
+ try {
+ // Convert the content to the expected format
+ const translationInput = Object.entries(sourceContent).map(
+ ([key, sourceText]) => ({
+ key,
+ sourceText: String(sourceText),
+ }),
+ );
+
+ console.log(translationInput);
+
+ return;
+
+ // Call the translation API with the mapped source format
+ const translations =
+ await client.translate.pushTranslations.mutate({
+ sourceFormat: sourceFormatMap[parserType],
+ sourceLanguage: sourceLocale,
+ targetLanguage: targetLocale,
+ content: translationInput,
+ projectId: "default", // TODO: Add project ID support
+ });
+
+ // Convert the translations back to the expected format
+ const translatedContent = Object.fromEntries(
+ translationInput.map((item, index) => [
+ item.key,
+ translations[index],
+ ]),
+ );
+
+ // Serialize the translated content
+ const targetPath = sourceFilePath.replace(
+ sourceLocale,
+ targetLocale,
+ );
+ const serialized = await parser.serialize(
+ translatedContent,
+ targetLocale,
+ );
+ await writeFile(targetPath, serialized, "utf-8");
+
+ console.log(
+ chalk.green(
+ `✓ Successfully translated to ${chalk.bold(targetLocale)}`,
+ ),
+ );
+ } catch (error) {
+ const translationError = error as Error;
+ console.error(
+ chalk.red(
+ `Failed to translate to ${chalk.bold(
+ targetLocale,
+ )}: ${translationError.message}`,
+ ),
+ );
+ }
+ }
+ }
+ }
+ }
+
+ s.stop("Translation completed");
+ outro("All translations completed");
+ } catch (error) {
+ const translationError = error as Error;
+ s.stop(chalk.red(`Translation failed: ${translationError.message}`));
+ process.exit(1);
+ }
+}
diff --git a/packages/cli/src/parsers/core/format.ts b/packages/cli/src/parsers/core/format.ts
new file mode 100644
index 0000000..4def6c7
--- /dev/null
+++ b/packages/cli/src/parsers/core/format.ts
@@ -0,0 +1,26 @@
+import type { Parser } from "./types.js";
+
+export interface FormatParserOptions {
+ filePath?: string;
+ defaultLocale?: string;
+ formatOptions?: Record;
+}
+
+export type FormatParserFactory = (
+ options?: FormatParserOptions,
+) => T;
+
+export function createFormatParser(
+ parser: T,
+ options: FormatParserOptions = {},
+): T {
+ const { defaultLocale } = options;
+
+ return {
+ ...parser,
+ defaultLocale,
+ setDefaultLocale(locale: string) {
+ this.defaultLocale = locale;
+ },
+ };
+}
diff --git a/packages/cli/src/parsers/core/types.ts b/packages/cli/src/parsers/core/types.ts
new file mode 100644
index 0000000..3a5e771
--- /dev/null
+++ b/packages/cli/src/parsers/core/types.ts
@@ -0,0 +1,18 @@
+import { z } from "zod";
+
+export interface ParserOptions {
+ type: string;
+ filePath: string;
+ defaultLocale: string;
+}
+
+export const parserOptionsSchema = z.object({
+ type: z.string(),
+ filePath: z.string(),
+ defaultLocale: z.string(),
+});
+
+export interface Parser {
+ parse(input: string): Promise>;
+ serialize(data: Record): Promise;
+}
diff --git a/packages/cli/src/parsers/core/utils.ts b/packages/cli/src/parsers/core/utils.ts
new file mode 100644
index 0000000..e71db12
--- /dev/null
+++ b/packages/cli/src/parsers/core/utils.ts
@@ -0,0 +1,54 @@
+import type { Parser } from "./types.js";
+
+export class ParserError extends Error {
+ code: string;
+ details?: unknown;
+
+ constructor(
+ message: string,
+ options: { code: string; details?: unknown } = { code: "UNKNOWN" },
+ ) {
+ super(message);
+ this.name = "ParserError";
+ this.code = options.code;
+ this.details = options.details;
+ }
+}
+
+export function createParser(parser: T): T {
+ return parser;
+}
+
+export function composeParsers(parsers: Parser[]): Parser {
+ return {
+ async parse(input: string) {
+ let result = input;
+ let data = {};
+
+ for (const parser of parsers) {
+ const parsed = await parser.parse(result);
+ data = { ...data, ...parsed };
+ result = JSON.stringify(parsed);
+ }
+
+ return data;
+ },
+
+ async serialize(data: Record) {
+ let result = data;
+ let output = JSON.stringify(data);
+
+ for (const parser of parsers.slice().reverse()) {
+ output = await parser.serialize(result);
+ try {
+ result = JSON.parse(output);
+ } catch {
+ // If the output is not JSON, just pass it through
+ result = output as unknown as Record;
+ }
+ }
+
+ return output;
+ },
+ };
+}
diff --git a/packages/cli/src/parsers/formats/__tests__/javascript.test.ts b/packages/cli/src/parsers/formats/__tests__/javascript.test.ts
new file mode 100644
index 0000000..157d4df
--- /dev/null
+++ b/packages/cli/src/parsers/formats/__tests__/javascript.test.ts
@@ -0,0 +1,183 @@
+import { describe, expect, test } from "bun:test";
+import { createJavaScriptParser } from "../javascript.ts";
+
+describe("JavaScript/TypeScript Parser", () => {
+ const parser = createJavaScriptParser();
+
+ describe("parse", () => {
+ test("parses simple object", async () => {
+ const input = `{ "hello": "world" }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({ hello: "world" });
+ });
+
+ test("parses nested object", async () => {
+ const input = `{
+ nested: {
+ key: "value",
+ deeper: {
+ another: "test"
+ }
+ }
+ }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({
+ "nested.key": "value",
+ "nested.deeper.another": "test",
+ });
+ });
+
+ test("handles export default", async () => {
+ const input = `export default {
+ key: "value"
+ }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({ key: "value" });
+ });
+
+ test("handles as const", async () => {
+ const input = `{
+ key: "value"
+ } as const`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({ key: "value" });
+ });
+
+ test("handles export default with as const", async () => {
+ const input = `export default {
+ key: "value"
+ } as const`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({ key: "value" });
+ });
+
+ test("parses pluralization keys", async () => {
+ const input = `{
+ "cows#one": "A cow",
+ "cows#other": "{count} cows"
+ }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({
+ "cows#one": "A cow",
+ "cows#other": "{count} cows",
+ });
+ });
+
+ test("parses deeply nested scopes", async () => {
+ const input = `{
+ scope: {
+ more: {
+ and: {
+ more: {
+ test: "A scope"
+ }
+ }
+ }
+ }
+ }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({
+ "scope.more.and.more.test": "A scope",
+ });
+ });
+
+ test("parses interpolation parameters", async () => {
+ const input = `{
+ welcome: "Hello {name}!",
+ "about.you": "Hello {name}! You are {age} years old"
+ }`;
+ const result = await parser.parse(input);
+ expect(result).toEqual({
+ welcome: "Hello {name}!",
+ "about.you": "Hello {name}! You are {age} years old",
+ });
+ });
+
+ test("throws on invalid JavaScript syntax", async () => {
+ const input = "{ invalid: syntax: }";
+ await expect(parser.parse(input)).rejects.toThrow(
+ "Invalid JavaScript syntax",
+ );
+ });
+
+ test("throws on non-object input", async () => {
+ const input = `"just a string"`;
+ await expect(parser.parse(input)).rejects.toThrow(
+ "Translation file must export an object",
+ );
+ });
+
+ test("throws on non-string values", async () => {
+ const input = "{ key: 123 }";
+ await expect(parser.parse(input)).rejects.toThrow(
+ "Invalid translation value",
+ );
+ });
+ });
+
+ describe("serialize", () => {
+ test("serializes flat object", async () => {
+ const input = { key: "value" };
+ const result = await parser.serialize(input);
+ expect(result).toBe(`export default {\n "key": "value"\n} as const;\n`);
+ });
+
+ test("serializes nested keys", async () => {
+ const input = {
+ "nested.key": "value",
+ "nested.deeper.another": "test",
+ };
+ const result = await parser.serialize(input);
+ expect(result).toBe(
+ `export default {\n "nested": {\n "key": "value",\n "deeper": {\n "another": "test"\n }\n }\n} as const;\n`,
+ );
+ });
+
+ test("preserves quotes in text content", async () => {
+ const input = { key: 'value with "quotes"' };
+ const result = await parser.serialize(input);
+ expect(result).toBe(
+ `export default {\n "key": "value with "quotes""\n} as const;\n`,
+ );
+ });
+
+ test("handles empty object", async () => {
+ const input = {};
+ const result = await parser.serialize(input);
+ expect(result).toBe("export default {} as const;\n");
+ });
+
+ test("serializes pluralization keys", async () => {
+ const input = {
+ "cows#one": "A cow",
+ "cows#other": "{count} cows",
+ };
+ const result = await parser.serialize(input);
+ expect(result).toBe(
+ `export default {\n "cows#one": "A cow",\n "cows#other": "{count} cows"\n} as const;\n`,
+ );
+ });
+
+ test("round trip test", async () => {
+ const original = {
+ simple: "value",
+ "nested.key": "nested value",
+ "very.deep.structure.key": "deep value",
+ };
+ const serialized = await parser.serialize(original);
+ const parsed = await parser.parse(serialized);
+ expect(parsed).toEqual(original);
+ });
+
+ test("round trip with pluralization and parameters", async () => {
+ const original = {
+ "scope.more.stars#one": "1 star on GitHub",
+ "scope.more.stars#other": "{count} stars on GitHub",
+ "scope.more.param": "A scope with {param}",
+ };
+ const serialized = await parser.serialize(original);
+ const parsed = await parser.parse(serialized);
+ expect(parsed).toEqual(original);
+ });
+ });
+});
diff --git a/packages/cli/src/parsers/formats/javascript.ts b/packages/cli/src/parsers/formats/javascript.ts
new file mode 100644
index 0000000..c781846
--- /dev/null
+++ b/packages/cli/src/parsers/formats/javascript.ts
@@ -0,0 +1,124 @@
+import { createFormatParser } from "../core/format.ts";
+import type { Parser } from "../core/types.ts";
+
+export function createJavaScriptParser(): Parser {
+ return createFormatParser({
+ async parse(input: string): Promise> {
+ try {
+ const cleanInput = preprocessInput(input);
+ const parsed = evaluateJavaScript(cleanInput);
+ validateParsedObject(parsed);
+ return flattenTranslations(parsed as Record);
+ } catch (error) {
+ throw new TranslationParseError(error as Error);
+ }
+ },
+
+ async serialize(data: Record): Promise {
+ const nested = unflattenTranslations(data);
+ const formatted = formatTranslationObject(nested);
+ return wrapInExport(formatted);
+ },
+ });
+}
+
+// Error class for better error handling
+class TranslationParseError extends Error {
+ constructor(originalError: Error) {
+ super(
+ `Failed to parse JavaScript/TypeScript translations: ${originalError.message}`,
+ );
+ this.name = "TranslationParseError";
+ }
+}
+
+function preprocessInput(input: string): string {
+ let processed = input.trim();
+
+ // Check if input starts with export default
+ if (processed.match(/^export\s+default\s+/)) {
+ processed = processed.replace(/export\s+default\s+/, "");
+ }
+
+ // Check if input ends with as const
+ if (processed.match(/\s*as\s+const\s*;?\s*$/)) {
+ processed = processed.replace(/\s*as\s+const\s*;?\s*$/, "");
+ }
+
+ return processed;
+}
+
+function evaluateJavaScript(input: string): unknown {
+ try {
+ return new Function(`return ${input};`)();
+ } catch (error) {
+ throw new Error(`Invalid JavaScript syntax: ${(error as Error).message}`);
+ }
+}
+
+function validateParsedObject(
+ parsed: unknown,
+): asserts parsed is Record {
+ if (typeof parsed !== "object" || parsed === null) {
+ throw new Error("Translation file must export an object");
+ }
+}
+
+function flattenTranslations(
+ obj: Record,
+ prefix = "",
+): Record {
+ const result: Record = {};
+
+ for (const [key, value] of Object.entries(obj)) {
+ const newKey = prefix ? `${prefix}.${key}` : key;
+
+ if (typeof value === "object" && value !== null) {
+ Object.assign(
+ result,
+ flattenTranslations(value as Record, newKey),
+ );
+ } else if (typeof value === "string") {
+ result[newKey] = value;
+ } else {
+ throw new Error(
+ `Invalid translation value at "${newKey}": expected string, got ${typeof value}`,
+ );
+ }
+ }
+
+ return result;
+}
+
+function unflattenTranslations(
+ data: Record,
+): Record {
+ const result: Record = {};
+
+ for (const [key, value] of Object.entries(data)) {
+ const keys = key.split(".");
+ let current = result;
+
+ for (let i = 0; i < keys.length; i++) {
+ const k = keys[i];
+ if (i === keys.length - 1) {
+ current[k] = value;
+ } else {
+ current[k] = current[k] || {};
+ current = current[k] as Record;
+ }
+ }
+ }
+
+ return result;
+}
+
+function formatTranslationObject(obj: Record): string {
+ return JSON.stringify(obj, null, 2)
+ .replace(/\\"/g, '"') // Unescape quotes in text content
+ .replace(/"([^"]+)":/g, '"$1":'); // Re-escape quotes in object keys
+}
+
+function wrapInExport(content: string): string {
+ return `export default ${content} as const;\n`;
+}
diff --git a/packages/cli/src/parsers/index.ts b/packages/cli/src/parsers/index.ts
new file mode 100644
index 0000000..26a08ab
--- /dev/null
+++ b/packages/cli/src/parsers/index.ts
@@ -0,0 +1,21 @@
+import { z } from "zod";
+import type { Parser } from "./core/types.js";
+import { createJavaScriptParser } from "./formats/javascript.js";
+
+export const parserTypeSchema = z.enum(["js", "ts"]);
+
+export type ParserType = z.infer;
+
+export interface CreateParserOptions {
+ type: ParserType;
+}
+
+export function createParser(options: CreateParserOptions): Parser {
+ switch (options.type) {
+ case "js":
+ case "ts":
+ return createJavaScriptParser();
+ default:
+ throw new Error(`Unsupported parser type: ${options.type}`);
+ }
+}
diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts
index f0626df..80ac4a7 100644
--- a/packages/cli/src/types.ts
+++ b/packages/cli/src/types.ts
@@ -2,6 +2,8 @@
* Configuration interface for Languine
*/
export interface Config {
+ /** Project ID from Languine */
+ projectId: string;
/** Locale configuration */
locale: {
/** Source language code (e.g. 'en') */
@@ -13,36 +15,31 @@ export interface Config {
files: {
/** Configuration for each file format */
[format: string]: {
- /** Glob patterns or path mappings to include */
- include: Include[];
-
- /**
- * Filter by file path, keep the file if `true` is returned
- */
- filter?: (file: string) => boolean;
+ /** Glob patterns to include */
+ include: (string | { glob: string })[];
};
};
- /** Glob patterns to extract translation keys from source files */
- extract?: string[];
- /** Hook functions */
- hooks?: {
- /** Hook called after translation is complete */
- afterTranslate?: (args: {
- /** Translated content */
- content: string;
- /** Path to the translated file */
- filePath: string;
- }) => Promise;
- };
}
-export type Include =
- | string
- | {
- from: string;
- to: string | ((locale: string) => string);
- }
- | {
- glob: string;
- to: (file: string, locale: string) => string;
- };
+export class ParserError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "ParserError";
+ }
+}
+
+export interface ParserOptions {
+ indent?: number;
+ separator?: string;
+ createDirectories?: boolean;
+ encoding?: BufferEncoding;
+}
+
+export interface Parser {
+ parse(input: string, locale: string): Promise>;
+ serialize(
+ data: Record,
+ locale: string,
+ options: ParserOptions | null,
+ ): Promise;
+}
diff --git a/packages/cli/src/utils/config.ts b/packages/cli/src/utils/config.ts
new file mode 100644
index 0000000..0bff4e1
--- /dev/null
+++ b/packages/cli/src/utils/config.ts
@@ -0,0 +1,71 @@
+import { readdir } from "node:fs/promises";
+import { join } from "node:path";
+import { pathToFileURL } from "node:url";
+import type { Config } from "@/types.js";
+import { outro } from "@clack/prompts";
+import chalk from "chalk";
+import type { Jiti } from "jiti";
+
+const CONFIG_NAME = "languine.config";
+
+export async function configFile(configType?: string) {
+ const files = await readdir(process.cwd());
+ const configFile = files.find(
+ (file: string) =>
+ file.startsWith(`${CONFIG_NAME}.`) &&
+ (file.endsWith(".ts") || file.endsWith(".mjs")),
+ );
+
+ // If configType is specified, use that
+ // Otherwise try to detect from existing file, falling back to ts
+ const format = configType || (configFile?.endsWith(".mjs") ? "mjs" : "ts");
+ const filePath = join(
+ process.cwd(),
+ configFile || `${CONFIG_NAME}.${format}`,
+ );
+
+ return {
+ path: filePath,
+ format,
+ };
+}
+
+/**
+ * Load the configuration file from the current working directory.
+ * Supports both TypeScript (languine.config.ts) and JSON (languine.config.json) formats.
+ */
+export async function loadConfig(): Promise {
+ let jiti: Jiti | undefined;
+
+ const { path: filePath, format } = await configFile();
+
+ if (!filePath) {
+ outro(
+ chalk.red(
+ `Could not find ${CONFIG_NAME}.${format}. Run 'languine init' first.`,
+ ),
+ );
+
+ process.exit(1);
+ }
+
+ try {
+ const configModule = await import(pathToFileURL(filePath).href);
+ return configModule.default;
+ } catch (error) {
+ const { createJiti } = await import("jiti");
+ const { transform } = await import("sucrase");
+
+ jiti ??= createJiti(import.meta.url, {
+ transform(opts) {
+ return transform(opts.source, {
+ transforms: ["typescript", "imports"],
+ });
+ },
+ });
+
+ return await jiti
+ .import(filePath)
+ .then((mod) => (mod as unknown as { default: Config }).default);
+ }
+}