From 99c60cc2bca8516861103deea23ea0a361e2bb37 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 14:03:58 +0000 Subject: [PATCH 01/34] Add i18n proof-of-concept using react-i18next, localize About modal Introduces a self-contained i18next setup (frontend/util/i18n) with en/de resource bundles and a language-switch atom, then wires the About modal over to translated strings including a quick EN/DE toggle to demonstrate the flow end-to-end. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01W9bu5FCyue74RQbpEgQBxm --- frontend/app/modals/about.test.tsx | 30 ++++++++++++++++++++++ frontend/app/modals/about.tsx | 41 ++++++++++++++++++++++-------- frontend/util/i18n/i18n.ts | 39 ++++++++++++++++++++++++++++ frontend/util/i18n/locales/de.json | 14 ++++++++++ frontend/util/i18n/locales/en.json | 14 ++++++++++ frontend/wave.ts | 1 + package.json | 2 ++ 7 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 frontend/app/modals/about.test.tsx create mode 100644 frontend/util/i18n/i18n.ts create mode 100644 frontend/util/i18n/locales/de.json create mode 100644 frontend/util/i18n/locales/en.json diff --git a/frontend/app/modals/about.test.tsx b/frontend/app/modals/about.test.tsx new file mode 100644 index 0000000000..3679994357 --- /dev/null +++ b/frontend/app/modals/about.test.tsx @@ -0,0 +1,30 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { setLanguage } from "@/util/i18n/i18n"; +import { renderToStaticMarkup } from "react-dom/server"; +import { afterEach, describe, expect, it } from "vitest"; +import { AboutModalV } from "./about"; + +describe("AboutModalV localization", () => { + afterEach(() => { + setLanguage("en"); + }); + + it("renders English strings by default", () => { + const markup = renderToStaticMarkup( + null} /> + ); + expect(markup).toContain("Open-Source AI-Integrated Terminal"); + expect(markup).toContain("Client Version 0.14.5 (test)"); + }); + + it("renders German strings once the language is switched", () => { + setLanguage("de"); + const markup = renderToStaticMarkup( + null} /> + ); + expect(markup).toContain("Open-Source-KI-Terminal"); + expect(markup).toContain("Client-Version 0.14.5 (test)"); + }); +}); diff --git a/frontend/app/modals/about.tsx b/frontend/app/modals/about.tsx index d3a43d386d..50adac23a0 100644 --- a/frontend/app/modals/about.tsx +++ b/frontend/app/modals/about.tsx @@ -7,10 +7,12 @@ import { atoms } from "@/app/store/global"; import { modalsModel } from "@/app/store/modalmodel"; import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { languageAtom, setLanguage, SUPPORTED_LANGUAGES, SupportedLanguage } from "@/util/i18n/i18n"; import { isDev } from "@/util/isdev"; import { fireAndForget } from "@/util/util"; import { useAtomValue } from "jotai"; import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { Modal } from "./modal"; interface AboutModalVProps { @@ -21,6 +23,8 @@ interface AboutModalVProps { const AboutModalV = ({ versionString, updaterChannel, onClose }: AboutModalVProps) => { const currentDate = new Date(); + const { t } = useTranslation(); + const language = useAtomValue(languageAtom); return ( @@ -28,17 +32,17 @@ const AboutModalV = ({ versionString, updaterChannel, onClose }: AboutModalVProp
-
Wave Terminal
+
{t("about.title")}
- Open-Source AI-Integrated Terminal + {t("about.tagline1")}
- Built for Seamless Workflows + {t("about.tagline2")}
- Client Version {versionString} + {t("about.clientVersion", { version: versionString })}
- Update Channel: {updaterChannel} + {t("about.updateChannel", { channel: updaterChannel })}
- © {currentDate.getFullYear()} Command Line Inc. + {t("about.copyright", { year: currentDate.getFullYear() })} +
+
+ {SUPPORTED_LANGUAGES.map((lang: SupportedLanguage) => ( + + ))}
diff --git a/frontend/util/i18n/i18n.ts b/frontend/util/i18n/i18n.ts new file mode 100644 index 0000000000..bd86b6049a --- /dev/null +++ b/frontend/util/i18n/i18n.ts @@ -0,0 +1,39 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { globalStore } from "@/app/store/jotaiStore"; +import { atom, PrimitiveAtom } from "jotai"; +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import de from "./locales/de.json"; +import en from "./locales/en.json"; + +const resources = { + en: { translation: en }, + de: { translation: de }, +}; + +export type SupportedLanguage = keyof typeof resources; + +export const SUPPORTED_LANGUAGES: SupportedLanguage[] = ["en", "de"]; + +i18n.use(initReactI18next).init({ + resources, + lng: "en", + fallbackLng: "en", + interpolation: { escapeValue: false }, + initImmediate: false, +}); + +export const languageAtom = atom("en") as PrimitiveAtom; + +globalStore.sub(languageAtom, () => { + const lang = globalStore.get(languageAtom); + i18n.changeLanguage(lang); +}); + +export function setLanguage(lang: SupportedLanguage) { + globalStore.set(languageAtom, lang); +} + +export default i18n; diff --git a/frontend/util/i18n/locales/de.json b/frontend/util/i18n/locales/de.json new file mode 100644 index 0000000000..84aa3eb6c5 --- /dev/null +++ b/frontend/util/i18n/locales/de.json @@ -0,0 +1,14 @@ +{ + "about": { + "title": "Wave Terminal", + "tagline1": "Open-Source-KI-Terminal", + "tagline2": "Entwickelt für nahtlose Workflows", + "clientVersion": "Client-Version {{version}}", + "updateChannel": "Update-Kanal: {{channel}}", + "github": "GitHub", + "website": "Website", + "openSource": "Open Source", + "sponsor": "Sponsor", + "copyright": "© {{year}} Command Line Inc." + } +} diff --git a/frontend/util/i18n/locales/en.json b/frontend/util/i18n/locales/en.json new file mode 100644 index 0000000000..0a06624428 --- /dev/null +++ b/frontend/util/i18n/locales/en.json @@ -0,0 +1,14 @@ +{ + "about": { + "title": "Wave Terminal", + "tagline1": "Open-Source AI-Integrated Terminal", + "tagline2": "Built for Seamless Workflows", + "clientVersion": "Client Version {{version}}", + "updateChannel": "Update Channel: {{channel}}", + "github": "GitHub", + "website": "Website", + "openSource": "Open Source", + "sponsor": "Sponsor", + "copyright": "© {{year}} Command Line Inc." + } +} diff --git a/frontend/wave.ts b/frontend/wave.ts index 20ee2ba97a..058864734c 100644 --- a/frontend/wave.ts +++ b/frontend/wave.ts @@ -31,6 +31,7 @@ import { import { activeTabIdAtom } from "@/store/tab-model"; import * as WOS from "@/store/wos"; import { loadFonts } from "@/util/fontutil"; +import "@/util/i18n/i18n"; import { setKeyUtilPlatform } from "@/util/keyutil"; import { isMacOS, setMacOSVersion } from "@/util/platformutil"; import { createElement } from "react"; diff --git a/package.json b/package.json index be03d9451b..f48a6a5204 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "fast-average-color": "^9.5.0", "htl": "^0.3.1", "html-to-image": "^1.11.13", + "i18next": "^26.4.2", "immer": "^10.1.1", "jotai": "2.9.3", "mermaid": "^11.15.0", @@ -109,6 +110,7 @@ "react-dnd-html5-backend": "^16.0.1", "react-dom": "^19.2.0", "react-frame-component": "^5.3.2", + "react-i18next": "^17.0.13", "react-markdown": "^9.0.3", "react-resizable-panels": "^3.0.6", "react-zoom-pan-pinch": "^3.7.0", From 9fcbf3efbde004518c62e7015f290632d4f7a294 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 14:13:24 +0000 Subject: [PATCH 02/34] Wire the About-modal language switch into the real settings system Adds app:language (en/de) to SettingsType, regenerates the JSON schema and TypeScript types via the codegen scripts, and replaces the PoC's local-only language toggle with a persisted setting: the About modal now calls SetConfigCommand, and a small AppLanguageSync effect in app.tsx keeps the i18n instance in sync with the settings atom. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01W9bu5FCyue74RQbpEgQBxm --- docs/docs/config.mdx | 1 + frontend/app/app.tsx | 12 ++++++- frontend/app/modals/about.tsx | 8 +++-- frontend/types/gotypes.d.ts | 2 ++ pkg/wconfig/defaultconfig/settings.json | 1 + pkg/wconfig/metaconsts.go | 1 + pkg/wconfig/settingsconfig.go | 45 +++++++++++++------------ schema/settings.json | 7 ++++ 8 files changed, 52 insertions(+), 25 deletions(-) diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx index 05389e99ef..8d05c785d6 100644 --- a/docs/docs/config.mdx +++ b/docs/docs/config.mdx @@ -45,6 +45,7 @@ wsh editconfig | app:disablectrlshiftdisplay | bool | Set to true to disable the Ctrl+Shift visual indicator display (defaults to false) | | app:focusfollowscursor | string | Controls whether block focus follows cursor movement: `"off"` (default), `"on"` (all blocks), or `"term"` (terminal blocks only) | | app:tabbar | string | Controls the position of the tab bar: `"top"` (default) for a horizontal tab bar at the top of the window, or `"left"` for a vertical tab bar on the left side of the window | +| app:language | string | Sets the UI language: `"en"` (default) or `"de"` | | ai:preset | string | the default AI preset to use | | ai:baseurl | string | Set the AI Base Url (must be OpenAI compatible) | | ai:apitoken | string | your AI api token | diff --git a/frontend/app/app.tsx b/frontend/app/app.tsx index e9c70a35df..c920fc2d17 100644 --- a/frontend/app/app.tsx +++ b/frontend/app/app.tsx @@ -17,9 +17,10 @@ import { makeWaveEnvImpl } from "@/app/waveenv/waveenvimpl"; import { Workspace } from "@/app/workspace/workspace"; import { getLayoutModelForStaticTab } from "@/layout/index"; import { ContextMenuModel } from "@/store/contextmenu"; -import { atoms, createBlock, getSettingsPrefixAtom, refocusNode } from "@/store/global"; +import { atoms, createBlock, getSettingsKeyAtom, getSettingsPrefixAtom, refocusNode } from "@/store/global"; import { appHandleKeyDown, keyboardMouseDownHandler } from "@/store/keymodel"; import { getElemAsStr } from "@/util/focusutil"; +import { setLanguage, SupportedLanguage } from "@/util/i18n/i18n"; import * as keyutil from "@/util/keyutil"; import { PLATFORM } from "@/util/platformutil"; import * as util from "@/util/util"; @@ -167,6 +168,14 @@ function AppSettingsUpdater() { return null; } +function AppLanguageSync() { + const language = useAtomValue(getSettingsKeyAtom("app:language")); + useEffect(() => { + setLanguage((language as SupportedLanguage) ?? "en"); + }, [language]); + return null; +} + function appFocusIn(e: FocusEvent) { focusLog("focusin", getElemAsStr(e.target), "<=", getElemAsStr(e.relatedTarget)); } @@ -382,6 +391,7 @@ const AppInner = () => { + diff --git a/frontend/app/modals/about.tsx b/frontend/app/modals/about.tsx index 50adac23a0..1726e914b9 100644 --- a/frontend/app/modals/about.tsx +++ b/frontend/app/modals/about.tsx @@ -7,7 +7,7 @@ import { atoms } from "@/app/store/global"; import { modalsModel } from "@/app/store/modalmodel"; import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; -import { languageAtom, setLanguage, SUPPORTED_LANGUAGES, SupportedLanguage } from "@/util/i18n/i18n"; +import { languageAtom, SUPPORTED_LANGUAGES, SupportedLanguage } from "@/util/i18n/i18n"; import { isDev } from "@/util/isdev"; import { fireAndForget } from "@/util/util"; import { useAtomValue } from "jotai"; @@ -89,7 +89,11 @@ const AboutModalV = ({ versionString, updaterChannel, onClose }: AboutModalVProp {SUPPORTED_LANGUAGES.map((lang: SupportedLanguage) => ( )} @@ -296,16 +302,16 @@ const AIToolUse = memo(({ part, isStreaming }: AIToolUseProps) => { )} {toolData.tooldesc && } {(toolData.errormessage || effectiveApproval === "timeout") && ( -
{toolData.errormessage || "Not approved"}
+
{toolData.errormessage || t("aiToolUse.notApproved")}
)} {effectiveApproval === "needs-approval" && (
diff --git a/frontend/app/aipanel/restorebackupmodal.tsx b/frontend/app/aipanel/restorebackupmodal.tsx index 36b4be5b5d..ade5f1e18d 100644 --- a/frontend/app/aipanel/restorebackupmodal.tsx +++ b/frontend/app/aipanel/restorebackupmodal.tsx @@ -5,6 +5,7 @@ import { Modal } from "@/app/modals/modal"; import { recordTEvent } from "@/app/store/global"; import { useAtomValue } from "jotai"; import { memo } from "react"; +import { useTranslation } from "react-i18next"; import { WaveUIMessagePart } from "./aitypes"; import { WaveAIModel } from "./waveai-model"; @@ -13,6 +14,7 @@ interface RestoreBackupModalProps { } export const RestoreBackupModal = memo(({ part }: RestoreBackupModalProps) => { + const { t } = useTranslation(); const model = WaveAIModel.getInstance(); const toolData = part.data; const status = useAtomValue(model.restoreBackupStatus); @@ -40,12 +42,18 @@ export const RestoreBackupModal = memo(({ part }: RestoreBackupModalProps) => { if (status === "success") { return ( - +
-
Backup Successfully Restored
+
{t("restoreBackup.restoredTitle")}
- The file {toolData.inputfilename} has - been restored to its previous state. + {t("restoreBackup.restoredBodyPrefix")}{" "} + {toolData.inputfilename}{" "} + {t("restoreBackup.restoredBodySuffix")}
@@ -54,12 +62,15 @@ export const RestoreBackupModal = memo(({ part }: RestoreBackupModalProps) => { if (status === "error") { return ( - +
-
Failed to Restore Backup
-
- An error occurred while restoring the backup: -
+
{t("restoreBackup.failedTitle")}
+
{t("restoreBackup.failedBody")}
{error}
@@ -74,21 +85,20 @@ export const RestoreBackupModal = memo(({ part }: RestoreBackupModalProps) => { onClose={handleCancel} onCancel={handleCancel} onOk={handleConfirm} - okLabel={isProcessing ? "Restoring..." : "Confirm Restore"} - cancelLabel="Cancel" + okLabel={isProcessing ? t("restoreBackup.restoring") : t("restoreBackup.confirmRestore")} + cancelLabel={t("modal.cancel")} okDisabled={isProcessing} cancelDisabled={isProcessing} >
-
Restore File Backup
+
{t("restoreBackup.title")}
- This will restore {toolData.inputfilename}{" "} - to its state before this edit was made + {t("restoreBackup.confirmBodyPrefix")}{" "} + {toolData.inputfilename}{" "} + {t("restoreBackup.confirmBodySuffix")} {toolData.runts && ({formatTimestamp(toolData.runts)})}.
-
- Any changes made by this edit and subsequent edits will be lost. -
+
{t("restoreBackup.warning")}
); diff --git a/frontend/app/element/modal.tsx b/frontend/app/element/modal.tsx index 4655dc2afc..b93e1154f9 100644 --- a/frontend/app/element/modal.tsx +++ b/frontend/app/element/modal.tsx @@ -3,6 +3,7 @@ import { Button } from "@/element/button"; import React from "react"; +import { useTranslation } from "react-i18next"; import "./modal.scss"; @@ -68,13 +69,14 @@ interface WaveModalProps { children: React.ReactNode; } -function WaveModal({ title, description, onSubmit, onCancel, buttonLabel = "Ok", children }: WaveModalProps) { +function WaveModal({ title, description, onSubmit, onCancel, buttonLabel, children }: WaveModalProps) { + const { t } = useTranslation(); return ( {children} - + ); diff --git a/frontend/app/modals/conntypeahead.tsx b/frontend/app/modals/conntypeahead.tsx index 95cf831e24..e90646af98 100644 --- a/frontend/app/modals/conntypeahead.tsx +++ b/frontend/app/modals/conntypeahead.tsx @@ -20,6 +20,8 @@ import * as keyutil from "@/util/keyutil"; import * as util from "@/util/util"; import * as jotai from "jotai"; import * as React from "react"; +import { useTranslation } from "react-i18next"; +import type { TFunction } from "i18next"; // newConnList -> connList => filteredList -> remoteItems -> sortedRemoteItems => remoteSuggestion // filteredList -> createNew @@ -114,6 +116,7 @@ function createFilteredLocalSuggestionItem( } function getReconnectItem( + t: TFunction, connStatus: ConnStatus, connSelected: string, blockId: string, @@ -126,7 +129,7 @@ function getReconnectItem( status: "connected", icon: "arrow-right-arrow-left", iconColor: "var(--grey-text-color)", - label: `Reconnect to ${connStatus.connection}`, + label: t("connTypeahead.reconnectTo", { connection: connStatus.connection }), value: "", onSelect: async (_: string) => { globalStore.set(changeConnModalAtom, false); @@ -142,6 +145,7 @@ function getReconnectItem( } function getLocalSuggestions( + t: TFunction, localName: string, connList: Array, connection: string, @@ -173,13 +177,14 @@ function getLocalSuggestions( return null; } const localSuggestions: SuggestionConnectionScope = { - headerText: "Local", + headerText: t("connTypeahead.local"), items: sortedSuggestionItems, }; return localSuggestions; } function getRemoteSuggestions( + t: TFunction, connList: Array, connection: string, connSelected: string, @@ -194,13 +199,14 @@ function getRemoteSuggestions( return null; } const remoteSuggestions: SuggestionConnectionScope = { - headerText: "Remote", + headerText: t("connTypeahead.remote"), items: sortedSuggestionItems, }; return remoteSuggestions; } function getDisconnectItem( + t: TFunction, connection: string, connStatusMap: Map, changeConnModalAtom: jotai.PrimitiveAtom @@ -216,7 +222,7 @@ function getDisconnectItem( status: "connected", icon: "xmark", iconColor: "var(--grey-text-color)", - label: `Disconnect ${connStatus.connection}`, + label: t("connTypeahead.disconnect", { connection: connStatus.connection }), value: "", onSelect: async (_: string) => { globalStore.set(changeConnModalAtom, false); @@ -228,6 +234,7 @@ function getDisconnectItem( } function getConnectionsEditItem( + t: TFunction, changeConnModalAtom: jotai.PrimitiveAtom, connSelected: string ): SuggestionConnectionItem | null { @@ -239,7 +246,7 @@ function getConnectionsEditItem( icon: "gear", iconColor: "var(--grey-text-color)", value: "Edit Connections", - label: "Edit Connections", + label: t("connTypeahead.editConnections"), onSelect: () => { util.fireAndForget(async () => { globalStore.set(changeConnModalAtom, false); @@ -257,6 +264,7 @@ function getConnectionsEditItem( } function getNewConnectionSuggestionItem( + t: TFunction, connSelected: string, localName: string, remoteConns: Array, @@ -274,7 +282,7 @@ function getNewConnectionSuggestionItem( status: "connected", icon: "plus", iconColor: "var(--grey-text-color)", - label: `${connSelected} (New Connection)`, + label: t("connTypeahead.newConnection", { connection: connSelected }), value: "", onSelect: (_: string) => { changeConnection(connSelected); @@ -300,6 +308,7 @@ const ChangeConnectionBlockModal = React.memo( changeConnModalAtom: jotai.PrimitiveAtom; nodeModel: NodeModel; }) => { + const { t } = useTranslation(); const [connSelected, setConnSelected] = React.useState(""); const changeConnModalOpen = jotai.useAtomValue(changeConnModalAtom); const [blockData] = WOS.useWaveObjectValue(WOS.makeORef("block", blockId)); @@ -375,8 +384,9 @@ const ChangeConnectionBlockModal = React.memo( [blockId, blockData] ); - const reconnectSuggestionItem = getReconnectItem(connStatus, connSelected, blockId, changeConnModalAtom); + const reconnectSuggestionItem = getReconnectItem(t, connStatus, connSelected, blockId, changeConnModalAtom); const localSuggestions = getLocalSuggestions( + t, localName, wslList, connection, @@ -387,6 +397,7 @@ const ChangeConnectionBlockModal = React.memo( hasGitBash ); const remoteSuggestions = getRemoteSuggestions( + t, connList, connection, connSelected, @@ -394,9 +405,10 @@ const ChangeConnectionBlockModal = React.memo( fullConfig, filterOutNowsh ); - const connectionsEditItem = getConnectionsEditItem(changeConnModalAtom, connSelected); - const disconnectItem = getDisconnectItem(connection, connStatusMap, changeConnModalAtom); + const connectionsEditItem = getConnectionsEditItem(t, changeConnModalAtom, connSelected); + const disconnectItem = getDisconnectItem(t, connection, connStatusMap, changeConnModalAtom); const newConnectionSuggestionItem = getNewConnectionSuggestionItem( + t, connSelected, localName, connList, @@ -486,7 +498,7 @@ const ChangeConnectionBlockModal = React.memo( onKeyDown={(e) => keyutil.keydownWrapper(handleTypeAheadKeyDown)(e)} onChange={(current: string) => setConnSelected(current)} value={connSelected} - label="Connect to (username@host)..." + label={t("connTypeahead.connectPlaceholder")} onClickBackdrop={() => globalStore.set(changeConnModalAtom, false)} /> ); diff --git a/frontend/app/modals/modal.tsx b/frontend/app/modals/modal.tsx index 5733ec2608..06b8a1a7e7 100644 --- a/frontend/app/modals/modal.tsx +++ b/frontend/app/modals/modal.tsx @@ -6,6 +6,7 @@ import { cn } from "@/util/util"; import clsx from "clsx"; import { forwardRef } from "react"; import ReactDOM from "react-dom"; +import { useTranslation } from "react-i18next"; import "./modal.scss"; @@ -38,6 +39,7 @@ const Modal = forwardRef( }: ModalProps, ref ) => { + const { t } = useTranslation(); const renderBackdrop = (onClick) =>
; const renderFooter = () => { @@ -48,7 +50,7 @@ const Modal = forwardRef(
{renderBackdrop(onClickBackdrop)}
-
@@ -89,24 +91,18 @@ interface ModalFooterProps { cancelDisabled?: boolean; } -const ModalFooter = ({ - onCancel, - onOk, - cancelLabel = "Cancel", - okLabel = "Ok", - okDisabled, - cancelDisabled, -}: ModalFooterProps) => { +const ModalFooter = ({ onCancel, onOk, cancelLabel, okLabel, okDisabled, cancelDisabled }: ModalFooterProps) => { + const { t } = useTranslation(); return (
{onCancel && ( )} {onOk && ( )}
diff --git a/frontend/app/onboarding/onboarding-upgrade-minor.tsx b/frontend/app/onboarding/onboarding-upgrade-minor.tsx index b165c0ce7f..db25fac7d3 100644 --- a/frontend/app/onboarding/onboarding-upgrade-minor.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-minor.tsx @@ -15,6 +15,7 @@ import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; import { debounce } from "throttle-debounce"; type UpgradeMinorWelcomePageProps = { @@ -24,13 +25,16 @@ type UpgradeMinorWelcomePageProps = { }; const UpgradeMinorWelcomePage = ({ onStarClick, onAlreadyStarred, onMaybeLater }: UpgradeMinorWelcomePageProps) => { + const { t } = useTranslation(); return (
-
Welcome to Wave v0.14!
+
+ {t("onboardingUpgrade.minor.welcomeTitle")} +
- Durable SSH Sessions + + {t("onboardingUpgrade.minor.durableSshBadge")} +
+

{t("onboardingUpgrade.minor.waveAiIntro")}

- Wave AI is your terminal assistant with full context. It can read your terminal output, - analyze widgets, read and write files, and help you solve problems faster. -

-

- New in v0.13: Wave AI now - supports local models and bring-your-own-key! Use Ollama, LM Studio, vLLM, OpenRouter, - or any OpenAI-compatible provider. + + {t("onboardingUpgrade.minor.newInV013Label")} + {" "} + {t("onboardingUpgrade.minor.newInV013Body")}

- New in v0.14: Durable SSH - sessions survive network drops, laptop sleep, and restarts — all without tmux or screen. + + {t("onboardingUpgrade.minor.newInV014Label")} + {" "} + {t("onboardingUpgrade.minor.newInV014Body")}

@@ -68,10 +74,9 @@ const UpgradeMinorWelcomePage = ({ onStarClick, onAlreadyStarred, onMaybeLater }
-
Thanks for being an early Wave adopter! ⭐
+
{t("onboardingUpgrade.minor.thanksAdopter")}
- A GitHub star shows your support for Wave (and open-source) and helps us reach more - developers. + {t("onboardingUpgrade.minor.githubStarHint")}
@@ -79,13 +84,13 @@ const UpgradeMinorWelcomePage = ({ onStarClick, onAlreadyStarred, onMaybeLater }
diff --git a/frontend/app/onboarding/onboarding-upgrade-patch.tsx b/frontend/app/onboarding/onboarding-upgrade-patch.tsx index 87ffadb1e4..b6e8f3349c 100644 --- a/frontend/app/onboarding/onboarding-upgrade-patch.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-patch.tsx @@ -16,6 +16,7 @@ import { TabRpcClient } from "@/app/store/wshrpcutil"; import { useAtomValue } from "jotai"; import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; import { debounce } from "throttle-debounce"; import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v0121"; import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122"; @@ -31,8 +32,6 @@ import { UpgradeOnboardingModal_v0_14_5_Content } from "./onboarding-upgrade-v01 interface VersionConfig { version: string; content: () => React.ReactNode; - prevText?: string; - nextText?: string; } interface UpgradeOnboardingPatchProps { @@ -58,6 +57,7 @@ export function UpgradeOnboardingFooter({ onNext, onClose, }: UpgradeOnboardingFooterProps) { + const { t } = useTranslation(); return (
@@ -75,7 +75,7 @@ export function UpgradeOnboardingFooter({
@@ -96,67 +96,20 @@ export function UpgradeOnboardingFooter({ } export const UpgradeOnboardingVersions: VersionConfig[] = [ - { - version: "v0.12.1", - content: () => , - nextText: "Next (v0.12.2)", - }, - { - version: "v0.12.2", - content: () => , - prevText: "Prev (v0.12.1)", - nextText: "Next (v0.12.3)", - }, - { - version: "v0.12.5", - content: () => , - prevText: "Prev (v0.12.2)", - nextText: "Next (v0.13.0)", - }, - { - version: "v0.13.0", - content: () => , - prevText: "Prev (v0.12.5)", - nextText: "Next (v0.13.1)", - }, - { - version: "v0.13.1", - content: () => , - prevText: "Prev (v0.13.0)", - nextText: "Next (v0.14.0)", - }, - { - version: "v0.14.0", - content: () => , - prevText: "Prev (v0.13.1)", - nextText: "Next (v0.14.1)", - }, - { - version: "v0.14.1", - content: () => , - prevText: "Prev (v0.14.0)", - nextText: "Next (v0.14.3)", - }, - { - version: "v0.14.3", - content: () => , - prevText: "Prev (v0.14.1)", - nextText: "Next (v0.14.4)", - }, - { - version: "v0.14.4", - content: () => , - prevText: "Prev (v0.14.3)", - nextText: "Next (v0.14.5)", - }, - { - version: "v0.14.5", - content: () => , - prevText: "Prev (v0.14.4)", - }, + { version: "v0.12.1", content: () => }, + { version: "v0.12.2", content: () => }, + { version: "v0.12.5", content: () => }, + { version: "v0.13.0", content: () => }, + { version: "v0.13.1", content: () => }, + { version: "v0.14.0", content: () => }, + { version: "v0.14.1", content: () => }, + { version: "v0.14.3", content: () => }, + { version: "v0.14.4", content: () => }, + { version: "v0.14.5", content: () => }, ]; const UpgradeOnboardingPatch = ({ isReleaseNotes = false }: UpgradeOnboardingPatchProps) => { + const { t } = useTranslation(); const modalRef = useRef(null); const [isCompact, setIsCompact] = useState(window.innerHeight < 800); const [currentIndex, setCurrentIndex] = useState(UpgradeOnboardingVersions.length - 1); @@ -264,7 +217,7 @@ const UpgradeOnboardingPatch = ({ isReleaseNotes = false }: UpgradeOnboardingPat
- Wave {currentVersion.version} Update + {t("onboardingUpgrade.patch.updateTitle", { version: currentVersion.version })}
{ + const { t } = useTranslation(); return (
-

- Patch release focused on shell integration improvements, Wave AI enhancements, and restoring syntax - highlighting in code editor blocks. -

+

{t("onboardingUpgrade.v0121.intro")}

@@ -17,17 +17,17 @@ const UpgradeOnboardingModal_v0_12_1_Content = () => {
- Shell Integration & Context + {t("onboardingUpgrade.v0121.shellSectionTitle")}
  • - OSC 7 Support - Wave now automatically tracks and restores your current - directory across restarts for bash, zsh, fish, and pwsh shells + {t("onboardingUpgrade.v0121.osc7Label")} -{" "} + {t("onboardingUpgrade.v0121.osc7Body")}
  • - Shell Context Tracking - Tracks when your shell is ready, last command - executed, and exit codes for better terminal management + {t("onboardingUpgrade.v0121.shellContextLabel")} -{" "} + {t("onboardingUpgrade.v0121.shellContextBody")}
@@ -40,17 +40,14 @@ const UpgradeOnboardingModal_v0_12_1_Content = () => {
- Wave AI Improvements + {t("onboardingUpgrade.v0121.aiSectionTitle")}
    -
  • Display reasoning summaries while waiting for AI responses
  • -
  • - Enhanced terminal context - AI now has access to shell state, current directory, command - history, and exit codes -
  • -
  • Added feedback buttons (thumbs up/down) for AI responses
  • -
  • Added copy button to easily copy AI responses to clipboard
  • +
  • {t("onboardingUpgrade.v0121.aiItem1")}
  • +
  • {t("onboardingUpgrade.v0121.aiItem2")}
  • +
  • {t("onboardingUpgrade.v0121.aiItem3")}
  • +
  • {t("onboardingUpgrade.v0121.aiItem4")}
@@ -61,12 +58,14 @@ const UpgradeOnboardingModal_v0_12_1_Content = () => {
-
Other Changes
+
+ {t("onboardingUpgrade.v0121.otherSectionTitle")} +
    -
  • Mobile user agent emulation support for web widgets
  • -
  • Fixed padding for header buttons in code editor
  • -
  • Restored syntax highlighting in code editor preview blocks
  • +
  • {t("onboardingUpgrade.v0121.otherItem1")}
  • +
  • {t("onboardingUpgrade.v0121.otherItem2")}
  • +
  • {t("onboardingUpgrade.v0121.otherItem3")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0122.tsx b/frontend/app/onboarding/onboarding-upgrade-v0122.tsx index 723672a357..0a4ba2932e 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0122.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0122.tsx @@ -1,14 +1,14 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_12_2_Content = () => { + const { t } = useTranslation(); return (
-

- Wave AI can now create and modify files with visual diff previews and easy rollback capabilities. - Plus performance improvements and bug fixes. -

+

{t("onboardingUpgrade.v0122.intro")}

@@ -16,19 +16,22 @@ const UpgradeOnboardingModal_v0_12_2_Content = () => {
-
Wave AI File Editing
+
+ {t("onboardingUpgrade.v0122.fileEditingSectionTitle")} +
  • - File Write Tool - Wave AI can now create and modify files with your - approval + {t("onboardingUpgrade.v0122.fileWriteToolLabel")} -{" "} + {t("onboardingUpgrade.v0122.fileWriteToolBody")}
  • - Visual Diff Preview - See exactly what will change before approving - edits + {t("onboardingUpgrade.v0122.diffPreviewLabel")} -{" "} + {t("onboardingUpgrade.v0122.diffPreviewBody")}
  • - Easy Rollback - Revert file changes with a simple "Revert File" button + {t("onboardingUpgrade.v0122.rollbackLabel")} -{" "} + {t("onboardingUpgrade.v0122.rollbackBody")}
@@ -41,16 +44,17 @@ const UpgradeOnboardingModal_v0_12_2_Content = () => {
- Additional AI Improvements + {t("onboardingUpgrade.v0122.aiSectionTitle")}
    -
  • Drag & drop files from preview viewer directly to Wave AI
  • +
  • {t("onboardingUpgrade.v0122.aiItem1")}
  • - Directory listings support in `wsh ai` commands + {t("onboardingUpgrade.v0122.aiItem2Prefix")}{" "} + `wsh ai` {t("onboardingUpgrade.v0122.aiItem2Suffix")}
  • -
  • Adjustable thinking level and max output tokens per chat
  • -
  • Improved tool descriptions and input validations
  • +
  • {t("onboardingUpgrade.v0122.aiItem3")}
  • +
  • {t("onboardingUpgrade.v0122.aiItem4")}
@@ -62,13 +66,13 @@ const UpgradeOnboardingModal_v0_12_2_Content = () => {
- Bug Fixes & Improvements + {t("onboardingUpgrade.v0122.bugFixesSectionTitle")}
    -
  • Fixed significant memory leak in the RPC system
  • -
  • Config file schema validation restored
  • -
  • Fixed PowerShell 5.x regression
  • +
  • {t("onboardingUpgrade.v0122.bugFixItem1")}
  • +
  • {t("onboardingUpgrade.v0122.bugFixItem2")}
  • +
  • {t("onboardingUpgrade.v0122.bugFixItem3")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0123.tsx b/frontend/app/onboarding/onboarding-upgrade-v0123.tsx index 6999fccef4..85695c7fc6 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0123.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0123.tsx @@ -1,14 +1,14 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_12_3_Content = () => { + const { t } = useTranslation(); return (
-

- Wave AI model upgrade to GPT-5.1, new secret management features, and improved terminal input - handling for interactive CLI tools. -

+

{t("onboardingUpgrade.v0123.intro")}

@@ -16,18 +16,20 @@ const UpgradeOnboardingModal_v0_12_3_Content = () => {
-
Wave AI Updates
+
+ {t("onboardingUpgrade.v0123.aiSectionTitle")} +
  • - GPT-5.1 Model - Upgraded to OpenAI's GPT-5.1 model for improved - responses + {t("onboardingUpgrade.v0123.gpt51Label")} -{" "} + {t("onboardingUpgrade.v0123.gpt51Body")}
  • - Thinking Mode Toggle - New dropdown to select between Quick, Balanced, - and Deep thinking modes + {t("onboardingUpgrade.v0123.thinkingModeLabel")} -{" "} + {t("onboardingUpgrade.v0123.thinkingModeBody")}
  • -
  • Fixed path mismatch issue when restoring AI write file backups
  • +
  • {t("onboardingUpgrade.v0123.aiItem3")}
@@ -38,18 +40,21 @@ const UpgradeOnboardingModal_v0_12_3_Content = () => {
-
Terminal Improvements
+
+ {t("onboardingUpgrade.v0123.terminalSectionTitle")} +
  • - Enhanced Input Handling - Better support for CLI tools like Claude Code + {t("onboardingUpgrade.v0123.inputHandlingLabel")} -{" "} + {t("onboardingUpgrade.v0123.inputHandlingBody")}
  • - Image Paste Support - Paste images directly into terminal (saved to - temp files) + {t("onboardingUpgrade.v0123.imagePasteLabel")} -{" "} + {t("onboardingUpgrade.v0123.imagePasteBody")}
  • -
  • Shift+Enter now inserts newlines by default for multi-line commands
  • -
  • Fixed duplicate text issue when switching input methods (IME)
  • +
  • {t("onboardingUpgrade.v0123.terminalItem3")}
  • +
  • {t("onboardingUpgrade.v0123.terminalItem4")}
@@ -60,16 +65,19 @@ const UpgradeOnboardingModal_v0_12_3_Content = () => {
-
Secret Store
+
+ {t("onboardingUpgrade.v0123.secretStoreSectionTitle")} +
  • - Secret Management Widget - Store and manage sensitive credentials - securely + {t("onboardingUpgrade.v0123.secretWidgetLabel")} -{" "} + {t("onboardingUpgrade.v0123.secretWidgetBody")}
  • - Access secrets via CLI with wsh secret list/get/set{" "} - commands + {t("onboardingUpgrade.v0123.secretCliPrefix")}{" "} + wsh secret list/get/set{" "} + {t("onboardingUpgrade.v0123.secretCliSuffix")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0130.tsx b/frontend/app/onboarding/onboarding-upgrade-v0130.tsx index 57ce06403e..ff7995dd4d 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0130.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0130.tsx @@ -1,14 +1,14 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_13_0_Content = () => { + const { t } = useTranslation(); return (
-

- Wave v0.13 brings local AI support, bring-your-own-key (BYOK), a redesigned configuration system, - and improved terminal functionality. -

+

{t("onboardingUpgrade.v0130.intro")}

@@ -16,22 +16,26 @@ const UpgradeOnboardingModal_v0_13_0_Content = () => {
-
Local AI & BYOK
+
+ {t("onboardingUpgrade.v0130.localAiSectionTitle")} +
  • - OpenAI-Compatible API - Connect to Ollama, LM Studio, vLLM, OpenRouter, - and other local or hosted models + {t("onboardingUpgrade.v0130.openaiCompatLabel")} -{" "} + {t("onboardingUpgrade.v0130.openaiCompatBody")}
  • - Google Gemini - Native support for Gemini models + {t("onboardingUpgrade.v0130.geminiLabel")} -{" "} + {t("onboardingUpgrade.v0130.geminiBody")}
  • - Provider Presets - Built-in configs for OpenAI, OpenRouter, Google, - Azure, and custom endpoints + {t("onboardingUpgrade.v0130.presetsLabel")} -{" "} + {t("onboardingUpgrade.v0130.presetsBody")}
  • - Multiple AI Modes - Easily switch between models and providers + {t("onboardingUpgrade.v0130.multiModeLabel")} -{" "} + {t("onboardingUpgrade.v0130.multiModeBody")}
@@ -43,19 +47,22 @@ const UpgradeOnboardingModal_v0_13_0_Content = () => {
-
Configuration Widget
+
+ {t("onboardingUpgrade.v0130.configSectionTitle")} +
  • - New Config Interface - Dedicated widget accessible from the sidebar + {t("onboardingUpgrade.v0130.newConfigLabel")} -{" "} + {t("onboardingUpgrade.v0130.newConfigBody")}
  • - Better Organization - Browse and edit settings with improved validation - and error handling + {t("onboardingUpgrade.v0130.betterOrgLabel")} -{" "} + {t("onboardingUpgrade.v0130.betterOrgBody")}
  • - Integrated Secrets - Manage API keys and credentials from the config - widget + {t("onboardingUpgrade.v0130.integratedSecretsLabel")} -{" "} + {t("onboardingUpgrade.v0130.integratedSecretsBody")}
@@ -67,18 +74,22 @@ const UpgradeOnboardingModal_v0_13_0_Content = () => {
-
Terminal Updates
+
+ {t("onboardingUpgrade.v0130.terminalSectionTitle")} +
  • - Bracketed Paste Mode - Enabled by default for better multi-line paste - behavior + {t("onboardingUpgrade.v0130.bracketedPasteLabel")} -{" "} + {t("onboardingUpgrade.v0130.bracketedPasteBody")}
  • - Windows Paste Fix - Ctrl+V now works as standard paste on Windows + {t("onboardingUpgrade.v0130.windowsPasteLabel")} -{" "} + {t("onboardingUpgrade.v0130.windowsPasteBody")}
  • - SSH Password Storage - Store SSH passwords in Wave's secret store + {t("onboardingUpgrade.v0130.sshPasswordLabel")} -{" "} + {t("onboardingUpgrade.v0130.sshPasswordBody")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0131.tsx b/frontend/app/onboarding/onboarding-upgrade-v0131.tsx index 7584607384..a14ae66950 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0131.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0131.tsx @@ -1,14 +1,14 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_13_1_Content = () => { + const { t } = useTranslation(); return (
-

- Wave v0.13.1 focuses on Windows platform improvements, Wave AI visual updates, and enhanced - terminal navigation. -

+

{t("onboardingUpgrade.v0131.intro")}

@@ -17,23 +17,25 @@ const UpgradeOnboardingModal_v0_13_1_Content = () => {
- Windows Platform Enhancements + {t("onboardingUpgrade.v0131.windowsSectionTitle")}
  • - Integrated Window Layout - Cleaner interface with controls integrated - into the tab-bar header + {t("onboardingUpgrade.v0131.integratedLayoutLabel")} -{" "} + {t("onboardingUpgrade.v0131.integratedLayoutBody")}
  • - Git Bash Auto-Detection - Automatically detects Git Bash installations + {t("onboardingUpgrade.v0131.gitBashLabel")} -{" "} + {t("onboardingUpgrade.v0131.gitBashBody")}
  • - SSH Agent Fallback - Improved SSH agent support on Windows + {t("onboardingUpgrade.v0131.sshAgentLabel")} -{" "} + {t("onboardingUpgrade.v0131.sshAgentBody")}
  • - Updated Focus Keybinding - Wave AI focus key changed to Alt:0 on - Windows + {t("onboardingUpgrade.v0131.focusKeybindingLabel")} -{" "} + {t("onboardingUpgrade.v0131.focusKeybindingBody")}
@@ -45,16 +47,18 @@ const UpgradeOnboardingModal_v0_13_1_Content = () => {
-
Wave AI Updates
+
+ {t("onboardingUpgrade.v0131.aiSectionTitle")} +
  • - Refreshed Visual Design - Complete UI refresh with transparency - support for custom backgrounds + {t("onboardingUpgrade.v0131.visualDesignLabel")} -{" "} + {t("onboardingUpgrade.v0131.visualDesignBody")}
  • - BYOK Without Telemetry - Wave AI now works with bring-your-own-key and - local models without requiring telemetry + {t("onboardingUpgrade.v0131.byokLabel")} -{" "} + {t("onboardingUpgrade.v0131.byokBody")}
@@ -66,12 +70,14 @@ const UpgradeOnboardingModal_v0_13_1_Content = () => {
-
Terminal Improvements
+
+ {t("onboardingUpgrade.v0131.terminalSectionTitle")} +
  • - New Scrolling Keybindings - Added Shift+Home, Shift+End, - Shift+PageUp, and Shift+PageDown for better navigation + {t("onboardingUpgrade.v0131.scrollingKeybindingsLabel")} -{" "} + {t("onboardingUpgrade.v0131.scrollingKeybindingsBody")}
@@ -83,4 +89,4 @@ const UpgradeOnboardingModal_v0_13_1_Content = () => { UpgradeOnboardingModal_v0_13_1_Content.displayName = "UpgradeOnboardingModal_v0_13_1_Content"; -export { UpgradeOnboardingModal_v0_13_1_Content }; \ No newline at end of file +export { UpgradeOnboardingModal_v0_13_1_Content }; diff --git a/frontend/app/onboarding/onboarding-upgrade-v0140.tsx b/frontend/app/onboarding/onboarding-upgrade-v0140.tsx index 0102b691e2..5994fb5484 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0140.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0140.tsx @@ -2,17 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 import { useWaveEnv } from "@/app/waveenv/waveenv"; +import { useTranslation } from "react-i18next"; const UpgradeOnboardingModal_v0_14_0_Content = () => { const waveEnv = useWaveEnv(); + const { t } = useTranslation(); return (
-

- Wave v0.14 introduces Durable Sessions. Enable them to keep your remote sessions alive through - network interruptions, computer sleep, and restarts — they'll automatically reconnect when your - connection is restored. -

+

{t("onboardingUpgrade.v0140.intro")}

@@ -21,25 +19,27 @@ const UpgradeOnboardingModal_v0_14_0_Content = () => {
- Durable SSH Sessions{" "} + {t("onboardingUpgrade.v0140.durableSectionTitle")}{" "}
  • - Session Protection - Programs and shell state survive disconnects + {t("onboardingUpgrade.v0140.sessionProtectionLabel")} -{" "} + {t("onboardingUpgrade.v0140.sessionProtectionBody")}
  • - Visual Status Indicators - Shield icons show status + {t("onboardingUpgrade.v0140.visualStatusLabel")} -{" "} + {t("onboardingUpgrade.v0140.visualStatusBody")}
  • - Flexible Configuration - Enable globally, per-connection, or - per-terminal + {t("onboardingUpgrade.v0140.flexibleConfigLabel")} -{" "} + {t("onboardingUpgrade.v0140.flexibleConfigBody")}
@@ -52,15 +52,17 @@ const UpgradeOnboardingModal_v0_14_0_Content = () => {
- Enhanced Connection Monitoring + {t("onboardingUpgrade.v0140.connectionMonitoringSectionTitle")}
  • - Connection Keepalives - Active monitoring with keepalive probes + {t("onboardingUpgrade.v0140.keepalivesLabel")} -{" "} + {t("onboardingUpgrade.v0140.keepalivesBody")}
  • - Stalled Connection Detection - Visual feedback for network issues + {t("onboardingUpgrade.v0140.stalledDetectionLabel")} -{" "} + {t("onboardingUpgrade.v0140.stalledDetectionBody")}
@@ -72,17 +74,21 @@ const UpgradeOnboardingModal_v0_14_0_Content = () => {
-
Wave AI Updates
+
+ {t("onboardingUpgrade.v0140.aiSectionTitle")} +
  • - Image Support - Vision capabilities for BYOK providers + {t("onboardingUpgrade.v0140.imageSupportLabel")} -{" "} + {t("onboardingUpgrade.v0140.imageSupportBody")}
  • - Stop Generation - Ability to stop AI responses mid-generation + {t("onboardingUpgrade.v0140.stopGenerationLabel")} -{" "} + {t("onboardingUpgrade.v0140.stopGenerationBody")}
  • - Improved Auto-scrolling + {t("onboardingUpgrade.v0140.autoScrollLabel")}
@@ -94,14 +100,18 @@ const UpgradeOnboardingModal_v0_14_0_Content = () => {
-
Terminal Improvements
+
+ {t("onboardingUpgrade.v0140.terminalSectionTitle")} +
  • - Enhanced Context Menu - Quick access to splits, themes, and more + {t("onboardingUpgrade.v0140.contextMenuLabel")} -{" "} + {t("onboardingUpgrade.v0140.contextMenuBody")}
  • - OSC 52 Clipboard Support - CLI apps can copy to system clipboard + {t("onboardingUpgrade.v0140.osc52Label")} -{" "} + {t("onboardingUpgrade.v0140.osc52Body")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0141.tsx b/frontend/app/onboarding/onboarding-upgrade-v0141.tsx index 82b0b34aef..196e669972 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0141.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0141.tsx @@ -1,14 +1,14 @@ // Copyright 2026, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_14_1_Content = () => { + const { t } = useTranslation(); return (
-

- Wave v0.14.1 fixes several high-impact terminal bugs and adds new config options for focus, cursor - style, and block navigation. -

+

{t("onboardingUpgrade.v0141.intro")}

@@ -16,21 +16,27 @@ const UpgradeOnboardingModal_v0_14_1_Content = () => {
-
Terminal Fixes
+
+ {t("onboardingUpgrade.v0141.terminalFixesSectionTitle")} +
  • - Claude Code Scroll Fix - Fixed unexpected terminal scroll jumps + {t("onboardingUpgrade.v0141.scrollFixLabel")} -{" "} + {t("onboardingUpgrade.v0141.scrollFixBody")}
  • - IME Fix - Fixed Korean/CJK input losing or sticking characters + {t("onboardingUpgrade.v0141.imeFixLabel")} -{" "} + {t("onboardingUpgrade.v0141.imeFixBody")}
  • - Scroll Position on Resize - Terminal stays at bottom across resizes + {t("onboardingUpgrade.v0141.scrollResizeLabel")} -{" "} + {t("onboardingUpgrade.v0141.scrollResizeBody")}
  • - Terminal Scrollback Save - New context menu item and{" "} - wsh command to save scrollback to a file + {t("onboardingUpgrade.v0141.scrollbackSaveLabel")} -{" "} + {t("onboardingUpgrade.v0141.scrollbackSaveBodyPrefix")} wsh{" "} + {t("onboardingUpgrade.v0141.scrollbackSaveBodySuffix")}
@@ -42,22 +48,28 @@ const UpgradeOnboardingModal_v0_14_1_Content = () => {
-
New Config Options
+
+ {t("onboardingUpgrade.v0141.newConfigSectionTitle")} +
  • - Focus Follows Cursor - New app:focusfollowscursor setting - (off/on/term) + {t("onboardingUpgrade.v0141.focusFollowsCursorLabel")} -{" "} + {t("onboardingUpgrade.v0141.focusFollowsCursorBodyPrefix")}{" "} + app:focusfollowscursor{" "} + {t("onboardingUpgrade.v0141.focusFollowsCursorBodySuffix")}
  • - Terminal Cursor Style & Blink - Configure cursor shape and blink - per-block + {t("onboardingUpgrade.v0141.cursorStyleLabel")} -{" "} + {t("onboardingUpgrade.v0141.cursorStyleBody")}
  • - Vim-Style Block Navigation - Ctrl+Shift+H/J/K/L to navigate blocks + {t("onboardingUpgrade.v0141.vimNavLabel")} -{" "} + {t("onboardingUpgrade.v0141.vimNavBody")}
  • - New AI Providers - Added Groq and NanoGPT as built-in presets + {t("onboardingUpgrade.v0141.newProvidersLabel")} -{" "} + {t("onboardingUpgrade.v0141.newProvidersBody")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0142.tsx b/frontend/app/onboarding/onboarding-upgrade-v0142.tsx index 2fb8c1bd82..2886dba88c 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0142.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0142.tsx @@ -2,17 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 import { useWaveEnv } from "@/app/waveenv/waveenv"; +import { useTranslation } from "react-i18next"; const UpgradeOnboardingModal_v0_14_2_Content = () => { const waveEnv = useWaveEnv(); + const { t } = useTranslation(); return (
-

- Wave v0.14.2 introduces a new block badge system for at-a-glance status, along with directory - preview improvements and bug fixes. v0.14.3 is a patch release fixing a showstopper bug in - onboarding. -

+

{t("onboardingUpgrade.v0142.intro")}

@@ -20,34 +18,38 @@ const UpgradeOnboardingModal_v0_14_2_Content = () => {
-
Block & Tab Badges
+
+ {t("onboardingUpgrade.v0142.badgesSectionTitle")} +
  • - Block Badges Roll Up to Tabs - Blocks can display icon badges (with - color and priority) that are visible in the tab bar for at-a-glance status + {t("onboardingUpgrade.v0142.badgesRollUpLabel")} -{" "} + {t("onboardingUpgrade.v0142.badgesRollUpBody")}
  • - Bell Indicator On by Default - Terminal bell badge now lights up the - block and tab when your terminal rings (controlled by term:bellindicator) + {t("onboardingUpgrade.v0142.bellIndicatorLabel")} -{" "} + {t("onboardingUpgrade.v0142.bellIndicatorBodyPrefix")}{" "} + term:bellindicator + {t("onboardingUpgrade.v0142.bellIndicatorBodySuffix")}
  • wsh badge {" "} - - New command to set or clear badges from the CLI. Supports icons, colors, priorities, - and PID-linked badges + - {t("onboardingUpgrade.v0142.wshBadgeBody")}
  • - Claude Code Integration - Use wsh badge with Claude Code - hooks to surface AI task status as tab bar notifications{" "} + {t("onboardingUpgrade.v0142.claudeIntegrationLabel")} -{" "} + {t("onboardingUpgrade.v0142.claudeIntegrationBodyPrefix")} wsh badge{" "} + {t("onboardingUpgrade.v0142.claudeIntegrationBodySuffix")}{" "}
@@ -60,21 +62,25 @@ const UpgradeOnboardingModal_v0_14_2_Content = () => {
-
Other Changes
+
+ {t("onboardingUpgrade.v0142.otherSectionTitle")} +
  • - [v0.14.3] [bugfix] Fixed a showstopper onboarding bug + {t("onboardingUpgrade.v0142.v0143Tag")} + {t("onboardingUpgrade.v0142.v0143Body")}
  • - Directory Preview - Improved mod time formatting, zebra-striped rows, - better default sort, and YAML file support + {t("onboardingUpgrade.v0142.dirPreviewLabel")} -{" "} + {t("onboardingUpgrade.v0142.dirPreviewBody")}
  • - Search Bar - Clipboard and focus improvements + {t("onboardingUpgrade.v0142.searchBarLabel")} -{" "} + {t("onboardingUpgrade.v0142.searchBarBody")}
  • -
  • [bugfix] Fixed "New Window" hanging on GNOME desktops
  • -
  • [bugfix] Fixed "Save Session As..." focused window tracking bug
  • +
  • {t("onboardingUpgrade.v0142.bugfixNewWindow")}
  • +
  • {t("onboardingUpgrade.v0142.bugfixSaveSession")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0144.tsx b/frontend/app/onboarding/onboarding-upgrade-v0144.tsx index 6fc50f8919..2e19832e44 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0144.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0144.tsx @@ -1,14 +1,14 @@ // Copyright 2026, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_14_4_Content = () => { + const { t } = useTranslation(); return (
-

- Wave v0.14.4 introduces vertical tabs, upgrades to xterm.js v6, and includes bug fixes and UI - improvements. -

+

{t("onboardingUpgrade.v0144.intro")}

@@ -16,13 +16,14 @@ const UpgradeOnboardingModal_v0_14_4_Content = () => {
-
Vertical Tab Bar
+
+ {t("onboardingUpgrade.v0144.verticalTabSectionTitle")} +
  • - New Vertical Tab Bar Option - Tabs can now be displayed vertically - along the side of the window for more horizontal space. Toggle between horizontal and - vertical layouts in settings. + {t("onboardingUpgrade.v0144.verticalTabLabel")} -{" "} + {t("onboardingUpgrade.v0144.verticalTabBody")}
@@ -34,12 +35,14 @@ const UpgradeOnboardingModal_v0_14_4_Content = () => {
-
Terminal Improvements
+
+ {t("onboardingUpgrade.v0144.terminalSectionTitle")} +
  • - xterm.js v6.0.0 Upgrade - Improved terminal compatibility and - rendering, resolving quirks with tools like Claude Code + {t("onboardingUpgrade.v0144.xtermUpgradeLabel")} -{" "} + {t("onboardingUpgrade.v0144.xtermUpgradeBody")}
@@ -51,26 +54,30 @@ const UpgradeOnboardingModal_v0_14_4_Content = () => {
-
Other Changes
+
+ {t("onboardingUpgrade.v0144.otherSectionTitle")} +
  • - macOS First Click - First click now focuses the clicked widget + {t("onboardingUpgrade.v0144.macFirstClickLabel")} -{" "} + {t("onboardingUpgrade.v0144.macFirstClickBody")}
  • backgrounds.json {" "} - - Renamed presets/bg.json to backgrounds.json + - {t("onboardingUpgrade.v0144.renamedPrefix")} presets/bg.json{" "} + {t("onboardingUpgrade.v0144.renamedTo")} backgrounds.json
  • - Config Errors Moved - Config errors to the WaveConfig view for less - clutter + {t("onboardingUpgrade.v0144.configErrorsLabel")} -{" "} + {t("onboardingUpgrade.v0144.configErrorsBody")}
  • -
  • WaveConfig now warns on Unsaved Changes
  • -
  • Preview streaming fixes for images/videos
  • -
  • Deprecated legacy AI widget has been removed
  • -
  • [bugfix] Fixed focus bug for newly created blocks
  • +
  • {t("onboardingUpgrade.v0144.unsavedChangesWarning")}
  • +
  • {t("onboardingUpgrade.v0144.previewStreamingFix")}
  • +
  • {t("onboardingUpgrade.v0144.legacyAiRemoved")}
  • +
  • {t("onboardingUpgrade.v0144.bugfixFocus")}
diff --git a/frontend/app/onboarding/onboarding-upgrade-v0145.tsx b/frontend/app/onboarding/onboarding-upgrade-v0145.tsx index be0b43cf4a..a9aa80b618 100644 --- a/frontend/app/onboarding/onboarding-upgrade-v0145.tsx +++ b/frontend/app/onboarding/onboarding-upgrade-v0145.tsx @@ -1,14 +1,14 @@ // Copyright 2026, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { useTranslation } from "react-i18next"; + const UpgradeOnboardingModal_v0_14_5_Content = () => { + const { t } = useTranslation(); return (
-

- Wave v0.14.5 introduces a new Process Viewer widget, several quality-of-life improvements, and a - fix for creating new config files from the Settings widget. -

+

{t("onboardingUpgrade.v0145.intro")}

@@ -16,11 +16,10 @@ const UpgradeOnboardingModal_v0_14_5_Content = () => {
-
Process Viewer
-
- New widget that displays running processes on local and remote machines, with CPU and memory - usage and sortable columns. +
+ {t("onboardingUpgrade.v0145.processViewerTitle")}
+
{t("onboardingUpgrade.v0145.processViewerBody")}
@@ -29,26 +28,30 @@ const UpgradeOnboardingModal_v0_14_5_Content = () => {
-
Other Changes
+
+ {t("onboardingUpgrade.v0145.otherSectionTitle")} +
  • - Quake Mode — global hotkey ( - app:globalhotkey) now toggles a Wave window visible and invisible + {t("onboardingUpgrade.v0145.quakeModeLabel")} —{" "} + {t("onboardingUpgrade.v0145.quakeModeBodyPrefix")} (app:globalhotkey){" "} + {t("onboardingUpgrade.v0145.quakeModeBodySuffix")}
  • - Drag & Drop Files into Terminal - to paste their quoted path + {t("onboardingUpgrade.v0145.dragDropLabel")}{" "} + {t("onboardingUpgrade.v0145.dragDropBody")}
  • - New app:showsplitbuttons setting adds split buttons to block headers + {t("onboardingUpgrade.v0145.splitButtonsPrefix")}{" "} + app:showsplitbuttons {t("onboardingUpgrade.v0145.splitButtonsSuffix")}
  • -
  • Toggle the widgets sidebar on and off from the View menu
  • -
  • F2 to rename the active tab
  • -
  • Mouse back/forward buttons now navigate in web widgets
  • +
  • {t("onboardingUpgrade.v0145.toggleSidebar")}
  • +
  • {t("onboardingUpgrade.v0145.f2Rename")}
  • +
  • {t("onboardingUpgrade.v0145.mouseNavigation")}
  • - [bugfix] Config files that didn't exist yet couldn't be - created or edited from the Settings widget + {t("onboardingUpgrade.v0145.bugfixTag")}{" "} + {t("onboardingUpgrade.v0145.bugfixConfigFiles")}
diff --git a/frontend/app/onboarding/onboarding.tsx b/frontend/app/onboarding/onboarding.tsx index ba139e81df..71fc4bd750 100644 --- a/frontend/app/onboarding/onboarding.tsx +++ b/frontend/app/onboarding/onboarding.tsx @@ -19,6 +19,7 @@ import { fireAndForget } from "@/util/util"; import { atom, PrimitiveAtom, useAtom, useAtomValue, useSetAtom } from "jotai"; import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; import { debounce } from "throttle-debounce"; // Page flow: @@ -36,6 +37,7 @@ const InitPage = ({ isCompact: boolean; telemetryUpdateFn: (value: boolean) => Promise; }) => { + const { t } = useTranslation(); const telemetrySetting = useSettingsKeyAtom("telemetry:enabled"); const clientData = useAtomValue(ClientModel.getInstance().clientAtom); const [telemetryEnabled, setTelemetryEnabled] = useState(!!telemetrySetting); @@ -75,7 +77,7 @@ const InitPage = ({ ); }; - const label = telemetryEnabled ? "Enabled" : "Disabled"; + const label = telemetryEnabled ? t("onboarding.enabled") : t("onboarding.disabled"); return (
@@ -85,7 +87,9 @@ const InitPage = ({
-
Welcome to Wave Terminal
+
+ {t("onboarding.welcomeTitle")} +
-
Support us on GitHub
+
+ {t("onboarding.supportUsOnGithub")} +
- We're open source, open-model, and committed to providing a free terminal - for individual users. Please show your support by giving us a star on{" "} + {t("onboarding.githubSupportBody")}{" "} - Github (wavetermdev/waveterm) + {t("onboarding.githubLinkText")}
@@ -133,10 +138,11 @@ const InitPage = ({
-
Join our Community
+
+ {t("onboarding.joinCommunity")} +
- Get help, submit feature requests, report bugs, or just chat with fellow terminal - enthusiasts. + {t("onboarding.communityBody")}
- Join the Wave Discord Channel + {t("onboarding.discordLinkText")}
@@ -155,7 +161,7 @@ const InitPage = ({
- Anonymous usage data helps us improve features you use. + {t("onboarding.telemetryHint")}
- Privacy Policy + {t("onboarding.privacyPolicy")}