Browse Source

chore(app): missing i18n strings

adamelmore 1 month ago
parent
commit
97aec21cb3

+ 1 - 1
packages/app/src/components/dialog-settings.tsx

@@ -50,7 +50,7 @@ export const DialogSettings: Component = () => {
               </div>
               </div>
             </div>
             </div>
             <div class="flex flex-col gap-1 pl-1 py-1 text-12-medium text-text-weak">
             <div class="flex flex-col gap-1 pl-1 py-1 text-12-medium text-text-weak">
-              <span>OpenCode Desktop</span>
+              <span>{language.t("app.name.desktop")}</span>
               <span class="text-11-regular">v{platform.version}</span>
               <span class="text-11-regular">v{platform.version}</span>
             </div>
             </div>
           </div>
           </div>

+ 5 - 5
packages/app/src/components/prompt-input.tsx

@@ -1565,7 +1565,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
       const timeoutMs = 5 * 60 * 1000
       const timeoutMs = 5 * 60 * 1000
       const timeout = new Promise<Awaited<ReturnType<typeof WorktreeState.wait>>>((resolve) => {
       const timeout = new Promise<Awaited<ReturnType<typeof WorktreeState.wait>>>((resolve) => {
         setTimeout(() => {
         setTimeout(() => {
-          resolve({ status: "failed", message: "Workspace is still preparing" })
+          resolve({ status: "failed", message: language.t("workspace.error.stillPreparing") })
         }, timeoutMs)
         }, timeoutMs)
       })
       })
 
 
@@ -1863,9 +1863,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
               store.mode === "shell"
               store.mode === "shell"
                 ? language.t("prompt.placeholder.shell")
                 ? language.t("prompt.placeholder.shell")
                 : commentCount() > 1
                 : commentCount() > 1
-                  ? "Summarize comments…"
+                  ? language.t("prompt.placeholder.summarizeComments")
                   : commentCount() === 1
                   : commentCount() === 1
-                    ? "Summarize comment…"
+                    ? language.t("prompt.placeholder.summarizeComment")
                     : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) })
                     : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) })
             }
             }
             contenteditable="true"
             contenteditable="true"
@@ -1887,9 +1887,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
               {store.mode === "shell"
               {store.mode === "shell"
                 ? language.t("prompt.placeholder.shell")
                 ? language.t("prompt.placeholder.shell")
                 : commentCount() > 1
                 : commentCount() > 1
-                  ? "Summarize comments…"
+                  ? language.t("prompt.placeholder.summarizeComments")
                   : commentCount() === 1
                   : commentCount() === 1
-                    ? "Summarize comment…"
+                    ? language.t("prompt.placeholder.summarizeComment")
                     : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) })}
                     : language.t("prompt.placeholder.normal", { example: language.t(EXAMPLES[store.placeholder]) })}
             </div>
             </div>
           </Show>
           </Show>

+ 2 - 2
packages/app/src/components/session/session-header.tsx

@@ -281,7 +281,7 @@ export function SessionHeader() {
                 </TooltipKeybind>
                 </TooltipKeybind>
               </div>
               </div>
               <div class="hidden md:block shrink-0">
               <div class="hidden md:block shrink-0">
-                <Tooltip value="Toggle file tree" placement="bottom">
+                <Tooltip value={language.t("command.fileTree.toggle")} placement="bottom">
                   <Button
                   <Button
                     variant="ghost"
                     variant="ghost"
                     class="group/file-tree-toggle size-5 p-0"
                     class="group/file-tree-toggle size-5 p-0"
@@ -290,7 +290,7 @@ export function SessionHeader() {
                       if (opening && !view().reviewPanel.opened()) view().reviewPanel.open()
                       if (opening && !view().reviewPanel.opened()) view().reviewPanel.open()
                       layout.fileTree.toggle()
                       layout.fileTree.toggle()
                     }}
                     }}
-                    aria-label="Toggle file tree"
+                    aria-label={language.t("command.fileTree.toggle")}
                     aria-expanded={layout.fileTree.opened()}
                     aria-expanded={layout.fileTree.opened()}
                   >
                   >
                     <div class="relative flex items-center justify-center size-4">
                     <div class="relative flex items-center justify-center size-4">

+ 1 - 1
packages/app/src/context/file.tsx

@@ -517,7 +517,7 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
           )
           )
           showToast({
           showToast({
             variant: "error",
             variant: "error",
-            title: "Failed to list files",
+            title: language.t("toast.file.listFailed.title"),
             description: e.message,
             description: e.message,
           })
           })
         })
         })

+ 20 - 0
packages/app/src/i18n/en.ts

