Skip to content

Commit e006aca

Browse files
johnnyshieldsclaudesrc-opn
authored
feat(i18n): extract en translations — pages (#1250)
* feat(i18n): extract en translations for pages Extract hardcoded English strings to i18n keys for: - config, extensions, identities, plugins - automations (was scheduled), settings, skills pages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(i18n): second-pass extraction of remaining hardcoded strings Scanned all 7 PR3 page files for hardcoded English strings missed by the reference diff. Converted to t() calls and added keys to en.ts: - identities.tsx: 25 keys (time ago, dispatched messages, health status, Telegram bot setup strings, routing override, agent scope/status, peer ID placeholders) - automations.tsx: 5 keys (scheduler install, prepare/remove job toasts, delete confirm description) - settings.tsx: 12 keys (actor labels, cap labels, workspace fallback, deeplink hint, worker ID label, inbox/outbox cap labels) - skills.tsx: 1 key (loading spinner text) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(i18n): add missing translation keys for identities page * fix(i18n): resolve rebase fallout on pages branch --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: src-opn <src-opn@users.noreply.github.com>
1 parent c349413 commit e006aca

File tree

8 files changed

+1243
-943
lines changed

8 files changed

+1243
-943
lines changed

apps/app/src/app/pages/automations.tsx

Lines changed: 114 additions & 112 deletions
Large diffs are not rendered by default.

apps/app/src/app/pages/config.tsx

Lines changed: 72 additions & 71 deletions
Large diffs are not rendered by default.

apps/app/src/app/pages/extensions.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import McpView from "../connections/mcp-view";
77
import { useConnections } from "../connections/provider";
88
import { useExtensions } from "../extensions/provider";
99
import PluginsView, { type PluginsViewProps } from "./plugins";
10+
import { t } from "../../i18n";
1011

1112
export type ExtensionsSection = "all" | "mcp" | "plugins";
1213

@@ -64,25 +65,25 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
6465
<div class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
6566
<div class="space-y-1">
6667
<Show when={props.showHeader !== false}>
67-
<h2 class="text-3xl font-bold text-dls-text">Extensions</h2>
68+
<h2 class="text-3xl font-bold text-dls-text">{t("extensions.title")}</h2>
6869
<p class="text-sm text-dls-secondary mt-1.5">
69-
Apps (MCP) and OpenCode plugins live in one place.
70+
{t("extensions.subtitle")}
7071
</p>
7172
</Show>
7273
<div class={`${props.showHeader === false ? "" : "mt-3"} flex flex-wrap items-center gap-2`}>
7374
<Show when={connectedAppsCount() > 0}>
7475
<div class="inline-flex items-center gap-2 rounded-full bg-green-3 px-3 py-1">
7576
<div class="w-2 h-2 rounded-full bg-green-9" />
7677
<span class="text-xs font-medium text-green-11">
77-
{connectedAppsCount()} app{connectedAppsCount() === 1 ? "" : "s"} connected
78+
{connectedAppsCount()} {connectedAppsCount() === 1 ? t("extensions.app_count_one") : t("extensions.app_count_many")}
7879
</span>
7980
</div>
8081
</Show>
8182
<Show when={pluginCount() > 0}>
8283
<div class="inline-flex items-center gap-2 rounded-full bg-gray-3 px-3 py-1">
8384
<Cpu size={14} class="text-gray-11" />
8485
<span class="text-xs font-medium text-gray-11">
85-
{pluginCount()} plugin{pluginCount() === 1 ? "" : "s"}
86+
{pluginCount()} {pluginCount() === 1 ? t("extensions.plugin_count_one") : t("extensions.plugin_count_many")}
8687
</span>
8788
</div>
8889
</Show>
@@ -97,7 +98,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
9798
aria-pressed={section() === "all"}
9899
onClick={() => selectSection("all")}
99100
>
100-
All
101+
{t("extensions.filter_all")}
101102
</button>
102103
<button
103104
type="button"
@@ -106,7 +107,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
106107
onClick={() => selectSection("mcp")}
107108
>
108109
<Box size={14} />
109-
Apps
110+
{t("extensions.filter_apps")}
110111
</button>
111112
<button
112113
type="button"
@@ -115,11 +116,11 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
115116
onClick={() => selectSection("plugins")}
116117
>
117118
<Cpu size={14} />
118-
Plugins
119+
{t("extensions.filter_plugins")}
119120
</button>
120121
</div>
121122
<Button variant="ghost" onClick={refreshAll}>
122-
Refresh
123+
{t("common.refresh")}
123124
</Button>
124125
</div>
125126
</div>
@@ -128,7 +129,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
128129
<div class="space-y-4">
129130
<div class="flex items-center gap-2 text-sm font-medium text-gray-12">
130131
<Box size={16} class="text-gray-11" />
131-
<span>Apps (MCP)</span>
132+
<span>{t("extensions.apps_mcp_header")}</span>
132133
</div>
133134
<McpView
134135
showHeader={false}
@@ -143,7 +144,7 @@ export default function ExtensionsView(props: ExtensionsViewProps) {
143144
<div class="space-y-4">
144145
<div class="flex items-center gap-2 text-sm font-medium text-gray-12">
145146
<Cpu size={16} class="text-gray-11" />
146-
<span>Plugins (OpenCode)</span>
147+
<span>{t("extensions.plugins_opencode_header")}</span>
147148
</div>
148149
<PluginsView
149150
busy={props.busy}

apps/app/src/app/pages/identities.tsx

Lines changed: 146 additions & 156 deletions
Large diffs are not rendered by default.

apps/app/src/app/pages/plugins.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useExtensions } from "../extensions/provider";
55
import Button from "../components/button";
66
import TextInput from "../components/text-input";
77
import { Cpu } from "lucide-solid";
8+
import { t } from "../../i18n";
89

910
export type PluginsViewProps = {
1011
busy: boolean;
@@ -37,8 +38,8 @@ export default function PluginsView(props: PluginsViewProps) {
3738
<div class="bg-gray-2/30 border border-gray-6/50 rounded-2xl p-5 space-y-4">
3839
<div class="flex items-start justify-between gap-4">
3940
<div class="space-y-1">
40-
<div class="text-sm font-medium text-gray-12">OpenCode plugins</div>
41-
<div class="text-xs text-gray-10">Manage `opencode.json` for your project or global OpenCode plugins.</div>
41+
<div class="text-sm font-medium text-gray-12">{t("plugins.title")}</div>
42+
<div class="text-xs text-gray-10">{t("plugins.desc")}</div>
4243
</div>
4344
<div class="flex items-center gap-2">
4445
<button
@@ -52,7 +53,7 @@ export default function PluginsView(props: PluginsViewProps) {
5253
void extensions.refreshPlugins("project");
5354
}}
5455
>
55-
Project
56+
{t("plugins.scope_project")}
5657
</button>
5758
<button
5859
disabled={!props.canUseGlobalScope}
@@ -67,24 +68,24 @@ export default function PluginsView(props: PluginsViewProps) {
6768
void extensions.refreshPlugins("global");
6869
}}
6970
>
70-
Global
71+
{t("plugins.scope_global")}
7172
</button>
7273
<Button variant="ghost" onClick={() => void extensions.refreshPlugins()}>
73-
Refresh
74+
{t("common.refresh")}
7475
</Button>
7576
</div>
7677
</div>
7778

7879
<div class="flex flex-col gap-1 text-xs text-gray-10">
79-
<div>Config</div>
80-
<div class="text-gray-7 font-mono truncate">{extensions.pluginConfigPath() ?? extensions.pluginConfig()?.path ?? "Not loaded yet"}</div>
80+
<div>{t("plugins.config_label")}</div>
81+
<div class="text-gray-7 font-mono truncate">{extensions.pluginConfigPath() ?? extensions.pluginConfig()?.path ?? t("plugins.not_loaded_yet")}</div>
8182
<Show when={props.accessHint}>
8283
<div class="text-gray-9">{props.accessHint}</div>
8384
</Show>
8485
</div>
8586

8687
<div class="space-y-3">
87-
<div class="text-xs font-medium text-gray-11 uppercase tracking-wider">Suggested plugins</div>
88+
<div class="text-xs font-medium text-gray-11 uppercase tracking-wider">{t("plugins.suggested_heading")}</div>
8889
<div class="grid gap-3">
8990
<For each={props.suggestedPlugins}>
9091
{(plugin) => {
@@ -108,7 +109,7 @@ export default function PluginsView(props: PluginsViewProps) {
108109
variant="ghost"
109110
onClick={() => extensions.setActivePluginGuide(isGuideOpen() ? null : plugin.packageName)}
110111
>
111-
{isGuideOpen() ? "Hide setup" : "Setup"}
112+
{isGuideOpen() ? t("plugins.hide_setup") : t("plugins.setup")}
112113
</Button>
113114
</Show>
114115
<Button
@@ -121,7 +122,7 @@ export default function PluginsView(props: PluginsViewProps) {
121122
(extensions.pluginScope() === "project" && !props.selectedWorkspaceRoot.trim())
122123
}
123124
>
124-
{isInstalled() ? "Added" : "Add"}
125+
{isInstalled() ? t("plugins.added") : t("plugins.add")}
125126
</Button>
126127
</div>
127128
</div>
@@ -177,7 +178,7 @@ export default function PluginsView(props: PluginsViewProps) {
177178
when={extensions.pluginList().length}
178179
fallback={
179180
<div class="rounded-xl border border-gray-6/60 bg-gray-1/40 p-4 text-sm text-gray-10">
180-
No plugins configured yet.
181+
{t("plugins.empty")}
181182
</div>
182183
}
183184
>
@@ -187,14 +188,14 @@ export default function PluginsView(props: PluginsViewProps) {
187188
<div class="flex items-center justify-between rounded-xl border border-gray-6/60 bg-gray-1/40 px-4 py-2.5">
188189
<div class="text-sm text-gray-12 font-mono">{pluginName}</div>
189190
<div class="flex items-center gap-2">
190-
<div class="text-[10px] uppercase tracking-wide text-gray-10">Enabled</div>
191+
<div class="text-[10px] uppercase tracking-wide text-gray-10">{t("plugins.enabled")}</div>
191192
<Button
192193
variant="ghost"
193194
class="h-7 px-2 text-[11px] text-red-11 hover:text-red-12"
194195
onClick={() => extensions.removePlugin(pluginName)}
195196
disabled={props.busy || !props.canEditPlugins}
196197
>
197-
Remove
198+
{t("plugins.remove")}
198199
</Button>
199200
</div>
200201
</div>
@@ -207,11 +208,11 @@ export default function PluginsView(props: PluginsViewProps) {
207208
<div class="flex flex-col md:flex-row gap-3">
208209
<div class="flex-1">
209210
<TextInput
210-
label="Add plugin"
211+
label={t("plugins.add_label")}
211212
placeholder="opencode-wakatime"
212213
value={extensions.pluginInput()}
213214
onInput={(e) => extensions.setPluginInput(e.currentTarget.value)}
214-
hint="Add npm package names, e.g. opencode-wakatime"
215+
hint={t("plugins.add_hint")}
215216
/>
216217
</div>
217218
<Button
@@ -220,7 +221,7 @@ export default function PluginsView(props: PluginsViewProps) {
220221
disabled={props.busy || !extensions.pluginInput().trim() || !props.canEditPlugins}
221222
class="md:mt-6"
222223
>
223-
Add
224+
{t("plugins.add")}
224225
</Button>
225226
</div>
226227
<Show when={extensions.pluginStatus()}>

0 commit comments

Comments
 (0)