From b66fbf22f3c6b239b3e27cc471fcf0c8c0150d2e Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 6 Apr 2026 15:21:25 +0000 Subject: [PATCH] feat: add i18n for sidebar buttons and links with 8 language support Co-Authored-By: Claude Opus 4.6 (1M context) --- .../components/sidebar/OperatorMenu.svelte | 79 +++++++++++----- .../components/sidebar/SidebarContent.svelte | 81 ++++++++--------- .../lib/components/sidebar/UserMenu.svelte | 32 +++++-- frontend/src/lib/i18n/index.ts | 14 +++ frontend/src/lib/i18n/messages/de.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/en.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/es.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/fr.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/index.ts | 22 +++++ frontend/src/lib/i18n/messages/ja.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/ko.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/pt.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/messages/zh.ts | 90 +++++++++++++++++++ frontend/src/lib/i18n/t.svelte.ts | 33 +++++++ 14 files changed, 909 insertions(+), 72 deletions(-) create mode 100644 frontend/src/lib/i18n/index.ts create mode 100644 frontend/src/lib/i18n/messages/de.ts create mode 100644 frontend/src/lib/i18n/messages/en.ts create mode 100644 frontend/src/lib/i18n/messages/es.ts create mode 100644 frontend/src/lib/i18n/messages/fr.ts create mode 100644 frontend/src/lib/i18n/messages/index.ts create mode 100644 frontend/src/lib/i18n/messages/ja.ts create mode 100644 frontend/src/lib/i18n/messages/ko.ts create mode 100644 frontend/src/lib/i18n/messages/pt.ts create mode 100644 frontend/src/lib/i18n/messages/zh.ts create mode 100644 frontend/src/lib/i18n/t.svelte.ts diff --git a/frontend/src/lib/components/sidebar/OperatorMenu.svelte b/frontend/src/lib/components/sidebar/OperatorMenu.svelte index 2b916550ff..5f55f1ad0f 100644 --- a/frontend/src/lib/components/sidebar/OperatorMenu.svelte +++ b/frontend/src/lib/components/sidebar/OperatorMenu.svelte @@ -38,6 +38,7 @@ import MenuButton, { sidebarClasses } from './MenuButton.svelte' import MenuLink from './MenuLink.svelte' import type { FavoriteKind } from './FavoriteMenu.svelte' + import { t } from '$lib/i18n/t.svelte' let darkMode: boolean = $state(false) let showExtraTriggers = $state(false) let menubarEl: HTMLElement | undefined = $state() @@ -55,14 +56,14 @@ let mainMenuLinks = $derived( [ - { label: 'Home', id: 'home', href: `${base}/`, icon: Home }, - { label: 'Runs', id: 'runs', href: `${base}/runs`, icon: Play }, - { label: 'Schedules', id: 'schedules', href: `${base}/schedules`, icon: Calendar }, + { label: t('sidebar.home'), id: 'home', href: `${base}/`, icon: Home }, + { label: t('sidebar.runs'), id: 'runs', href: `${base}/runs`, icon: Play }, + { label: t('sidebar.schedules'), id: 'schedules', href: `${base}/schedules`, icon: Calendar }, // Add Tutorials to main menu only if not all completed and not skipped ...($tutorialsToDo.length > 0 && !$skippedAll ? [ { - label: 'Tutorials', + label: t('sidebar.tutorials'), id: 'tutorials', href: `${base}/tutorials`, icon: GraduationCap @@ -89,37 +90,37 @@ let secondMenuLinks: SecondMenuLink[] = $derived( [ { - label: 'Resources', + label: t('sidebar.resources'), id: 'resources', href: `${base}/resources` }, { - label: 'Variables', + label: t('sidebar.variables'), id: 'variables', href: `${base}/variables` }, { - label: 'Assets', + label: t('sidebar.assets'), id: 'assets', href: `${base}/assets` }, { - label: 'Groups', + label: t('sidebar.groups'), id: 'groups', href: `${base}/groups` }, { - label: 'Folders', + label: t('sidebar.folders'), id: 'folders', href: `${base}/folders` }, { - label: 'Workers', + label: t('sidebar.workers'), id: 'workers', href: `${base}/workers` }, { - label: 'Audit logs', + label: t('sidebar.audit_logs'), id: 'audit_logs', href: `${base}/audit_logs` } @@ -129,30 +130,60 @@ let allTriggerLinks: TriggerMenuLink[] = $derived( ( [ - { label: 'Custom HTTP routes', id: 'triggers', href: `${base}/routes`, kind: 'http' }, { - label: 'Websocket triggers', + label: t('operator.custom_http_routes'), + id: 'triggers', + href: `${base}/routes`, + kind: 'http' + }, + { + label: t('operator.websocket_triggers'), id: 'triggers', href: `${base}/websocket_triggers`, kind: 'ws' }, { - label: 'Postgres triggers', + label: t('operator.postgres_triggers'), id: 'triggers', href: `${base}/postgres_triggers`, kind: 'postgres' }, - { label: 'Kafka triggers', id: 'triggers', href: `${base}/kafka_triggers`, kind: 'kafka' }, - { label: 'NATS triggers', id: 'triggers', href: `${base}/nats_triggers`, kind: 'nats' }, - { label: 'SQS triggers', id: 'triggers', href: `${base}/sqs_triggers`, kind: 'sqs' }, { - label: 'GCP Pub/Sub triggers', + label: t('operator.kafka_triggers'), + id: 'triggers', + href: `${base}/kafka_triggers`, + kind: 'kafka' + }, + { + label: t('operator.nats_triggers'), + id: 'triggers', + href: `${base}/nats_triggers`, + kind: 'nats' + }, + { + label: t('operator.sqs_triggers'), + id: 'triggers', + href: `${base}/sqs_triggers`, + kind: 'sqs' + }, + { + label: t('operator.gcp_triggers'), id: 'triggers', href: `${base}/gcp_triggers`, kind: 'gcp' }, - { label: 'MQTT triggers', id: 'triggers', href: `${base}/mqtt_triggers`, kind: 'mqtt' }, - { label: 'Email triggers', id: 'triggers', href: `${base}/email_triggers`, kind: 'email' } + { + label: t('operator.mqtt_triggers'), + id: 'triggers', + href: `${base}/mqtt_triggers`, + kind: 'mqtt' + }, + { + label: t('operator.email_triggers'), + id: 'triggers', + href: `${base}/email_triggers`, + kind: 'email' + } ] as TriggerMenuLink[] ).filter(filterLink) ) @@ -231,7 +262,7 @@ {item} > - Account settings + {t('user.account_settings')} @@ -259,7 +290,7 @@ {:else} {/if} - Switch theme + {t('user.switch_theme')} - Instance settings + {t('sidebar.instance')} {/if} @@ -303,7 +334,7 @@ {item} > - Sign out + {t('user.sign_out')}
diff --git a/frontend/src/lib/components/sidebar/SidebarContent.svelte b/frontend/src/lib/components/sidebar/SidebarContent.svelte index b0382158bf..ff85b719c3 100644 --- a/frontend/src/lib/components/sidebar/SidebarContent.svelte +++ b/frontend/src/lib/components/sidebar/SidebarContent.svelte @@ -73,6 +73,7 @@ } from '$lib/components/meltComponents' import MenuButton from './MenuButton.svelte' import GoogleCloudIcon from '../icons/GoogleCloudIcon.svelte' + import { t } from '$lib/i18n/t.svelte' async function leaveWorkspace() { await WorkspaceService.leaveWorkspace({ workspace: $workspaceStore ?? '' }) @@ -133,13 +134,13 @@ hasNewChangelogs = false } - const thirdMenuLinks = [ + let thirdMenuLinks = $derived([ { - label: 'Help', + label: t('sidebar.help'), icon: HelpCircle, subItems: [ { - label: 'Tutorials', + label: t('sidebar.tutorials'), href: `${base}/tutorials`, icon: GraduationCap, aiId: 'sidebar-menu-link-tutorials', @@ -147,7 +148,7 @@ external: false }, { - label: 'Docs', + label: t('sidebar.docs'), href: 'https://www.windmill.dev/docs/intro/', icon: BookOpen, aiId: 'sidebar-menu-link-docs', @@ -155,7 +156,7 @@ external: true }, { - label: 'Feedbacks', + label: t('sidebar.feedbacks'), href: 'https://discord.gg/V7PM2YHsPB', icon: DiscordIcon, aiId: 'sidebar-menu-link-feedbacks', @@ -163,7 +164,7 @@ external: true }, { - label: 'Issues', + label: t('sidebar.issues'), href: 'https://github.com/windmill-labs/windmill/issues/new', icon: Github, aiId: 'sidebar-menu-link-issues', @@ -171,7 +172,7 @@ external: true }, { - label: 'Changelog', + label: t('sidebar.changelog'), href: 'https://www.windmill.dev/changelog/', icon: Newspaper, aiId: 'sidebar-menu-link-changelog', @@ -180,7 +181,7 @@ } ] } - ] + ]) interface Props { numUnacknowledgedCriticalAlerts?: number @@ -205,7 +206,7 @@ ) let mainMenuLinks = $derived([ { - label: 'Home', + label: t('sidebar.home'), href: `${base}/`, icon: Home, aiId: 'sidebar-menu-link-home', @@ -213,7 +214,7 @@ "Button to navigate to home which contains all the user's scripts, flows and apps" }, { - label: 'Runs', + label: t('sidebar.runs'), href: `${base}/runs`, icon: Play, aiId: 'sidebar-menu-link-runs', @@ -225,7 +226,7 @@ } }, { - label: 'Variables', + label: t('sidebar.variables'), href: `${base}/variables`, icon: DollarSign, disabled: $userStore?.operator, @@ -233,7 +234,7 @@ aiDescription: 'Button to navigate to variables' }, { - label: 'Resources', + label: t('sidebar.resources'), href: `${base}/resources`, icon: Boxes, disabled: $userStore?.operator, @@ -241,7 +242,7 @@ aiDescription: 'Button to navigate to resources' }, { - label: 'Assets', + label: t('sidebar.assets'), href: `${base}/assets`, icon: Pyramid, disabled: $userStore?.operator, @@ -252,7 +253,7 @@ ...($tutorialsToDo.length > 0 && !$skippedAll ? [ { - label: 'Tutorials', + label: t('sidebar.tutorials'), href: `${base}/tutorials`, icon: GraduationCap, aiId: 'sidebar-menu-link-tutorials-main', @@ -263,7 +264,7 @@ ]) let defaultExtraTriggerLinks = $derived([ { - label: 'HTTP', + label: t('sidebar.http'), href: '/routes', icon: Route, disabled: $userStore?.operator, @@ -272,7 +273,7 @@ aiDescription: 'Button to navigate to HTTP routes' }, { - label: 'WebSockets', + label: t('sidebar.websockets'), href: '/websocket_triggers', icon: Unplug, disabled: $userStore?.operator, @@ -281,7 +282,7 @@ aiDescription: 'Button to navigate to websocket triggers' }, { - label: 'Postgres', + label: t('sidebar.postgres'), href: '/postgres_triggers', icon: Database, disabled: $userStore?.operator, @@ -290,7 +291,7 @@ aiDescription: 'Button to navigate to Postgres triggers' }, { - label: 'Kafka' + ($enterpriseLicense ? '' : ' (EE)'), + label: t('sidebar.kafka') + ($enterpriseLicense ? '' : ' (EE)'), href: '/kafka_triggers', icon: KafkaIcon, disabled: $userStore?.operator || !$enterpriseLicense, @@ -299,7 +300,7 @@ aiDescription: 'Button to navigate to Kafka triggers' }, { - label: 'NATS' + ($enterpriseLicense ? '' : ' (EE)'), + label: t('sidebar.nats') + ($enterpriseLicense ? '' : ' (EE)'), href: '/nats_triggers', icon: NatsIcon, disabled: $userStore?.operator || !$enterpriseLicense, @@ -308,7 +309,7 @@ aiDescription: 'Button to navigate to NATS triggers' }, { - label: 'SQS' + ($enterpriseLicense ? '' : ' (EE)'), + label: t('sidebar.sqs') + ($enterpriseLicense ? '' : ' (EE)'), href: '/sqs_triggers', icon: AwsIcon, disabled: $userStore?.operator || !$enterpriseLicense, @@ -317,7 +318,7 @@ aiDescription: 'Button to navigate to SQS triggers' }, { - label: 'GCP Pub/Sub' + ($enterpriseLicense ? '' : ' (EE)'), + label: t('sidebar.gcp_pubsub') + ($enterpriseLicense ? '' : ' (EE)'), href: '/gcp_triggers', icon: GoogleCloudIcon, disabled: $userStore?.operator || !$enterpriseLicense, @@ -326,7 +327,7 @@ aiDescription: 'Button to navigate to GCP Pub/Sub triggers' }, { - label: 'MQTT', + label: t('sidebar.mqtt'), href: '/mqtt_triggers', icon: MqttIcon, disabled: $userStore?.operator, @@ -335,7 +336,7 @@ aiDescription: 'Button to navigate to MQTT triggers' }, { - label: 'Email', + label: t('sidebar.email'), href: '/email_triggers', icon: MailIcon, disabled: $userStore?.operator, @@ -361,7 +362,7 @@ let triggerMenuLinks = $derived([ { - label: 'Schedules', + label: t('sidebar.schedules'), href: `${base}/schedules`, icon: Calendar, disabled: !SIDEBAR_SHOW_SCHEDULES || $userStore?.operator, @@ -385,14 +386,14 @@ // disabled: !$userStore?.is_admin && !$userStore?.is_super_admin // }, { - label: 'Settings', + label: t('sidebar.settings'), icon: Settings, aiId: 'sidebar-menu-link-settings', aiDescription: 'Button to navigate to settings, including account, workspace, and instance settings', subItems: [ { - label: 'Account', + label: t('sidebar.account'), href: '#user-settings', icon: UserCog, aiId: 'sidebar-menu-link-account', @@ -402,7 +403,7 @@ ...($userStore?.is_admin || $superadmin ? [ { - label: 'Workspace', + label: t('sidebar.workspace'), href: `${base}/workspace_settings`, icon: FolderCog, aiId: 'sidebar-menu-link-workspace', @@ -414,7 +415,7 @@ ...($superadmin ? [ { - label: 'Instance', + label: t('sidebar.instance'), href: '#superadmin-settings', icon: ServerCog, aiId: 'sidebar-menu-link-instance', @@ -426,7 +427,7 @@ ...(!$superadmin && !$userStore?.is_admin ? [ { - label: 'Leave workspace', + label: t('sidebar.leave_workspace'), action: () => { leaveWorkspaceModal = true }, @@ -439,7 +440,7 @@ ...($workspaceStore?.startsWith('wm-fork-') ? [ { - label: 'Delete Forked Workspace', + label: t('sidebar.delete_fork'), action: () => { deleteWorkspaceForkModal = true }, @@ -452,7 +453,7 @@ disabled: $userStore?.operator }, { - label: 'Workers', + label: t('sidebar.workers'), href: `${base}/workers`, icon: ServerCog, disabled: $userStore?.operator, @@ -460,13 +461,13 @@ aiDescription: 'Button to navigate to workers' }, { - label: 'Folders & Groups', + label: t('sidebar.folders_groups'), icon: FolderOpen, aiId: 'sidebar-menu-link-folders-groups', aiDescription: 'Button to navigate to folders and groups', subItems: [ { - label: 'Folders', + label: t('sidebar.folders'), href: `${base}/folders`, icon: FolderOpen, disabled: $userStore?.operator, @@ -475,7 +476,7 @@ faIcon: undefined }, { - label: 'Groups', + label: t('sidebar.groups'), href: `${base}/groups`, icon: UserCog, disabled: $userStore?.operator, @@ -488,13 +489,13 @@ }, $devopsRole || $userStore?.is_admin ? { - label: 'Logs', + label: t('sidebar.logs'), icon: Logs, aiId: 'sidebar-menu-link-logs', aiDescription: 'Button to navigate to logs', subItems: [ { - label: 'Audit logs', + label: t('sidebar.audit_logs'), href: `${base}/audit_logs`, icon: Eye, aiId: 'sidebar-menu-link-audit-logs', @@ -503,7 +504,7 @@ ...($devopsRole ? [ { - label: 'Service logs', + label: t('sidebar.service_logs'), href: `${base}/service_logs`, icon: Logs, aiId: 'sidebar-menu-link-service-logs', @@ -514,7 +515,7 @@ ...($enterpriseLicense ? [ { - label: 'Critical alerts', + label: t('sidebar.critical_alerts'), action: () => { isCriticalAlertsUIOpen.set(true) }, @@ -528,7 +529,7 @@ ] } : { - label: 'Audit logs', + label: t('sidebar.audit_logs'), href: `${base}/audit_logs`, icon: Eye, disabled: $userStore?.operator, @@ -552,7 +553,7 @@
Triggers
{t('sidebar.triggers')}
{#snippet children({ createMenu })} diff --git a/frontend/src/lib/components/sidebar/UserMenu.svelte b/frontend/src/lib/components/sidebar/UserMenu.svelte index b6e6d6a9cc..bb3bb03a59 100644 --- a/frontend/src/lib/components/sidebar/UserMenu.svelte +++ b/frontend/src/lib/components/sidebar/UserMenu.svelte @@ -11,11 +11,14 @@ import { USER_SETTINGS_HASH } from './settings' import { isCloudHosted } from '$lib/cloud' import { twMerge } from 'tailwind-merge' - import { Crown, ServerCog, LogOut, Moon, Settings, Sun, User } from 'lucide-svelte' + import { Crown, ServerCog, LogOut, Moon, Settings, Sun, User, Languages } from 'lucide-svelte' import DarkModeObserver from '../DarkModeObserver.svelte' import MenuButton from './MenuButton.svelte' import { Menu, MenuItem } from '$lib/components/meltComponents' import { type MenubarBuilders } from '@melt-ui/svelte' + import { t } from '$lib/i18n/t.svelte' + import { getLocale, setLocale } from '$lib/i18n/t.svelte' + import { SUPPORTED_LOCALES, LOCALE_NAMES } from '$lib/i18n/index' let darkMode: boolean = $state(false) @@ -53,16 +56,16 @@

{#if $userStore?.is_admin} - Admin of this workspace + {t('user.admin_of_workspace')} {:else if $userStore?.operator} - Operator in this workspace + {t('user.operator_in_workspace')} {/if}
- Account settings + {t('user.account_settings')} {/if} - Switch theme + {t('user.switch_theme')} + + + { + const currentIndex = SUPPORTED_LOCALES.indexOf(getLocale()) + const nextIndex = (currentIndex + 1) % SUPPORTED_LOCALES.length + setLocale(SUPPORTED_LOCALES[nextIndex]) + }} + class={itemClass} + {item} + > + + {t('user.language')}: {LOCALE_NAMES[getLocale()]} logout()} class={itemClass} {item}> - Sign out + {t('user.sign_out')}
@@ -125,7 +141,7 @@ }} {item} > - Upgrade + {t('user.upgrade')} {/if} {:else} @@ -136,7 +152,7 @@ }} {item} > - Premium plan + {t('user.premium_plan')} {/if} diff --git a/frontend/src/lib/i18n/index.ts b/frontend/src/lib/i18n/index.ts new file mode 100644 index 0000000000..5fbe595a41 --- /dev/null +++ b/frontend/src/lib/i18n/index.ts @@ -0,0 +1,14 @@ +export const SUPPORTED_LOCALES = ['en', 'fr', 'de', 'es', 'pt', 'ja', 'zh', 'ko'] as const +export type Locale = (typeof SUPPORTED_LOCALES)[number] +export const DEFAULT_LOCALE: Locale = 'en' + +export const LOCALE_NAMES: Record = { + en: 'English', + fr: 'Français', + de: 'Deutsch', + es: 'Español', + pt: 'Português', + ja: '日本語', + zh: '中文', + ko: '한국어' +} diff --git a/frontend/src/lib/i18n/messages/de.ts b/frontend/src/lib/i18n/messages/de.ts new file mode 100644 index 0000000000..9a67e9379e --- /dev/null +++ b/frontend/src/lib/i18n/messages/de.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const de: Record = { + // Sidebar - main nav + 'sidebar.home': 'Start', + 'sidebar.runs': 'Ausführungen', + 'sidebar.variables': 'Variablen', + 'sidebar.resources': 'Ressourcen', + 'sidebar.assets': 'Assets', + 'sidebar.tutorials': 'Tutorials', + + // Sidebar - triggers section + 'sidebar.triggers': 'Trigger', + 'sidebar.schedules': 'Zeitpläne', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'E-Mail', + + // Sidebar - settings + 'sidebar.settings': 'Einstellungen', + 'sidebar.account': 'Konto', + 'sidebar.workspace': 'Workspace', + 'sidebar.instance': 'Instanz', + 'sidebar.leave_workspace': 'Verlassen', + 'sidebar.delete_fork': 'Fork löschen', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': 'Ordner & Gruppen', + 'sidebar.folders': 'Ordner', + 'sidebar.groups': 'Gruppen', + 'sidebar.logs': 'Protokolle', + 'sidebar.audit_logs': 'Audit', + 'sidebar.service_logs': 'Dienste', + 'sidebar.critical_alerts': 'Kritische Alerts', + + // Sidebar - help + 'sidebar.help': 'Hilfe', + 'sidebar.docs': 'Doku', + 'sidebar.feedbacks': 'Feedback', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': 'Changelog', + + // User menu + 'user.account_settings': 'Kontoeinstellungen', + 'user.switch_theme': 'Design wechseln', + 'user.sign_out': 'Abmelden', + 'user.upgrade': 'Upgrade', + 'user.premium_plan': 'Premium-Plan', + 'user.admin_of_workspace': 'Admin', + 'user.operator_in_workspace': 'Operator', + 'user.language': 'Sprache', + + // Operator menu + 'operator.custom_http_routes': 'HTTP-Routen', + 'operator.websocket_triggers': 'WebSocket-Trigger', + 'operator.postgres_triggers': 'Postgres-Trigger', + 'operator.kafka_triggers': 'Kafka-Trigger', + 'operator.nats_triggers': 'NATS-Trigger', + 'operator.sqs_triggers': 'SQS-Trigger', + 'operator.gcp_triggers': 'GCP-Trigger', + 'operator.mqtt_triggers': 'MQTT-Trigger', + 'operator.email_triggers': 'E-Mail-Trigger', + + // Common actions + 'action.save': 'Speichern', + 'action.cancel': 'Abbrechen', + 'action.delete': 'Löschen', + 'action.edit': 'Bearbeiten', + 'action.create': 'Erstellen', + 'action.run': 'Ausführen', + 'action.deploy': 'Deployen', + 'action.share': 'Teilen', + 'action.close': 'Schließen', + 'action.confirm': 'Bestätigen', + 'action.refresh': 'Aktualisieren', + + // Page headers + 'page.home': 'Start', + 'page.variables': 'Variablen', + 'page.resources': 'Ressourcen', + 'page.schedules': 'Zeitpläne', + 'page.workers': 'Workers', + 'page.folders': 'Ordner', + 'page.groups': 'Gruppen' +} diff --git a/frontend/src/lib/i18n/messages/en.ts b/frontend/src/lib/i18n/messages/en.ts new file mode 100644 index 0000000000..ea19ac4689 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en.ts @@ -0,0 +1,90 @@ +export const en = { + // Sidebar - main nav + 'sidebar.home': 'Home', + 'sidebar.runs': 'Runs', + 'sidebar.variables': 'Variables', + 'sidebar.resources': 'Resources', + 'sidebar.assets': 'Assets', + 'sidebar.tutorials': 'Tutorials', + + // Sidebar - triggers section + 'sidebar.triggers': 'Triggers', + 'sidebar.schedules': 'Schedules', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'Email', + + // Sidebar - settings + 'sidebar.settings': 'Settings', + 'sidebar.account': 'Account', + 'sidebar.workspace': 'Workspace', + 'sidebar.instance': 'Instance', + 'sidebar.leave_workspace': 'Leave workspace', + 'sidebar.delete_fork': 'Delete Forked Workspace', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': 'Folders & Groups', + 'sidebar.folders': 'Folders', + 'sidebar.groups': 'Groups', + 'sidebar.logs': 'Logs', + 'sidebar.audit_logs': 'Audit logs', + 'sidebar.service_logs': 'Service logs', + 'sidebar.critical_alerts': 'Critical alerts', + + // Sidebar - help + 'sidebar.help': 'Help', + 'sidebar.docs': 'Docs', + 'sidebar.feedbacks': 'Feedbacks', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': 'Changelog', + + // User menu + 'user.account_settings': 'Account settings', + 'user.switch_theme': 'Switch theme', + 'user.sign_out': 'Sign out', + 'user.upgrade': 'Upgrade', + 'user.premium_plan': 'Premium plan', + 'user.admin_of_workspace': 'Admin of this workspace', + 'user.operator_in_workspace': 'Operator in this workspace', + 'user.language': 'Language', + + // Operator menu + 'operator.custom_http_routes': 'Custom HTTP routes', + 'operator.websocket_triggers': 'Websocket triggers', + 'operator.postgres_triggers': 'Postgres triggers', + 'operator.kafka_triggers': 'Kafka triggers', + 'operator.nats_triggers': 'NATS triggers', + 'operator.sqs_triggers': 'SQS triggers', + 'operator.gcp_triggers': 'GCP Pub/Sub triggers', + 'operator.mqtt_triggers': 'MQTT triggers', + 'operator.email_triggers': 'Email triggers', + + // Common actions + 'action.save': 'Save', + 'action.cancel': 'Cancel', + 'action.delete': 'Delete', + 'action.edit': 'Edit', + 'action.create': 'Create', + 'action.run': 'Run', + 'action.deploy': 'Deploy', + 'action.share': 'Share', + 'action.close': 'Close', + 'action.confirm': 'Confirm', + 'action.refresh': 'Refresh', + + // Page headers + 'page.home': 'Home', + 'page.variables': 'Variables', + 'page.resources': 'Resources', + 'page.schedules': 'Schedules', + 'page.workers': 'Workers', + 'page.folders': 'Folders', + 'page.groups': 'Groups' +} as const + +export type MessageKey = keyof typeof en diff --git a/frontend/src/lib/i18n/messages/es.ts b/frontend/src/lib/i18n/messages/es.ts new file mode 100644 index 0000000000..35cfb561ba --- /dev/null +++ b/frontend/src/lib/i18n/messages/es.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const es: Record = { + // Sidebar - main nav + 'sidebar.home': 'Inicio', + 'sidebar.runs': 'Ejecuciones', + 'sidebar.variables': 'Variables', + 'sidebar.resources': 'Recursos', + 'sidebar.assets': 'Assets', + 'sidebar.tutorials': 'Tutoriales', + + // Sidebar - triggers section + 'sidebar.triggers': 'Disparadores', + 'sidebar.schedules': 'Programados', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'Email', + + // Sidebar - settings + 'sidebar.settings': 'Ajustes', + 'sidebar.account': 'Cuenta', + 'sidebar.workspace': 'Espacio', + 'sidebar.instance': 'Instancia', + 'sidebar.leave_workspace': 'Salir', + 'sidebar.delete_fork': 'Eliminar fork', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': 'Carpetas y Grupos', + 'sidebar.folders': 'Carpetas', + 'sidebar.groups': 'Grupos', + 'sidebar.logs': 'Registros', + 'sidebar.audit_logs': 'Auditoría', + 'sidebar.service_logs': 'Servicios', + 'sidebar.critical_alerts': 'Alertas críticas', + + // Sidebar - help + 'sidebar.help': 'Ayuda', + 'sidebar.docs': 'Docs', + 'sidebar.feedbacks': 'Comentarios', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': 'Changelog', + + // User menu + 'user.account_settings': 'Mi cuenta', + 'user.switch_theme': 'Cambiar tema', + 'user.sign_out': 'Cerrar sesión', + 'user.upgrade': 'Mejorar plan', + 'user.premium_plan': 'Plan premium', + 'user.admin_of_workspace': 'Admin', + 'user.operator_in_workspace': 'Operador', + 'user.language': 'Idioma', + + // Operator menu + 'operator.custom_http_routes': 'Rutas HTTP', + 'operator.websocket_triggers': 'Triggers WebSocket', + 'operator.postgres_triggers': 'Triggers Postgres', + 'operator.kafka_triggers': 'Triggers Kafka', + 'operator.nats_triggers': 'Triggers NATS', + 'operator.sqs_triggers': 'Triggers SQS', + 'operator.gcp_triggers': 'Triggers GCP', + 'operator.mqtt_triggers': 'Triggers MQTT', + 'operator.email_triggers': 'Triggers email', + + // Common actions + 'action.save': 'Guardar', + 'action.cancel': 'Cancelar', + 'action.delete': 'Eliminar', + 'action.edit': 'Editar', + 'action.create': 'Crear', + 'action.run': 'Ejecutar', + 'action.deploy': 'Desplegar', + 'action.share': 'Compartir', + 'action.close': 'Cerrar', + 'action.confirm': 'Confirmar', + 'action.refresh': 'Actualizar', + + // Page headers + 'page.home': 'Inicio', + 'page.variables': 'Variables', + 'page.resources': 'Recursos', + 'page.schedules': 'Programados', + 'page.workers': 'Workers', + 'page.folders': 'Carpetas', + 'page.groups': 'Grupos' +} diff --git a/frontend/src/lib/i18n/messages/fr.ts b/frontend/src/lib/i18n/messages/fr.ts new file mode 100644 index 0000000000..b40a9bdac4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const fr: Record = { + // Sidebar - main nav + 'sidebar.home': 'Accueil', + 'sidebar.runs': 'Exécutions', + 'sidebar.variables': 'Variables', + 'sidebar.resources': 'Ressources', + 'sidebar.assets': 'Assets', + 'sidebar.tutorials': 'Tutoriels', + + // Sidebar - triggers section + 'sidebar.triggers': 'Déclencheurs', + 'sidebar.schedules': 'Plannings', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'Email', + + // Sidebar - settings + 'sidebar.settings': 'Paramètres', + 'sidebar.account': 'Compte', + 'sidebar.workspace': 'Espace', + 'sidebar.instance': 'Instance', + 'sidebar.leave_workspace': 'Quitter', + 'sidebar.delete_fork': 'Supprimer le fork', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': 'Dossiers & Groupes', + 'sidebar.folders': 'Dossiers', + 'sidebar.groups': 'Groupes', + 'sidebar.logs': 'Journaux', + 'sidebar.audit_logs': 'Audit', + 'sidebar.service_logs': 'Services', + 'sidebar.critical_alerts': 'Alertes critiques', + + // Sidebar - help + 'sidebar.help': 'Aide', + 'sidebar.docs': 'Docs', + 'sidebar.feedbacks': 'Retours', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': 'Changelog', + + // User menu + 'user.account_settings': 'Mon compte', + 'user.switch_theme': 'Changer de thème', + 'user.sign_out': 'Déconnexion', + 'user.upgrade': 'Passer en premium', + 'user.premium_plan': 'Plan premium', + 'user.admin_of_workspace': 'Admin de cet espace', + 'user.operator_in_workspace': 'Opérateur', + 'user.language': 'Langue', + + // Operator menu + 'operator.custom_http_routes': 'Routes HTTP', + 'operator.websocket_triggers': 'Déclencheurs WS', + 'operator.postgres_triggers': 'Déclencheurs PG', + 'operator.kafka_triggers': 'Déclencheurs Kafka', + 'operator.nats_triggers': 'Déclencheurs NATS', + 'operator.sqs_triggers': 'Déclencheurs SQS', + 'operator.gcp_triggers': 'Déclencheurs GCP', + 'operator.mqtt_triggers': 'Déclencheurs MQTT', + 'operator.email_triggers': 'Déclencheurs email', + + // Common actions + 'action.save': 'Enregistrer', + 'action.cancel': 'Annuler', + 'action.delete': 'Supprimer', + 'action.edit': 'Modifier', + 'action.create': 'Créer', + 'action.run': 'Lancer', + 'action.deploy': 'Déployer', + 'action.share': 'Partager', + 'action.close': 'Fermer', + 'action.confirm': 'Confirmer', + 'action.refresh': 'Actualiser', + + // Page headers + 'page.home': 'Accueil', + 'page.variables': 'Variables', + 'page.resources': 'Ressources', + 'page.schedules': 'Plannings', + 'page.workers': 'Workers', + 'page.folders': 'Dossiers', + 'page.groups': 'Groupes' +} diff --git a/frontend/src/lib/i18n/messages/index.ts b/frontend/src/lib/i18n/messages/index.ts new file mode 100644 index 0000000000..2d915de831 --- /dev/null +++ b/frontend/src/lib/i18n/messages/index.ts @@ -0,0 +1,22 @@ +import type { Locale } from '../index' +import { en, type MessageKey } from './en' +import { fr } from './fr' +import { de } from './de' +import { es } from './es' +import { pt } from './pt' +import { ja } from './ja' +import { zh } from './zh' +import { ko } from './ko' + +export type { MessageKey } + +export const messages: Record> = { + en, + fr, + de, + es, + pt, + ja, + zh, + ko +} diff --git a/frontend/src/lib/i18n/messages/ja.ts b/frontend/src/lib/i18n/messages/ja.ts new file mode 100644 index 0000000000..16c5ea3479 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const ja: Record = { + // Sidebar - main nav + 'sidebar.home': 'ホーム', + 'sidebar.runs': '実行', + 'sidebar.variables': '変数', + 'sidebar.resources': 'リソース', + 'sidebar.assets': 'アセット', + 'sidebar.tutorials': 'チュートリアル', + + // Sidebar - triggers section + 'sidebar.triggers': 'トリガー', + 'sidebar.schedules': 'スケジュール', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'メール', + + // Sidebar - settings + 'sidebar.settings': '設定', + 'sidebar.account': 'アカウント', + 'sidebar.workspace': 'ワークスペース', + 'sidebar.instance': 'インスタンス', + 'sidebar.leave_workspace': '退出', + 'sidebar.delete_fork': 'フォークを削除', + 'sidebar.workers': 'ワーカー', + 'sidebar.folders_groups': 'フォルダとグループ', + 'sidebar.folders': 'フォルダ', + 'sidebar.groups': 'グループ', + 'sidebar.logs': 'ログ', + 'sidebar.audit_logs': '監査ログ', + 'sidebar.service_logs': 'サービスログ', + 'sidebar.critical_alerts': '重要なアラート', + + // Sidebar - help + 'sidebar.help': 'ヘルプ', + 'sidebar.docs': 'ドキュメント', + 'sidebar.feedbacks': 'フィードバック', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': '変更履歴', + + // User menu + 'user.account_settings': 'アカウント設定', + 'user.switch_theme': 'テーマ切替', + 'user.sign_out': 'ログアウト', + 'user.upgrade': 'アップグレード', + 'user.premium_plan': 'プレミアムプラン', + 'user.admin_of_workspace': '管理者', + 'user.operator_in_workspace': 'オペレーター', + 'user.language': '言語', + + // Operator menu + 'operator.custom_http_routes': 'HTTPルート', + 'operator.websocket_triggers': 'WebSocketトリガー', + 'operator.postgres_triggers': 'Postgresトリガー', + 'operator.kafka_triggers': 'Kafkaトリガー', + 'operator.nats_triggers': 'NATSトリガー', + 'operator.sqs_triggers': 'SQSトリガー', + 'operator.gcp_triggers': 'GCPトリガー', + 'operator.mqtt_triggers': 'MQTTトリガー', + 'operator.email_triggers': 'メールトリガー', + + // Common actions + 'action.save': '保存', + 'action.cancel': 'キャンセル', + 'action.delete': '削除', + 'action.edit': '編集', + 'action.create': '作成', + 'action.run': '実行', + 'action.deploy': 'デプロイ', + 'action.share': '共有', + 'action.close': '閉じる', + 'action.confirm': '確認', + 'action.refresh': '更新', + + // Page headers + 'page.home': 'ホーム', + 'page.variables': '変数', + 'page.resources': 'リソース', + 'page.schedules': 'スケジュール', + 'page.workers': 'ワーカー', + 'page.folders': 'フォルダ', + 'page.groups': 'グループ' +} diff --git a/frontend/src/lib/i18n/messages/ko.ts b/frontend/src/lib/i18n/messages/ko.ts new file mode 100644 index 0000000000..68e7ab73ba --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const ko: Record = { + // Sidebar - main nav + 'sidebar.home': '홈', + 'sidebar.runs': '실행', + 'sidebar.variables': '변수', + 'sidebar.resources': '리소스', + 'sidebar.assets': '에셋', + 'sidebar.tutorials': '튜토리얼', + + // Sidebar - triggers section + 'sidebar.triggers': '트리거', + 'sidebar.schedules': '스케줄', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': '이메일', + + // Sidebar - settings + 'sidebar.settings': '설정', + 'sidebar.account': '계정', + 'sidebar.workspace': '워크스페이스', + 'sidebar.instance': '인스턴스', + 'sidebar.leave_workspace': '나가기', + 'sidebar.delete_fork': '포크 삭제', + 'sidebar.workers': '워커', + 'sidebar.folders_groups': '폴더 및 그룹', + 'sidebar.folders': '폴더', + 'sidebar.groups': '그룹', + 'sidebar.logs': '로그', + 'sidebar.audit_logs': '감사 로그', + 'sidebar.service_logs': '서비스 로그', + 'sidebar.critical_alerts': '심각한 알림', + + // Sidebar - help + 'sidebar.help': '도움말', + 'sidebar.docs': '문서', + 'sidebar.feedbacks': '피드백', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': '변경 내역', + + // User menu + 'user.account_settings': '계정 설정', + 'user.switch_theme': '테마 전환', + 'user.sign_out': '로그아웃', + 'user.upgrade': '업그레이드', + 'user.premium_plan': '프리미엄 플랜', + 'user.admin_of_workspace': '관리자', + 'user.operator_in_workspace': '운영자', + 'user.language': '언어', + + // Operator menu + 'operator.custom_http_routes': 'HTTP 라우트', + 'operator.websocket_triggers': 'WebSocket 트리거', + 'operator.postgres_triggers': 'Postgres 트리거', + 'operator.kafka_triggers': 'Kafka 트리거', + 'operator.nats_triggers': 'NATS 트리거', + 'operator.sqs_triggers': 'SQS 트리거', + 'operator.gcp_triggers': 'GCP 트리거', + 'operator.mqtt_triggers': 'MQTT 트리거', + 'operator.email_triggers': '이메일 트리거', + + // Common actions + 'action.save': '저장', + 'action.cancel': '취소', + 'action.delete': '삭제', + 'action.edit': '편집', + 'action.create': '생성', + 'action.run': '실행', + 'action.deploy': '배포', + 'action.share': '공유', + 'action.close': '닫기', + 'action.confirm': '확인', + 'action.refresh': '새로고침', + + // Page headers + 'page.home': '홈', + 'page.variables': '변수', + 'page.resources': '리소스', + 'page.schedules': '스케줄', + 'page.workers': '워커', + 'page.folders': '폴더', + 'page.groups': '그룹' +} diff --git a/frontend/src/lib/i18n/messages/pt.ts b/frontend/src/lib/i18n/messages/pt.ts new file mode 100644 index 0000000000..b648c12baa --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const pt: Record = { + // Sidebar - main nav + 'sidebar.home': 'Início', + 'sidebar.runs': 'Execuções', + 'sidebar.variables': 'Variáveis', + 'sidebar.resources': 'Recursos', + 'sidebar.assets': 'Assets', + 'sidebar.tutorials': 'Tutoriais', + + // Sidebar - triggers section + 'sidebar.triggers': 'Gatilhos', + 'sidebar.schedules': 'Agendamentos', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': 'Email', + + // Sidebar - settings + 'sidebar.settings': 'Configurações', + 'sidebar.account': 'Conta', + 'sidebar.workspace': 'Workspace', + 'sidebar.instance': 'Instância', + 'sidebar.leave_workspace': 'Sair', + 'sidebar.delete_fork': 'Excluir fork', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': 'Pastas e Grupos', + 'sidebar.folders': 'Pastas', + 'sidebar.groups': 'Grupos', + 'sidebar.logs': 'Logs', + 'sidebar.audit_logs': 'Auditoria', + 'sidebar.service_logs': 'Serviços', + 'sidebar.critical_alerts': 'Alertas críticos', + + // Sidebar - help + 'sidebar.help': 'Ajuda', + 'sidebar.docs': 'Docs', + 'sidebar.feedbacks': 'Feedbacks', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': 'Changelog', + + // User menu + 'user.account_settings': 'Minha conta', + 'user.switch_theme': 'Mudar tema', + 'user.sign_out': 'Sair', + 'user.upgrade': 'Upgrade', + 'user.premium_plan': 'Plano premium', + 'user.admin_of_workspace': 'Admin', + 'user.operator_in_workspace': 'Operador', + 'user.language': 'Idioma', + + // Operator menu + 'operator.custom_http_routes': 'Rotas HTTP', + 'operator.websocket_triggers': 'Triggers WebSocket', + 'operator.postgres_triggers': 'Triggers Postgres', + 'operator.kafka_triggers': 'Triggers Kafka', + 'operator.nats_triggers': 'Triggers NATS', + 'operator.sqs_triggers': 'Triggers SQS', + 'operator.gcp_triggers': 'Triggers GCP', + 'operator.mqtt_triggers': 'Triggers MQTT', + 'operator.email_triggers': 'Triggers email', + + // Common actions + 'action.save': 'Salvar', + 'action.cancel': 'Cancelar', + 'action.delete': 'Excluir', + 'action.edit': 'Editar', + 'action.create': 'Criar', + 'action.run': 'Executar', + 'action.deploy': 'Implantar', + 'action.share': 'Compartilhar', + 'action.close': 'Fechar', + 'action.confirm': 'Confirmar', + 'action.refresh': 'Atualizar', + + // Page headers + 'page.home': 'Início', + 'page.variables': 'Variáveis', + 'page.resources': 'Recursos', + 'page.schedules': 'Agendamentos', + 'page.workers': 'Workers', + 'page.folders': 'Pastas', + 'page.groups': 'Grupos' +} diff --git a/frontend/src/lib/i18n/messages/zh.ts b/frontend/src/lib/i18n/messages/zh.ts new file mode 100644 index 0000000000..c87b25f6fb --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh.ts @@ -0,0 +1,90 @@ +import type { MessageKey } from './en' + +export const zh: Record = { + // Sidebar - main nav + 'sidebar.home': '首页', + 'sidebar.runs': '运行', + 'sidebar.variables': '变量', + 'sidebar.resources': '资源', + 'sidebar.assets': '资产', + 'sidebar.tutorials': '教程', + + // Sidebar - triggers section + 'sidebar.triggers': '触发器', + 'sidebar.schedules': '定时任务', + 'sidebar.http': 'HTTP', + 'sidebar.websockets': 'WebSockets', + 'sidebar.postgres': 'Postgres', + 'sidebar.kafka': 'Kafka', + 'sidebar.nats': 'NATS', + 'sidebar.sqs': 'SQS', + 'sidebar.gcp_pubsub': 'GCP Pub/Sub', + 'sidebar.mqtt': 'MQTT', + 'sidebar.email': '邮件', + + // Sidebar - settings + 'sidebar.settings': '设置', + 'sidebar.account': '账户', + 'sidebar.workspace': '工作区', + 'sidebar.instance': '实例', + 'sidebar.leave_workspace': '退出', + 'sidebar.delete_fork': '删除分支', + 'sidebar.workers': 'Workers', + 'sidebar.folders_groups': '文件夹和分组', + 'sidebar.folders': '文件夹', + 'sidebar.groups': '分组', + 'sidebar.logs': '日志', + 'sidebar.audit_logs': '审计日志', + 'sidebar.service_logs': '服务日志', + 'sidebar.critical_alerts': '严重告警', + + // Sidebar - help + 'sidebar.help': '帮助', + 'sidebar.docs': '文档', + 'sidebar.feedbacks': '反馈', + 'sidebar.issues': 'Issues', + 'sidebar.changelog': '更新日志', + + // User menu + 'user.account_settings': '账户设置', + 'user.switch_theme': '切换主题', + 'user.sign_out': '退出登录', + 'user.upgrade': '升级', + 'user.premium_plan': '高级版', + 'user.admin_of_workspace': '管理员', + 'user.operator_in_workspace': '操作员', + 'user.language': '语言', + + // Operator menu + 'operator.custom_http_routes': 'HTTP路由', + 'operator.websocket_triggers': 'WebSocket触发器', + 'operator.postgres_triggers': 'Postgres触发器', + 'operator.kafka_triggers': 'Kafka触发器', + 'operator.nats_triggers': 'NATS触发器', + 'operator.sqs_triggers': 'SQS触发器', + 'operator.gcp_triggers': 'GCP触发器', + 'operator.mqtt_triggers': 'MQTT触发器', + 'operator.email_triggers': '邮件触发器', + + // Common actions + 'action.save': '保存', + 'action.cancel': '取消', + 'action.delete': '删除', + 'action.edit': '编辑', + 'action.create': '创建', + 'action.run': '运行', + 'action.deploy': '部署', + 'action.share': '共享', + 'action.close': '关闭', + 'action.confirm': '确认', + 'action.refresh': '刷新', + + // Page headers + 'page.home': '首页', + 'page.variables': '变量', + 'page.resources': '资源', + 'page.schedules': '定时任务', + 'page.workers': 'Workers', + 'page.folders': '文件夹', + 'page.groups': '分组' +} diff --git a/frontend/src/lib/i18n/t.svelte.ts b/frontend/src/lib/i18n/t.svelte.ts new file mode 100644 index 0000000000..da68dd3ae2 --- /dev/null +++ b/frontend/src/lib/i18n/t.svelte.ts @@ -0,0 +1,33 @@ +import { getLocalSetting, storeLocalSetting } from '$lib/utils' +import { type Locale, DEFAULT_LOCALE, SUPPORTED_LOCALES } from './index' +import { en, type MessageKey } from './messages/en' +import { messages } from './messages/index' + +function getInitialLocale(): Locale { + const stored = getLocalSetting('locale') + if (stored && SUPPORTED_LOCALES.includes(stored as Locale)) { + return stored as Locale + } + return DEFAULT_LOCALE +} + +let locale = $state(getInitialLocale()) + +export function getLocale(): Locale { + return locale +} + +export function setLocale(l: Locale) { + locale = l + storeLocalSetting('locale', l) + if (typeof document !== 'undefined') { + document.documentElement.lang = l + } +} + +export function t(key: MessageKey): string { + if (locale === 'en') { + return en[key] + } + return messages[locale]?.[key] ?? en[key] +}