@@ -8,6 +8,7 @@ export const dict = {
   "command.category.theme": "Theme",
   "command.category.theme": "Theme",
   "command.category.language": "Language",
   "command.category.language": "Language",
   "command.category.file": "File",
   "command.category.file": "File",
+  "command.category.context": "Context",
   "command.category.terminal": "Terminal",
   "command.category.terminal": "Terminal",
   "command.category.model": "Model",
   "command.category.model": "Model",
   "command.category.mcp": "MCP",
   "command.category.mcp": "MCP",
@@ -42,7 +43,10 @@ export const dict = {
   "command.session.new": "New session",
   "command.session.new": "New session",
   "command.file.open": "Open file",
   "command.file.open": "Open file",
   "command.file.open.description": "Search files and commands",
   "command.file.open.description": "Search files and commands",
+  "command.context.addSelection": "Add selection to context",
+  "command.context.addSelection.description": "Add selected lines from the current file",
   "command.terminal.toggle": "Toggle terminal",
   "command.terminal.toggle": "Toggle terminal",
+  "command.fileTree.toggle": "Toggle file tree",
   "command.review.toggle": "Toggle review",
   "command.review.toggle": "Toggle review",
   "command.terminal.new": "New terminal",
   "command.terminal.new": "New terminal",
   "command.terminal.new.description": "Create a new terminal tab",
   "command.terminal.new.description": "Create a new terminal tab",
@@ -172,6 +176,8 @@ export const dict = {
 
 
   "prompt.placeholder.shell": "Enter shell command...",
   "prompt.placeholder.shell": "Enter shell command...",
   "prompt.placeholder.normal": 'Ask anything... "{{example}}"',
   "prompt.placeholder.normal": 'Ask anything... "{{example}}"',
+  "prompt.placeholder.summarizeComments": "Summarize comments…",
+  "prompt.placeholder.summarizeComment": "Summarize comment…",
   "prompt.mode.shell": "Shell",
   "prompt.mode.shell": "Shell",
   "prompt.mode.shell.exit": "esc to exit",
   "prompt.mode.shell.exit": "esc to exit",
 
 
@@ -342,6 +348,10 @@ export const dict = {
   "toast.model.none.description": "Connect a provider to summarize this session",
   "toast.model.none.description": "Connect a provider to summarize this session",
 
 
   "toast.file.loadFailed.title": "Failed to load file",
   "toast.file.loadFailed.title": "Failed to load file",
+  "toast.file.listFailed.title": "Failed to list files",
+
+  "toast.context.noLineSelection.title": "No line selection",
+  "toast.context.noLineSelection.description": "Select a line range in a file tab first.",
 
 
   "toast.session.share.copyFailed.title": "Failed to copy URL to clipboard",
   "toast.session.share.copyFailed.title": "Failed to copy URL to clipboard",
   "toast.session.share.success.title": "Session shared",
   "toast.session.share.success.title": "Session shared",
@@ -417,8 +427,15 @@ export const dict = {
   "session.tab.context": "Context",
   "session.tab.context": "Context",
   "session.panel.reviewAndFiles": "Review and files",
   "session.panel.reviewAndFiles": "Review and files",
   "session.review.filesChanged": "{{count}} Files Changed",
   "session.review.filesChanged": "{{count}} Files Changed",
+  "session.review.change.one": "Change",
+  "session.review.change.other": "Changes",
   "session.review.loadingChanges": "Loading changes...",
   "session.review.loadingChanges": "Loading changes...",
   "session.review.empty": "No changes in this session yet",
   "session.review.empty": "No changes in this session yet",
+  "session.review.noChanges": "No changes",
+
+  "session.files.selectToOpen": "Select a file to open",
+  "session.files.all": "All files",
+
   "session.messages.renderEarlier": "Render earlier messages",
   "session.messages.renderEarlier": "Render earlier messages",
   "session.messages.loadingEarlier": "Loading earlier messages...",
   "session.messages.loadingEarlier": "Loading earlier messages...",
   "session.messages.loadEarlier": "Load earlier messages",
   "session.messages.loadEarlier": "Load earlier messages",
@@ -495,6 +512,8 @@ export const dict = {
   "sidebar.project.recentSessions": "Recent sessions",
   "sidebar.project.recentSessions": "Recent sessions",
   "sidebar.project.viewAllSessions": "View all sessions",
   "sidebar.project.viewAllSessions": "View all sessions",
 
 
+  "app.name.desktop": "OpenCode Desktop",
+
   "settings.section.desktop": "Desktop",
   "settings.section.desktop": "Desktop",
   "settings.section.server": "Server",
   "settings.section.server": "Server",
   "settings.tab.general": "General",
   "settings.tab.general": "General",
@@ -678,6 +697,7 @@ export const dict = {
   "workspace.reset.failed.title": "Failed to reset workspace",
   "workspace.reset.failed.title": "Failed to reset workspace",
   "workspace.reset.success.title": "Workspace reset",
   "workspace.reset.success.title": "Workspace reset",
   "workspace.reset.success.description": "Workspace now matches the default branch.",
   "workspace.reset.success.description": "Workspace now matches the default branch.",
+  "workspace.error.stillPreparing": "Workspace is still preparing",
   "workspace.status.checking": "Checking for unmerged changes...",
   "workspace.status.checking": "Checking for unmerged changes...",
   "workspace.status.error": "Unable to verify git status.",
   "workspace.status.error": "Unable to verify git status.",
   "workspace.status.clean": "No unmerged changes detected.",
   "workspace.status.clean": "No unmerged changes detected.",

+ 105 - 86
packages/app/src/pages/session.tsx

@@ -586,26 +586,26 @@ export default function Page() {
   command.register(() => [
   command.register(() => [
     {
     {
       id: "session.new",
       id: "session.new",
-      title: "New session",
-      category: "Session",
+      title: language.t("command.session.new"),
+      category: language.t("command.category.session"),
       keybind: "mod+shift+s",
       keybind: "mod+shift+s",
       slash: "new",
       slash: "new",
       onSelect: () => navigate(`/${params.dir}/session`),
       onSelect: () => navigate(`/${params.dir}/session`),
     },
     },
     {
     {
       id: "file.open",
       id: "file.open",
-      title: "Open file",
-      description: "Search files and commands",
-      category: "File",
+      title: language.t("command.file.open"),
+      description: language.t("command.file.open.description"),
+      category: language.t("command.category.file"),
       keybind: "mod+p",
       keybind: "mod+p",
       slash: "open",
       slash: "open",
       onSelect: () => dialog.show(() => <DialogSelectFile />),
       onSelect: () => dialog.show(() => <DialogSelectFile />),
     },
     },
     {
     {
       id: "context.addSelection",
       id: "context.addSelection",
-      title: "Add selection to context",
-      description: "Add selected lines from the current file",
-      category: "Context",
+      title: language.t("command.context.addSelection"),
+      description: language.t("command.context.addSelection.description"),
+      category: language.t("command.category.context"),
       keybind: "mod+shift+l",
       keybind: "mod+shift+l",
       disabled: (() => {
       disabled: (() => {
         const active = tabs().active()
         const active = tabs().active()
@@ -623,8 +623,8 @@ export default function Page() {
         const range = file.selectedLines(path)
         const range = file.selectedLines(path)
         if (!range) {
         if (!range) {
           showToast({
           showToast({
-            title: "No line selection",
-            description: "Select a line range in a file tab first.",
+            title: language.t("toast.context.noLineSelection.title"),
+            description: language.t("toast.context.noLineSelection.description"),
           })
           })
           return
           return
         }
         }
@@ -634,18 +634,18 @@ export default function Page() {
     },
     },
     {
     {
       id: "terminal.toggle",
       id: "terminal.toggle",
-      title: "Toggle terminal",
+      title: language.t("command.terminal.toggle"),
       description: "",
       description: "",
-      category: "View",
+      category: language.t("command.category.view"),
       keybind: "ctrl+`",
       keybind: "ctrl+`",
       slash: "terminal",
       slash: "terminal",
       onSelect: () => view().terminal.toggle(),
       onSelect: () => view().terminal.toggle(),
     },
     },
     {
     {
       id: "review.toggle",
       id: "review.toggle",
-      title: "Toggle review",
+      title: language.t("command.review.toggle"),
       description: "",
       description: "",
-      category: "View",
+      category: language.t("command.category.view"),
       keybind: "mod+shift+r",
       keybind: "mod+shift+r",
       onSelect: () => view().reviewPanel.toggle(),
       onSelect: () => view().reviewPanel.toggle(),
     },
     },
@@ -662,9 +662,9 @@ export default function Page() {
     },
     },
     {
     {
       id: "steps.toggle",
       id: "steps.toggle",
-      title: "Toggle steps",
-      description: "Show or hide steps for the current message",
-      category: "View",
+      title: language.t("command.steps.toggle"),
+      description: language.t("command.steps.toggle.description"),
+      category: language.t("command.category.view"),
       keybind: "mod+e",
       keybind: "mod+e",
       slash: "steps",
       slash: "steps",
       disabled: !params.id,
       disabled: !params.id,
@@ -676,62 +676,62 @@ export default function Page() {
     },
     },
     {
     {
       id: "message.previous",
       id: "message.previous",
-      title: "Previous message",
-      description: "Go to the previous user message",
-      category: "Session",
+      title: language.t("command.message.previous"),
+      description: language.t("command.message.previous.description"),
+      category: language.t("command.category.session"),
       keybind: "mod+arrowup",
       keybind: "mod+arrowup",
       disabled: !params.id,
       disabled: !params.id,
       onSelect: () => navigateMessageByOffset(-1),
       onSelect: () => navigateMessageByOffset(-1),
     },
     },
     {
     {
       id: "message.next",
       id: "message.next",
-      title: "Next message",
-      description: "Go to the next user message",
-      category: "Session",
+      title: language.t("command.message.next"),
+      description: language.t("command.message.next.description"),
+      category: language.t("command.category.session"),
       keybind: "mod+arrowdown",
       keybind: "mod+arrowdown",
       disabled: !params.id,
       disabled: !params.id,
       onSelect: () => navigateMessageByOffset(1),
       onSelect: () => navigateMessageByOffset(1),
     },
     },
     {
     {
       id: "model.choose",
       id: "model.choose",
-      title: "Choose model",
-      description: "Select a different model",
-      category: "Model",
+      title: language.t("command.model.choose"),
+      description: language.t("command.model.choose.description"),
+      category: language.t("command.category.model"),
       keybind: "mod+'",
       keybind: "mod+'",
       slash: "model",
       slash: "model",
       onSelect: () => dialog.show(() => <DialogSelectModel />),
       onSelect: () => dialog.show(() => <DialogSelectModel />),
     },
     },
     {
     {
       id: "mcp.toggle",
       id: "mcp.toggle",
-      title: "Toggle MCPs",
-      description: "Toggle MCPs",
-      category: "MCP",
+      title: language.t("command.mcp.toggle"),
+      description: language.t("command.mcp.toggle.description"),
+      category: language.t("command.category.mcp"),
       keybind: "mod+;",
       keybind: "mod+;",
       slash: "mcp",
       slash: "mcp",
       onSelect: () => dialog.show(() => <DialogSelectMcp />),
       onSelect: () => dialog.show(() => <DialogSelectMcp />),
     },
     },
     {
     {
       id: "agent.cycle",
       id: "agent.cycle",
-      title: "Cycle agent",
-      description: "Switch to the next agent",
-      category: "Agent",
+      title: language.t("command.agent.cycle"),
+      description: language.t("command.agent.cycle.description"),
+      category: language.t("command.category.agent"),
       keybind: "mod+.",
       keybind: "mod+.",
       slash: "agent",
       slash: "agent",
       onSelect: () => local.agent.move(1),
       onSelect: () => local.agent.move(1),
     },
     },
     {
     {
       id: "agent.cycle.reverse",
       id: "agent.cycle.reverse",
-      title: "Cycle agent backwards",
-      description: "Switch to the previous agent",
-      category: "Agent",
+      title: language.t("command.agent.cycle.reverse"),
+      description: language.t("command.agent.cycle.reverse.description"),
+      category: language.t("command.category.agent"),
       keybind: "shift+mod+.",
       keybind: "shift+mod+.",
       onSelect: () => local.agent.move(-1),
       onSelect: () => local.agent.move(-1),
     },
     },
     {
     {
       id: "model.variant.cycle",
       id: "model.variant.cycle",
-      title: "Cycle thinking effort",
-      description: "Switch to the next effort level",
-      category: "Model",
+      title: language.t("command.model.variant.cycle"),
+      description: language.t("command.model.variant.cycle.description"),
+      category: language.t("command.category.model"),
       keybind: "shift+mod+d",
       keybind: "shift+mod+d",
       onSelect: () => {
       onSelect: () => {
         local.model.variant.cycle()
         local.model.variant.cycle()
@@ -741,9 +741,9 @@ export default function Page() {
       id: "permissions.autoaccept",
       id: "permissions.autoaccept",
       title:
       title:
         params.id && permission.isAutoAccepting(params.id, sdk.directory)
         params.id && permission.isAutoAccepting(params.id, sdk.directory)
-          ? "Stop auto-accepting edits"
-          : "Auto-accept edits",
-      category: "Permissions",
+          ? language.t("command.permissions.autoaccept.disable")
+          : language.t("command.permissions.autoaccept.enable"),
+      category: language.t("command.category.permissions"),
       keybind: "mod+shift+a",
       keybind: "mod+shift+a",
       disabled: !params.id || !permission.permissionsEnabled(),
       disabled: !params.id || !permission.permissionsEnabled(),
       onSelect: () => {
       onSelect: () => {
@@ -752,19 +752,19 @@ export default function Page() {
         permission.toggleAutoAccept(sessionID, sdk.directory)
         permission.toggleAutoAccept(sessionID, sdk.directory)
         showToast({
         showToast({
           title: permission.isAutoAccepting(sessionID, sdk.directory)
           title: permission.isAutoAccepting(sessionID, sdk.directory)
-            ? "Auto-accepting edits"
-            : "Stopped auto-accepting edits",
+            ? language.t("toast.permissions.autoaccept.on.title")
+            : language.t("toast.permissions.autoaccept.off.title"),
           description: permission.isAutoAccepting(sessionID, sdk.directory)
           description: permission.isAutoAccepting(sessionID, sdk.directory)
-            ? "Edit and write permissions will be automatically approved"
-            : "Edit and write permissions will require approval",
+            ? language.t("toast.permissions.autoaccept.on.description")
+            : language.t("toast.permissions.autoaccept.off.description"),
         })
         })
       },
       },
     },
     },
     {
     {
       id: "session.undo",
       id: "session.undo",
-      title: "Undo",
-      description: "Undo the last message",
-      category: "Session",
+      title: language.t("command.session.undo"),
+      description: language.t("command.session.undo.description"),
+      category: language.t("command.category.session"),
       slash: "undo",
       slash: "undo",
       disabled: !params.id || visibleUserMessages().length === 0,
       disabled: !params.id || visibleUserMessages().length === 0,
       onSelect: async () => {
       onSelect: async () => {
@@ -791,9 +791,9 @@ export default function Page() {
     },
     },
     {
     {
       id: "session.redo",
       id: "session.redo",
-      title: "Redo",
-      description: "Redo the last undone message",
-      category: "Session",
+      title: language.t("command.session.redo"),
+      description: language.t("command.session.redo.description"),
+      category: language.t("command.category.session"),
       slash: "redo",
       slash: "redo",
       disabled: !params.id || !info()?.revert?.messageID,
       disabled: !params.id || !info()?.revert?.messageID,
       onSelect: async () => {
       onSelect: async () => {
@@ -820,9 +820,9 @@ export default function Page() {
     },
     },
     {
     {
       id: "session.compact",
       id: "session.compact",
-      title: "Compact session",
-      description: "Summarize the session to reduce context size",
-      category: "Session",
+      title: language.t("command.session.compact"),
+      description: language.t("command.session.compact.description"),
+      category: language.t("command.category.session"),
       slash: "compact",
       slash: "compact",
       disabled: !params.id || visibleUserMessages().length === 0,
       disabled: !params.id || visibleUserMessages().length === 0,
       onSelect: async () => {
       onSelect: async () => {
@@ -831,8 +831,8 @@ export default function Page() {
         const model = local.model.current()
         const model = local.model.current()
         if (!model) {
         if (!model) {
           showToast({
           showToast({
-            title: "No model selected",
-            description: "Connect a provider to summarize this session",
+            title: language.t("toast.model.none.title"),
+            description: language.t("toast.model.none.description"),
           })
           })
           return
           return
         }
         }
@@ -845,9 +845,9 @@ export default function Page() {
     },
     },
     {
     {
       id: "session.fork",
       id: "session.fork",
-      title: "Fork from message",
-      description: "Create a new session from a previous message",
-      category: "Session",
+      title: language.t("command.session.fork"),
+      description: language.t("command.session.fork.description"),
+      category: language.t("command.category.session"),
       slash: "fork",
       slash: "fork",
       disabled: !params.id || visibleUserMessages().length === 0,
       disabled: !params.id || visibleUserMessages().length === 0,
       onSelect: () => dialog.show(() => <DialogFork />),
       onSelect: () => dialog.show(() => <DialogFork />),
@@ -856,9 +856,9 @@ export default function Page() {
       ? [
       ? [
           {
           {
             id: "session.share",
             id: "session.share",
-            title: "Share session",
-            description: "Share this session and copy the URL to clipboard",
-            category: "Session",
+            title: language.t("command.session.share"),
+            description: language.t("command.session.share.description"),
+            category: language.t("command.category.session"),
             slash: "share",
             slash: "share",
             disabled: !params.id || !!info()?.share?.url,
             disabled: !params.id || !!info()?.share?.url,
             onSelect: async () => {
             onSelect: async () => {
@@ -868,22 +868,22 @@ export default function Page() {
                 .then((res) => {
                 .then((res) => {
                   navigator.clipboard.writeText(res.data!.share!.url).catch(() =>
                   navigator.clipboard.writeText(res.data!.share!.url).catch(() =>
                     showToast({
                     showToast({
-                      title: "Failed to copy URL to clipboard",
+                      title: language.t("toast.session.share.copyFailed.title"),
                       variant: "error",
                       variant: "error",
                     }),
                     }),
                   )
                   )
                 })
                 })
                 .then(() =>
                 .then(() =>
                   showToast({
                   showToast({
-                    title: "Session shared",
-                    description: "Share URL copied to clipboard!",
+                    title: language.t("toast.session.share.success.title"),
+                    description: language.t("toast.session.share.success.description"),
                     variant: "success",
                     variant: "success",
                   }),
                   }),
                 )
                 )
                 .catch(() =>
                 .catch(() =>
                   showToast({
                   showToast({
-                    title: "Failed to share session",
-                    description: "An error occurred while sharing the session",
+                    title: language.t("toast.session.share.failed.title"),
+                    description: language.t("toast.session.share.failed.description"),
                     variant: "error",
                     variant: "error",
                   }),
                   }),
                 )
                 )
@@ -891,9 +891,9 @@ export default function Page() {
           },
           },
           {
           {
             id: "session.unshare",
             id: "session.unshare",
-            title: "Unshare session",
-            description: "Stop sharing this session",
-            category: "Session",
+            title: language.t("command.session.unshare"),
+            description: language.t("command.session.unshare.description"),
+            category: language.t("command.category.session"),
             slash: "unshare",
             slash: "unshare",
             disabled: !params.id || !info()?.share?.url,
             disabled: !params.id || !info()?.share?.url,
             onSelect: async () => {
             onSelect: async () => {
@@ -902,15 +902,15 @@ export default function Page() {
                 .unshare({ sessionID: params.id })
                 .unshare({ sessionID: params.id })
                 .then(() =>
                 .then(() =>
                   showToast({
                   showToast({
-                    title: "Session unshared",
-                    description: "Session unshared successfully!",
+                    title: language.t("toast.session.unshare.success.title"),
+                    description: language.t("toast.session.unshare.success.description"),
                     variant: "success",
                     variant: "success",
                   }),
                   }),
                 )
                 )
                 .catch(() =>
                 .catch(() =>
                   showToast({
                   showToast({
-                    title: "Failed to unshare session",
-                    description: "An error occurred while unsharing the session",
+                    title: language.t("toast.session.unshare.failed.title"),
+                    description: language.t("toast.session.unshare.failed.description"),
                     variant: "error",
                     variant: "error",
                   }),
                   }),
                 )
                 )
@@ -1759,7 +1759,7 @@ export default function Page() {
                                 class="text-12-medium opacity-50"
                                 class="text-12-medium opacity-50"
                                 onClick={() => setStore("turnStart", 0)}
                                 onClick={() => setStore("turnStart", 0)}
                               >
                               >
-                                Render earlier messages
+                                {language.t("session.messages.renderEarlier")}
                               </Button>
                               </Button>
                             </div>
                             </div>
                           </Show>
                           </Show>
@@ -1777,7 +1777,9 @@ export default function Page() {
                                   sync.session.history.loadMore(id)
                                   sync.session.history.loadMore(id)
                                 }}
                                 }}
                               >
                               >
-                                {historyLoading() ? "Loading earlier messages..." : "Load earlier messages"}
+                                {historyLoading()
+                                  ? language.t("session.messages.loadingEarlier")
+                                  : language.t("session.messages.loadEarlier")}
                               </Button>
                               </Button>
                             </div>
                             </div>
                           </Show>
                           </Show>
@@ -1911,7 +1913,7 @@ export default function Page() {
                 when={prompt.ready()}
                 when={prompt.ready()}
                 fallback={
                 fallback={
                   <div class="w-full min-h-32 md:min-h-40 rounded-md border border-border-weak-base bg-background-base/50 px-4 py-3 text-text-weak whitespace-pre-wrap pointer-events-none">
                   <div class="w-full min-h-32 md:min-h-40 rounded-md border border-border-weak-base bg-background-base/50 px-4 py-3 text-text-weak whitespace-pre-wrap pointer-events-none">
-                    {handoff.prompt || "Loading prompt..."}
+                    {handoff.prompt || language.t("prompt.loading")}
                   </div>
                   </div>
                 }
                 }
               >
               >
@@ -2057,7 +2059,7 @@ export default function Page() {
                                   <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                                   <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                                     <Mark class="w-14 opacity-10" />
                                     <Mark class="w-14 opacity-10" />
                                     <div class="text-13-regular text-text-weak max-w-56">
                                     <div class="text-13-regular text-text-weak max-w-56">
-                                      No changes in this session yet
+                                      {language.t("session.review.empty")}
                                     </div>
                                     </div>
                                   </div>
                                   </div>
                                 </Match>
                                 </Match>
@@ -2071,7 +2073,9 @@ export default function Page() {
                         <Tabs.Content value="review" class="flex flex-col h-full overflow-hidden contain-strict">
                         <Tabs.Content value="review" class="flex flex-col h-full overflow-hidden contain-strict">
                           <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                           <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                             <Mark class="w-14 opacity-10" />
                             <Mark class="w-14 opacity-10" />
-                            <div class="text-13-regular text-text-weak max-w-56">Select a file to open</div>
+                            <div class="text-13-regular text-text-weak max-w-56">
+                              {language.t("session.files.selectToOpen")}
+                            </div>
                           </div>
                           </div>
                         </Tabs.Content>
                         </Tabs.Content>
                       </Show>
                       </Show>
@@ -2609,7 +2613,9 @@ export default function Page() {
                       <Match when={true}>
                       <Match when={true}>
                         <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                         <div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
                           <Mark class="w-14 opacity-10" />
                           <Mark class="w-14 opacity-10" />
-                          <div class="text-13-regular text-text-weak max-w-56">No changes in this session yet</div>
+                          <div class="text-13-regular text-text-weak max-w-56">
+                            {language.t("session.review.empty")}
+                          </div>
                         </div>
                         </div>
                       </Match>
                       </Match>
                     </Switch>
                     </Switch>
@@ -2624,10 +2630,11 @@ export default function Page() {
                   <Tabs variant="pill" value={fileTreeTab()} onChange={setFileTreeTabValue} class="h-full">
                   <Tabs variant="pill" value={fileTreeTab()} onChange={setFileTreeTabValue} class="h-full">
                     <Tabs.List>
                     <Tabs.List>
                       <Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
                       <Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
-                        {reviewCount()} {reviewCount() === 1 ? "Change" : "Changes"}
+                        {reviewCount()}{" "}
+                        {language.t(reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other")}
                       </Tabs.Trigger>
                       </Tabs.Trigger>
                       <Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
                       <Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
-                        All files
+                        {language.t("session.files.all")}
                       </Tabs.Trigger>
                       </Tabs.Trigger>
                     </Tabs.List>
                     </Tabs.List>
                     <Tabs.Content value="changes" class="bg-background-base p-2">
                     <Tabs.Content value="changes" class="bg-background-base p-2">
@@ -2635,7 +2642,12 @@ export default function Page() {
                         <Match when={hasReview()}>
                         <Match when={hasReview()}>
                           <Show
                           <Show
                             when={diffsReady()}
                             when={diffsReady()}
-                            fallback={<div class="px-2 py-2 text-12-regular text-text-weak">Loading...</div>}
+                            fallback={
+                              <div class="px-2 py-2 text-12-regular text-text-weak">
+                                {language.t("common.loading")}
+                                {language.t("common.loading.ellipsis")}
+                              </div>
+                            }
                           >
                           >
                             <FileTree
                             <FileTree
                               path=""
                               path=""
@@ -2647,7 +2659,9 @@ export default function Page() {
                           </Show>
                           </Show>
                         </Match>
                         </Match>
                         <Match when={true}>
                         <Match when={true}>
-                          <div class="px-2 py-2 text-12-regular text-text-weak">No changes</div>
+                          <div class="px-2 py-2 text-12-regular text-text-weak">
+                            {language.t("session.review.noChanges")}
+                          </div>
                         </Match>
                         </Match>
                       </Switch>
                       </Switch>
                     </Tabs.Content>
                     </Tabs.Content>
@@ -2702,9 +2716,14 @@ export default function Page() {
                     )}
                     )}
                   </For>
                   </For>
                   <div class="flex-1" />
                   <div class="flex-1" />
-                  <div class="text-text-weak pr-2">Loading...</div>
+                  <div class="text-text-weak pr-2">
+                    {language.t("common.loading")}
+                    {language.t("common.loading.ellipsis")}
+                  </div>
+                </div>
+                <div class="flex-1 flex items-center justify-center text-text-weak">
+                  {language.t("terminal.loading")}
                 </div>
                 </div>
-                <div class="flex-1 flex items-center justify-center text-text-weak">Loading terminal...</div>
               </div>
               </div>
             }
             }
           >
           >

+ 16 - 5
packages/ui/src/components/line-comment.tsx

@@ -1,6 +1,7 @@
 import { onMount, Show, splitProps, type JSX } from "solid-js"
 import { onMount, Show, splitProps, type JSX } from "solid-js"
 import { Button } from "./button"
 import { Button } from "./button"
 import { Icon } from "./icon"
 import { Icon } from "./icon"
+import { useI18n } from "../context/i18n"
 
 
 export type LineCommentVariant = "default" | "editor"
 export type LineCommentVariant = "default" | "editor"
 
 
@@ -60,13 +61,18 @@ export type LineCommentProps = Omit<LineCommentAnchorProps, "children" | "varian
 }
 }
 
 
 export const LineComment = (props: LineCommentProps) => {
 export const LineComment = (props: LineCommentProps) => {
+  const i18n = useI18n()
   const [split, rest] = splitProps(props, ["comment", "selection"])
   const [split, rest] = splitProps(props, ["comment", "selection"])
 
 
   return (
   return (
     <LineCommentAnchor {...rest} variant="default">
     <LineCommentAnchor {...rest} variant="default">
       <div data-slot="line-comment-content">
       <div data-slot="line-comment-content">
         <div data-slot="line-comment-text">{split.comment}</div>
         <div data-slot="line-comment-text">{split.comment}</div>
-        <div data-slot="line-comment-label">Comment on {split.selection}</div>
+        <div data-slot="line-comment-label">
+          {i18n.t("ui.lineComment.label.prefix")}
+          {split.selection}
+          {i18n.t("ui.lineComment.label.suffix")}
+        </div>
       </div>
       </div>
     </LineCommentAnchor>
     </LineCommentAnchor>
   )
   )
@@ -86,6 +92,7 @@ export type LineCommentEditorProps = Omit<LineCommentAnchorProps, "children" | "
 }
 }
 
 
 export const LineCommentEditor = (props: LineCommentEditorProps) => {
 export const LineCommentEditor = (props: LineCommentEditorProps) => {
+  const i18n = useI18n()
   const [split, rest] = splitProps(props, [
   const [split, rest] = splitProps(props, [
     "value",
     "value",
     "selection",
     "selection",
@@ -125,7 +132,7 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => {
           }}
           }}
           data-slot="line-comment-textarea"
           data-slot="line-comment-textarea"
           rows={split.rows ?? 3}
           rows={split.rows ?? 3}
-          placeholder={split.placeholder ?? "Add comment"}
+          placeholder={split.placeholder ?? i18n.t("ui.lineComment.placeholder")}
           value={split.value}
           value={split.value}
           onInput={(e) => split.onInput(e.currentTarget.value)}
           onInput={(e) => split.onInput(e.currentTarget.value)}
           onKeyDown={(e) => {
           onKeyDown={(e) => {
@@ -143,12 +150,16 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => {
           }}
           }}
         />
         />
         <div data-slot="line-comment-actions">
         <div data-slot="line-comment-actions">
-          <div data-slot="line-comment-editor-label">Commenting on {split.selection}</div>
+          <div data-slot="line-comment-editor-label">
+            {i18n.t("ui.lineComment.editorLabel.prefix")}
+            {split.selection}
+            {i18n.t("ui.lineComment.editorLabel.suffix")}
+          </div>
           <Button size="small" variant="ghost" onClick={split.onCancel}>
           <Button size="small" variant="ghost" onClick={split.onCancel}>
-            {split.cancelLabel ?? "Cancel"}
+            {split.cancelLabel ?? i18n.t("ui.common.cancel")}
           </Button>
           </Button>
           <Button size="small" variant="primary" disabled={split.value.trim().length === 0} onClick={submit}>
           <Button size="small" variant="primary" disabled={split.value.trim().length === 0} onClick={submit}>
-            {split.submitLabel ?? "Comment"}
+            {split.submitLabel ?? i18n.t("ui.lineComment.submit")}
           </Button>
           </Button>
         </div>
         </div>
       </div>
       </div>

+ 2 - 2
packages/ui/src/components/session-review.tsx

@@ -530,12 +530,12 @@ export const SessionReview = (props: SessionReviewProps) => {
                           <Switch>
                           <Switch>
                             <Match when={isAdded()}>
                             <Match when={isAdded()}>
                               <span data-slot="session-review-change" data-type="added">
                               <span data-slot="session-review-change" data-type="added">
-                                Added
+                                {i18n.t("ui.sessionReview.change.added")}
                               </span>
                               </span>
                             </Match>
                             </Match>
                             <Match when={isDeleted()}>
                             <Match when={isDeleted()}>
                               <span data-slot="session-review-change" data-type="removed">
                               <span data-slot="session-review-change" data-type="removed">
-                                Removed
+                                {i18n.t("ui.sessionReview.change.removed")}
                               </span>
                               </span>
                             </Match>
                             </Match>
                             <Match when={true}>
                             <Match when={true}>

+ 9 - 0
packages/ui/src/i18n/en.ts

@@ -4,6 +4,15 @@ export const dict = {
   "ui.sessionReview.diffStyle.split": "Split",
   "ui.sessionReview.diffStyle.split": "Split",
   "ui.sessionReview.expandAll": "Expand all",
   "ui.sessionReview.expandAll": "Expand all",
   "ui.sessionReview.collapseAll": "Collapse all",
   "ui.sessionReview.collapseAll": "Collapse all",
+  "ui.sessionReview.change.added": "Added",
+  "ui.sessionReview.change.removed": "Removed",
+
+  "ui.lineComment.label.prefix": "Comment on ",
+  "ui.lineComment.label.suffix": "",
+  "ui.lineComment.editorLabel.prefix": "Commenting on ",
+  "ui.lineComment.editorLabel.suffix": "",
+  "ui.lineComment.placeholder": "Add comment",
+  "ui.lineComment.submit": "Comment",
 
 
   "ui.sessionTurn.steps.show": "Show steps",
   "ui.sessionTurn.steps.show": "Show steps",
   "ui.sessionTurn.steps.hide": "Hide steps",
   "ui.sessionTurn.steps.hide": "Hide steps",