summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/components
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-20 17:56:53 -0600
committerAdam <[email protected]>2026-01-20 17:58:06 -0600
commit233d003b4926ec615ff15c1ddd54a1719a62ef13 (patch)
tree7c96d92f8b7bbf2b0fa9d5976d338fe10ab611dc /packages/app/src/components
parent6037e88ddf3fd08191dfb5e136796e15e8bc163c (diff)
downloadopencode-233d003b4926ec615ff15c1ddd54a1719a62ef13.tar.gz
opencode-233d003b4926ec615ff15c1ddd54a1719a62ef13.zip
wip(app): i18n
Diffstat (limited to 'packages/app/src/components')
-rw-r--r--packages/app/src/components/dialog-settings.tsx9
-rw-r--r--packages/app/src/components/settings-agents.tsx7
-rw-r--r--packages/app/src/components/settings-commands.tsx7
-rw-r--r--packages/app/src/components/settings-general.tsx94
-rw-r--r--packages/app/src/components/settings-keybinds.tsx49
-rw-r--r--packages/app/src/components/settings-mcp.tsx7
-rw-r--r--packages/app/src/components/settings-models.tsx7
-rw-r--r--packages/app/src/components/settings-permissions.tsx136
-rw-r--r--packages/app/src/components/settings-providers.tsx7
9 files changed, 246 insertions, 77 deletions
diff --git a/packages/app/src/components/dialog-settings.tsx b/packages/app/src/components/dialog-settings.tsx
index 5ef89b8bf..1e9575cb2 100644
--- a/packages/app/src/components/dialog-settings.tsx
+++ b/packages/app/src/components/dialog-settings.tsx
@@ -2,6 +2,7 @@ import { Component } from "solid-js"
import { Dialog } from "@opencode-ai/ui/dialog"
import { Tabs } from "@opencode-ai/ui/tabs"
import { Icon } from "@opencode-ai/ui/icon"
+import { useLanguage } from "@/context/language"
import { SettingsGeneral } from "./settings-general"
import { SettingsKeybinds } from "./settings-keybinds"
import { SettingsPermissions } from "./settings-permissions"
@@ -12,6 +13,8 @@ import { SettingsCommands } from "./settings-commands"
import { SettingsMcp } from "./settings-mcp"
export const DialogSettings: Component = () => {
+ const language = useLanguage()
+
return (
<Dialog size="x-large">
<Tabs orientation="vertical" variant="settings" defaultValue="general" class="h-full settings-dialog">
@@ -26,15 +29,15 @@ export const DialogSettings: Component = () => {
"padding-bottom": "12px",
}}
>
- <Tabs.SectionTitle>Desktop</Tabs.SectionTitle>
+ <Tabs.SectionTitle>{language.t("settings.section.desktop")}</Tabs.SectionTitle>
<div style={{ display: "flex", "flex-direction": "column", gap: "6px", width: "100%" }}>
<Tabs.Trigger value="general">
<Icon name="sliders" />
- General
+ {language.t("settings.tab.general")}
</Tabs.Trigger>
<Tabs.Trigger value="shortcuts">
<Icon name="keyboard" />
- Shortcuts
+ {language.t("settings.tab.shortcuts")}
</Tabs.Trigger>
</div>
</div>
diff --git a/packages/app/src/components/settings-agents.tsx b/packages/app/src/components/settings-agents.tsx
index 892be152b..e68f1e59c 100644
--- a/packages/app/src/components/settings-agents.tsx
+++ b/packages/app/src/components/settings-agents.tsx
@@ -1,11 +1,14 @@
import { Component } from "solid-js"
+import { useLanguage } from "@/context/language"
export const SettingsAgents: Component = () => {
+ const language = useLanguage()
+
return (
<div class="flex flex-col h-full overflow-y-auto">
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">Agents</h2>
- <p class="text-14-regular text-text-weak">Agent settings will be configurable here.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.agents.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.agents.description")}</p>
</div>
</div>
)
diff --git a/packages/app/src/components/settings-commands.tsx b/packages/app/src/components/settings-commands.tsx
index e98c0eeb0..cf796d0aa 100644
--- a/packages/app/src/components/settings-commands.tsx
+++ b/packages/app/src/components/settings-commands.tsx
@@ -1,11 +1,14 @@
import { Component } from "solid-js"
+import { useLanguage } from "@/context/language"
export const SettingsCommands: Component = () => {
+ const language = useLanguage()
+
return (
<div class="flex flex-col h-full overflow-y-auto">
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">Commands</h2>
- <p class="text-14-regular text-text-weak">Command settings will be configurable here.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.commands.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.commands.description")}</p>
</div>
</div>
)
diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx
index e8749cbde..5f3519a74 100644
--- a/packages/app/src/components/settings-general.tsx
+++ b/packages/app/src/components/settings-general.tsx
@@ -2,22 +2,33 @@ import { Component, createMemo, type JSX } from "solid-js"
import { Select } from "@opencode-ai/ui/select"
import { Switch } from "@opencode-ai/ui/switch"
import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme"
+import { useLanguage } from "@/context/language"
import { useSettings, monoFontFamily } from "@/context/settings"
import { playSound, SOUND_OPTIONS } from "@/utils/sound"
export const SettingsGeneral: Component = () => {
const theme = useTheme()
+ const language = useLanguage()
const settings = useSettings()
const themeOptions = createMemo(() =>
Object.entries(theme.themes()).map(([id, def]) => ({ id, name: def.name ?? id })),
)
- const colorSchemeOptions: { value: ColorScheme; label: string }[] = [
- { value: "system", label: "System setting" },
- { value: "light", label: "Light" },
- { value: "dark", label: "Dark" },
- ]
+ const colorSchemeOptions = createMemo(
+ (): { value: ColorScheme; label: string }[] => [
+ { value: "system", label: language.t("theme.scheme.system") },
+ { value: "light", label: language.t("theme.scheme.light") },
+ { value: "dark", label: language.t("theme.scheme.dark") },
+ ],
+ )
+
+ const languageOptions = createMemo(() =>
+ language.locales.map((locale) => ({
+ value: locale,
+ label: language.label(locale),
+ })),
+ )
const fontOptions = [
{ value: "ibm-plex-mono", label: "IBM Plex Mono" },
@@ -45,20 +56,39 @@ export const SettingsGeneral: Component = () => {
}}
>
<div class="flex flex-col gap-1 pt-6 pb-8">
- <h2 class="text-16-medium text-text-strong">General</h2>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.tab.general")}</h2>
</div>
</div>
<div class="flex flex-col gap-8 w-full">
{/* Appearance Section */}
<div class="flex flex-col gap-1">
- <h3 class="text-14-medium text-text-strong pb-2">Appearance</h3>
+ <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
<div class="bg-surface-raised-base px-4 rounded-lg">
- <SettingsRow title="Appearance" description="Customise how OpenCode looks on your device">
+ <SettingsRow
+ title={language.t("settings.general.row.language.title")}
+ description={language.t("settings.general.row.language.description")}
+ >
<Select
- options={colorSchemeOptions}
- current={colorSchemeOptions.find((o) => o.value === theme.colorScheme())}
+ options={languageOptions()}
+ current={languageOptions().find((o) => o.value === language.locale())}
+ value={(o) => o.value}
+ label={(o) => o.label}
+ onSelect={(option) => option && language.setLocale(option.value)}
+ variant="secondary"
+ size="small"
+ triggerVariant="settings"
+ />
+ </SettingsRow>
+
+ <SettingsRow
+ title={language.t("settings.general.row.appearance.title")}
+ description={language.t("settings.general.row.appearance.description")}
+ >
+ <Select
+ options={colorSchemeOptions()}
+ current={colorSchemeOptions().find((o) => o.value === theme.colorScheme())}
value={(o) => o.value}
label={(o) => o.label}
onSelect={(option) => option && theme.setColorScheme(option.value)}
@@ -74,12 +104,12 @@ export const SettingsGeneral: Component = () => {
</SettingsRow>
<SettingsRow
- title="Theme"
+ title={language.t("settings.general.row.theme.title")}
description={
<>
- Customise how OpenCode is themed.{" "}
+ {language.t("settings.general.row.theme.description")} {" "}
<a href="#" class="text-text-interactive-base">
- Learn more
+ {language.t("common.learnMore")}
</a>
</>
}
@@ -104,7 +134,10 @@ export const SettingsGeneral: Component = () => {
/>
</SettingsRow>
- <SettingsRow title="Font" description="Customise the mono font used in code blocks">
+ <SettingsRow
+ title={language.t("settings.general.row.font.title")}
+ description={language.t("settings.general.row.font.description")}
+ >
<Select
options={fontOptions}
current={fontOptions.find((o) => o.value === settings.appearance.font())}
@@ -124,12 +157,12 @@ export const SettingsGeneral: Component = () => {
{/* System notifications Section */}
<div class="flex flex-col gap-1">
- <h3 class="text-14-medium text-text-strong pb-2">System notifications</h3>
+ <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.notifications")}</h3>
<div class="bg-surface-raised-base px-4 rounded-lg">
<SettingsRow
- title="Agent"
- description="Show system notification when the agent is complete or needs attention"
+ title={language.t("settings.general.notifications.agent.title")}
+ description={language.t("settings.general.notifications.agent.description")}
>
<Switch
checked={settings.notifications.agent()}
@@ -137,14 +170,20 @@ export const SettingsGeneral: Component = () => {
/>
</SettingsRow>
- <SettingsRow title="Permissions" description="Show system notification when a permission is required">
+ <SettingsRow
+ title={language.t("settings.general.notifications.permissions.title")}
+ description={language.t("settings.general.notifications.permissions.description")}
+ >
<Switch
checked={settings.notifications.permissions()}
onChange={(checked) => settings.notifications.setPermissions(checked)}
/>
</SettingsRow>
- <SettingsRow title="Errors" description="Show system notification when an error occurs">
+ <SettingsRow
+ title={language.t("settings.general.notifications.errors.title")}
+ description={language.t("settings.general.notifications.errors.description")}
+ >
<Switch
checked={settings.notifications.errors()}
onChange={(checked) => settings.notifications.setErrors(checked)}
@@ -155,10 +194,13 @@ export const SettingsGeneral: Component = () => {
{/* Sound effects Section */}
<div class="flex flex-col gap-1">
- <h3 class="text-14-medium text-text-strong pb-2">Sound effects</h3>
+ <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.sounds")}</h3>
<div class="bg-surface-raised-base px-4 rounded-lg">
- <SettingsRow title="Agent" description="Play sound when the agent is complete or needs attention">
+ <SettingsRow
+ title={language.t("settings.general.sounds.agent.title")}
+ description={language.t("settings.general.sounds.agent.description")}
+ >
<Select
options={soundOptions}
current={soundOptions.find((o) => o.id === settings.sounds.agent())}
@@ -179,7 +221,10 @@ export const SettingsGeneral: Component = () => {
/>
</SettingsRow>
- <SettingsRow title="Permissions" description="Play sound when a permission is required">
+ <SettingsRow
+ title={language.t("settings.general.sounds.permissions.title")}
+ description={language.t("settings.general.sounds.permissions.description")}
+ >
<Select
options={soundOptions}
current={soundOptions.find((o) => o.id === settings.sounds.permissions())}
@@ -200,7 +245,10 @@ export const SettingsGeneral: Component = () => {
/>
</SettingsRow>
- <SettingsRow title="Errors" description="Play sound when an error occurs">
+ <SettingsRow
+ title={language.t("settings.general.sounds.errors.title")}
+ description={language.t("settings.general.sounds.errors.description")}
+ >
<Select
options={soundOptions}
current={soundOptions.find((o) => o.id === settings.sounds.errors())}
diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx
index bac727cd7..13a0042ff 100644
--- a/packages/app/src/components/settings-keybinds.tsx
+++ b/packages/app/src/components/settings-keybinds.tsx
@@ -2,6 +2,7 @@ import { Component, For, Show, createMemo, createSignal, onCleanup, onMount } fr
import { Button } from "@opencode-ai/ui/button"
import { showToast } from "@opencode-ai/ui/toast"
import { formatKeybind, parseKeybind, useCommand } from "@/context/command"
+import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings"
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
@@ -17,6 +18,23 @@ type KeybindMeta = {
const GROUPS: KeybindGroup[] = ["General", "Session", "Navigation", "Model and agent", "Terminal", "Prompt"]
+type GroupKey =
+ | "settings.shortcuts.group.general"
+ | "settings.shortcuts.group.session"
+ | "settings.shortcuts.group.navigation"
+ | "settings.shortcuts.group.modelAndAgent"
+ | "settings.shortcuts.group.terminal"
+ | "settings.shortcuts.group.prompt"
+
+const groupKey: Record<KeybindGroup, GroupKey> = {
+ General: "settings.shortcuts.group.general",
+ Session: "settings.shortcuts.group.session",
+ Navigation: "settings.shortcuts.group.navigation",
+ "Model and agent": "settings.shortcuts.group.modelAndAgent",
+ Terminal: "settings.shortcuts.group.terminal",
+ Prompt: "settings.shortcuts.group.prompt",
+}
+
function groupFor(id: string): KeybindGroup {
if (id === PALETTE_ID) return "General"
if (id.startsWith("terminal.")) return "Terminal"
@@ -86,6 +104,7 @@ function signatures(config: string | undefined) {
export const SettingsKeybinds: Component = () => {
const command = useCommand()
+ const language = useLanguage()
const settings = useSettings()
const [active, setActive] = createSignal<string | null>(null)
@@ -117,12 +136,16 @@ export const SettingsKeybinds: Component = () => {
const resetAll = () => {
stop()
settings.keybinds.resetAll()
- showToast({ title: "Shortcuts reset", description: "Keyboard shortcuts have been reset to defaults." })
+ showToast({
+ title: language.t("settings.shortcuts.reset.toast.title"),
+ description: language.t("settings.shortcuts.reset.toast.description"),
+ })
}
const list = createMemo(() => {
+ language.locale()
const out = new Map<string, KeybindMeta>()
- out.set(PALETTE_ID, { title: "Command palette", group: "General" })
+ out.set(PALETTE_ID, { title: language.t("command.palette"), group: "General" })
for (const opt of command.catalog) {
if (opt.id.startsWith("suggested.")) continue
@@ -188,7 +211,7 @@ export const SettingsKeybinds: Component = () => {
const palette = settings.keybinds.get(PALETTE_ID) ?? DEFAULT_PALETTE_KEYBIND
for (const sig of signatures(palette)) {
- add(sig, { id: PALETTE_ID, title: "Command palette" })
+ add(sig, { id: PALETTE_ID, title: title(PALETTE_ID) })
}
const valueFor = (id: string) => {
@@ -258,8 +281,11 @@ export const SettingsKeybinds: Component = () => {
if (conflicts.size > 0) {
showToast({
- title: "Shortcut already in use",
- description: `${formatKeybind(next)} is already assigned to ${[...conflicts.values()].join(", ")}.`,
+ title: language.t("settings.shortcuts.conflict.title"),
+ description: language.t("settings.shortcuts.conflict.description", {
+ keybind: formatKeybind(next),
+ titles: [...conflicts.values()].join(", "),
+ }),
})
return
}
@@ -288,9 +314,9 @@ export const SettingsKeybinds: Component = () => {
}}
>
<div class="flex items-center justify-between gap-4 pt-6 pb-8 max-w-[720px]">
- <h2 class="text-16-medium text-text-strong">Keyboard shortcuts</h2>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.shortcuts.title")}</h2>
<Button size="small" variant="secondary" onClick={resetAll} disabled={!hasOverrides()}>
- Reset to defaults
+ {language.t("settings.shortcuts.reset.button")}
</Button>
</div>
</div>
@@ -300,7 +326,7 @@ export const SettingsKeybinds: Component = () => {
{(group) => (
<Show when={(grouped().get(group) ?? []).length > 0}>
<div class="flex flex-col gap-1">
- <h3 class="text-14-medium text-text-strong pb-2">{group}</h3>
+ <h3 class="text-14-medium text-text-strong pb-2">{language.t(groupKey[group])}</h3>
<div class="bg-surface-raised-base px-4 rounded-lg">
<For each={grouped().get(group) ?? []}>
{(id) => (
@@ -316,8 +342,11 @@ export const SettingsKeybinds: Component = () => {
}}
onClick={() => start(id)}
>
- <Show when={active() === id} fallback={command.keybind(id) || "Unassigned"}>
- Press keys
+ <Show
+ when={active() === id}
+ fallback={command.keybind(id) || language.t("settings.shortcuts.unassigned")}
+ >
+ {language.t("settings.shortcuts.pressKeys")}
</Show>
</button>
</div>
diff --git a/packages/app/src/components/settings-mcp.tsx b/packages/app/src/components/settings-mcp.tsx
index ea6bf350f..928464a51 100644
--- a/packages/app/src/components/settings-mcp.tsx
+++ b/packages/app/src/components/settings-mcp.tsx
@@ -1,11 +1,14 @@
import { Component } from "solid-js"
+import { useLanguage } from "@/context/language"
export const SettingsMcp: Component = () => {
+ const language = useLanguage()
+
return (
<div class="flex flex-col h-full overflow-y-auto">
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">MCP</h2>
- <p class="text-14-regular text-text-weak">MCP settings will be configurable here.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.mcp.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.mcp.description")}</p>
</div>
</div>
)
diff --git a/packages/app/src/components/settings-models.tsx b/packages/app/src/components/settings-models.tsx
index 5fbeb144e..6a636879d 100644
--- a/packages/app/src/components/settings-models.tsx
+++ b/packages/app/src/components/settings-models.tsx
@@ -1,11 +1,14 @@
import { Component } from "solid-js"
+import { useLanguage } from "@/context/language"
export const SettingsModels: Component = () => {
+ const language = useLanguage()
+
return (
<div class="flex flex-col h-full overflow-y-auto">
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">Models</h2>
- <p class="text-14-regular text-text-weak">Model settings will be configurable here.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.models.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.models.description")}</p>
</div>
</div>
)
diff --git a/packages/app/src/components/settings-permissions.tsx b/packages/app/src/components/settings-permissions.tsx
index d0551d247..1381515f5 100644
--- a/packages/app/src/components/settings-permissions.tsx
+++ b/packages/app/src/components/settings-permissions.tsx
@@ -2,6 +2,7 @@ import { Select } from "@opencode-ai/ui/select"
import { showToast } from "@opencode-ai/ui/toast"
import { Component, For, createMemo, type JSX } from "solid-js"
import { useGlobalSync } from "@/context/global-sync"
+import { useLanguage } from "@/context/language"
type PermissionAction = "allow" | "ask" | "deny"
@@ -15,30 +16,94 @@ type PermissionItem = {
description: string
}
-const ACTIONS: Array<{ value: PermissionAction; label: string }> = [
- { value: "allow", label: "Allow" },
- { value: "ask", label: "Ask" },
- { value: "deny", label: "Deny" },
-]
-
-const ITEMS: PermissionItem[] = [
- { id: "read", title: "Read", description: "Reading a file (matches the file path)" },
- { id: "edit", title: "Edit", description: "Modify files, including edits, writes, patches, and multi-edits" },
- { id: "glob", title: "Glob", description: "Match files using glob patterns" },
- { id: "grep", title: "Grep", description: "Search file contents using regular expressions" },
- { id: "list", title: "List", description: "List files within a directory" },
- { id: "bash", title: "Bash", description: "Run shell commands" },
- { id: "task", title: "Task", description: "Launch sub-agents" },
- { id: "skill", title: "Skill", description: "Load a skill by name" },
- { id: "lsp", title: "LSP", description: "Run language server queries" },
- { id: "todoread", title: "Todo Read", description: "Read the todo list" },
- { id: "todowrite", title: "Todo Write", description: "Update the todo list" },
- { id: "webfetch", title: "Web Fetch", description: "Fetch content from a URL" },
- { id: "websearch", title: "Web Search", description: "Search the web" },
- { id: "codesearch", title: "Code Search", description: "Search code on the web" },
- { id: "external_directory", title: "External Directory", description: "Access files outside the project directory" },
- { id: "doom_loop", title: "Doom Loop", description: "Detect repeated tool calls with identical input" },
-]
+const ACTIONS = [
+ { value: "allow", label: "settings.permissions.action.allow" },
+ { value: "ask", label: "settings.permissions.action.ask" },
+ { value: "deny", label: "settings.permissions.action.deny" },
+] as const
+
+const ITEMS = [
+ {
+ id: "read",
+ title: "settings.permissions.tool.read.title",
+ description: "settings.permissions.tool.read.description",
+ },
+ {
+ id: "edit",
+ title: "settings.permissions.tool.edit.title",
+ description: "settings.permissions.tool.edit.description",
+ },
+ {
+ id: "glob",
+ title: "settings.permissions.tool.glob.title",
+ description: "settings.permissions.tool.glob.description",
+ },
+ {
+ id: "grep",
+ title: "settings.permissions.tool.grep.title",
+ description: "settings.permissions.tool.grep.description",
+ },
+ {
+ id: "list",
+ title: "settings.permissions.tool.list.title",
+ description: "settings.permissions.tool.list.description",
+ },
+ {
+ id: "bash",
+ title: "settings.permissions.tool.bash.title",
+ description: "settings.permissions.tool.bash.description",
+ },
+ {
+ id: "task",
+ title: "settings.permissions.tool.task.title",
+ description: "settings.permissions.tool.task.description",
+ },
+ {
+ id: "skill",
+ title: "settings.permissions.tool.skill.title",
+ description: "settings.permissions.tool.skill.description",
+ },
+ {
+ id: "lsp",
+ title: "settings.permissions.tool.lsp.title",
+ description: "settings.permissions.tool.lsp.description",
+ },
+ {
+ id: "todoread",
+ title: "settings.permissions.tool.todoread.title",
+ description: "settings.permissions.tool.todoread.description",
+ },
+ {
+ id: "todowrite",
+ title: "settings.permissions.tool.todowrite.title",
+ description: "settings.permissions.tool.todowrite.description",
+ },
+ {
+ id: "webfetch",
+ title: "settings.permissions.tool.webfetch.title",
+ description: "settings.permissions.tool.webfetch.description",
+ },
+ {
+ id: "websearch",
+ title: "settings.permissions.tool.websearch.title",
+ description: "settings.permissions.tool.websearch.description",
+ },
+ {
+ id: "codesearch",
+ title: "settings.permissions.tool.codesearch.title",
+ description: "settings.permissions.tool.codesearch.description",
+ },
+ {
+ id: "external_directory",
+ title: "settings.permissions.tool.external_directory.title",
+ description: "settings.permissions.tool.external_directory.description",
+ },
+ {
+ id: "doom_loop",
+ title: "settings.permissions.tool.doom_loop.title",
+ description: "settings.permissions.tool.doom_loop.description",
+ },
+] as const
const VALID_ACTIONS = new Set<PermissionAction>(["allow", "ask", "deny"])
@@ -67,6 +132,15 @@ function getRuleDefault(value: unknown): PermissionAction | undefined {
export const SettingsPermissions: Component = () => {
const globalSync = useGlobalSync()
+ const language = useLanguage()
+
+ const actions = createMemo(
+ (): Array<{ value: PermissionAction; label: string }> =>
+ ACTIONS.map((action) => ({
+ value: action.value,
+ label: language.t(action.label),
+ })),
+ )
const permission = createMemo(() => {
return toMap(globalSync.data.config.permission)
@@ -95,7 +169,7 @@ export const SettingsPermissions: Component = () => {
globalSync.updateConfig({ permission: { [id]: nextValue } }).catch((err: unknown) => {
globalSync.set("config", "permission", before)
const message = err instanceof Error ? err.message : String(err)
- showToast({ title: "Failed to update permissions", description: message })
+ showToast({ title: language.t("settings.permissions.toast.updateFailed.title"), description: message })
})
}
@@ -109,21 +183,21 @@ export const SettingsPermissions: Component = () => {
}}
>
<div class="flex flex-col gap-1 p-8 max-w-[720px]">
- <h2 class="text-16-medium text-text-strong">Permissions</h2>
- <p class="text-14-regular text-text-weak">Control what tools the server can use by default.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.permissions.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.permissions.description")}</p>
</div>
</div>
<div class="flex flex-col gap-6 p-8 pt-6 max-w-[720px]">
<div class="flex flex-col gap-2">
- <h3 class="text-14-medium text-text-strong">Appearance</h3>
+ <h3 class="text-14-medium text-text-strong">{language.t("settings.permissions.section.tools")}</h3>
<div class="border border-border-weak-base rounded-lg overflow-hidden">
<For each={ITEMS}>
{(item) => (
- <SettingsRow title={item.title} description={item.description}>
+ <SettingsRow title={language.t(item.title)} description={language.t(item.description)}>
<Select
- options={ACTIONS}
- current={ACTIONS.find((o) => o.value === actionFor(item.id))}
+ options={actions()}
+ current={actions().find((o) => o.value === actionFor(item.id))}
value={(o) => o.value}
label={(o) => o.label}
onSelect={(option) => option && setPermission(item.id, option.value)}
diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx
index cf90b6c13..7b6ca1939 100644
--- a/packages/app/src/components/settings-providers.tsx
+++ b/packages/app/src/components/settings-providers.tsx
@@ -1,11 +1,14 @@
import { Component } from "solid-js"
+import { useLanguage } from "@/context/language"
export const SettingsProviders: Component = () => {
+ const language = useLanguage()
+
return (
<div class="flex flex-col h-full overflow-y-auto">
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">Providers</h2>
- <p class="text-14-regular text-text-weak">Provider settings will be configurable here.</p>
+ <h2 class="text-16-medium text-text-strong">{language.t("settings.providers.title")}</h2>
+ <p class="text-14-regular text-text-weak">{language.t("settings.providers.description")}</p>
</div>
</div>
)