Skip to content

Commit 4f8799f

Browse files
fix localization bugs
1 parent 1853eba commit 4f8799f

File tree

6 files changed

+100
-89
lines changed

6 files changed

+100
-89
lines changed

webview-ui/src/components/package-manager/PackageManagerView.tsx

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { PackageManagerSource } from "../../../../src/services/package-manager/t
66
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "cmdk"
77
import { PackageManagerItemCard } from "./components/PackageManagerItemCard"
88
import { useStateManager } from "./useStateManager"
9+
import { useAppTranslation } from "@/i18n/TranslationContext"
910

1011
interface PackageManagerViewProps {
1112
onDone?: () => void
1213
}
13-
1414
const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
15+
const { t } = useAppTranslation()
1516
const [state, manager] = useStateManager()
1617

1718
const [tagSearch, setTagSearch] = useState("")
@@ -31,7 +32,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
3132
<Tab>
3233
<TabHeader className="flex justify-between items-center sticky top-0 z-10 bg-vscode-editor-background border-b border-vscode-panel-border">
3334
<div className="flex items-center">
34-
<h3 className="text-vscode-foreground m-0">Package Manager</h3>
35+
<h3 className="text-vscode-foreground m-0">{t("package-manager:title")}</h3>
3536
</div>
3637
<div className="flex gap-2">
3738
<Button
@@ -41,7 +42,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
4142
"bg-vscode-button-background text-vscode-button-foreground hover:bg-vscode-button-hoverBackground",
4243
)}
4344
onClick={() => manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: "browse" } })}>
44-
Browse
45+
{t("package-manager:tabs.browse")}
4546
</Button>
4647
<Button
4748
variant={state.activeTab === "sources" ? "default" : "secondary"}
@@ -50,7 +51,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
5051
"bg-vscode-button-background text-vscode-button-foreground hover:bg-vscode-button-hoverBackground",
5152
)}
5253
onClick={() => manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: "sources" } })}>
53-
Sources
54+
{t("package-manager:tabs.sources")}
5455
</Button>
5556
</div>
5657
</TabHeader>
@@ -61,7 +62,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
6162
<div className="mb-4">
6263
<input
6364
type="text"
64-
placeholder="Search package manager items..."
65+
placeholder={t("package-manager:filters.search.placeholder")}
6566
value={state.filters.search}
6667
onChange={(e) =>
6768
manager.transition({
@@ -75,7 +76,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
7576
<div className="flex flex-wrap justify-between gap-2">
7677
<div className="whitespace-nowrap">
7778
<label htmlFor="type-filter" className="mr-2">
78-
Filter by type:
79+
{t("package-manager:filters.type.label")}
7980
</label>
8081
<select
8182
id="type-filter"
@@ -87,16 +88,18 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
8788
})
8889
}
8990
className="p-1 bg-vscode-dropdown-background text-vscode-dropdown-foreground border border-vscode-dropdown-border rounded">
90-
<option value="">All types</option>
91-
<option value="mode">Mode</option>
92-
<option value="mcp server">MCP Server</option>
93-
<option value="prompt">Prompt</option>
94-
<option value="package">Package</option>
91+
<option value="">{t("package-manager:filters.type.all")}</option>
92+
<option value="mode">{t("package-manager:filters.type.mode")}</option>
93+
<option value="mcp server">
94+
{t("package-manager:filters.type.mcp server")}
95+
</option>
96+
<option value="prompt">{t("package-manager:filters.type.prompt")}</option>
97+
<option value="package">{t("package-manager:filters.type.package")}</option>
9598
</select>
9699
</div>
97100

98101
<div className="whitespace-nowrap">
99-
<label className="mr-2">Sort by:</label>
102+
<label className="mr-2">{t("package-manager:filters.sort.label")}</label>
100103
<select
101104
value={state.sortConfig.by}
102105
onChange={(e) =>
@@ -106,8 +109,10 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
106109
})
107110
}
108111
className="p-1 bg-vscode-dropdown-background text-vscode-dropdown-foreground border border-vscode-dropdown-border rounded mr-2">
109-
<option value="name">Name</option>
110-
<option value="lastUpdated">Last Updated</option>
112+
<option value="name">{t("package-manager:filters.sort.name")}</option>
113+
<option value="lastUpdated">
114+
{t("package-manager:filters.sort.lastUpdated")}
115+
</option>
111116
</select>
112117
<button
113118
onClick={() =>
@@ -130,9 +135,13 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
130135
<div>
131136
<div className="flex items-center justify-between mb-1">
132137
<div className="flex items-center">
133-
<label className="mr-2">Filter by tags:</label>
138+
<label className="mr-2">
139+
{t("package-manager:filters.tags.label")}
140+
</label>
134141
<span className="text-xs text-vscode-descriptionForeground">
135-
({allTags.length} available)
142+
{t("package-manager:filters.tags.available", {
143+
count: allTags.length,
144+
})}
136145
</span>
137146
</div>
138147
{state.filters.tags.length > 0 && (
@@ -144,13 +153,15 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
144153
})
145154
}
146155
className="p-1 bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground rounded text-xs">
147-
Clear tags ({state.filters.tags.length})
156+
{t("package-manager:filters.tags.clear", {
157+
count: state.filters.tags.length,
158+
})}
148159
</button>
149160
)}
150161
</div>
151162
<Command className="rounded-lg border border-vscode-dropdown-border">
152163
<CommandInput
153-
placeholder="Type to search and select tags..."
164+
placeholder={t("package-manager:filters.tags.placeholder")}
154165
value={tagSearch}
155166
onValueChange={setTagSearch}
156167
onFocus={() => setIsTagInputActive(true)}
@@ -164,7 +175,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
164175
{(isTagInputActive || tagSearch) && (
165176
<CommandList className="max-h-[200px] overflow-y-auto bg-vscode-dropdown-background">
166177
<CommandEmpty className="p-2 text-sm text-vscode-descriptionForeground">
167-
No matching tags found
178+
{t("package-manager:filters.tags.noResults")}
168179
</CommandEmpty>
169180
<CommandGroup>
170181
{allTags
@@ -222,8 +233,10 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
222233
</Command>
223234
<div className="text-xs text-vscode-descriptionForeground mt-1">
224235
{state.filters.tags.length > 0
225-
? `Showing items with any of the selected tags (${state.filters.tags.length} selected)`
226-
: "Click tags to filter items"}
236+
? t("package-manager:filters.tags.selected", {
237+
count: state.filters.tags.length,
238+
})
239+
: t("package-manager:filters.tags.clickToFilter")}
227240
</div>
228241
</div>
229242
)}
@@ -243,7 +256,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
243256
) {
244257
return (
245258
<div className="flex flex-col items-center justify-center h-64 text-vscode-descriptionForeground">
246-
<p>Loading items...</p>
259+
<p>{t("package-manager:items.refresh.refreshing")}</p>
247260
</div>
248261
)
249262
}
@@ -252,7 +265,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
252265
if (isEmpty) {
253266
return (
254267
<div className="flex flex-col items-center justify-center h-64 text-vscode-descriptionForeground">
255-
<p>No package manager items found</p>
268+
<p>{t("package-manager:items.empty.noItems")}</p>
256269
</div>
257270
)
258271
}
@@ -261,9 +274,7 @@ const PackageManagerView: React.FC<PackageManagerViewProps> = ({ onDone }) => {
261274
return (
262275
<div>
263276
<p className="text-vscode-descriptionForeground mb-4">
264-
{state.filters.type || state.filters.search || state.filters.tags.length > 0
265-
? `${items.length} items found (filtered)`
266-
: `${items.length} ${items.length === 1 ? "item" : "items"} total`}
277+
{t("package-manager:items.count", { count: items.length })}
267278
</p>
268279
<div className="grid grid-cols-1 gap-4 pb-4">
269280
{items.map((item) => (
@@ -313,48 +324,49 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
313324
onRefreshSource,
314325
onSourcesChange,
315326
}) => {
327+
const { t } = useAppTranslation()
316328
const [newSourceUrl, setNewSourceUrl] = useState("")
317329
const [newSourceName, setNewSourceName] = useState("")
318330
const [error, setError] = useState("")
319331

320332
const handleAddSource = () => {
321333
if (!newSourceUrl) {
322-
setError("URL cannot be empty")
334+
setError(t("package-manager:sources.errors.emptyUrl"))
323335
return
324336
}
325337

326338
try {
327339
new URL(newSourceUrl)
328340
} catch (e) {
329-
setError("Invalid URL format")
341+
setError(t("package-manager:sources.errors.invalidUrl"))
330342
return
331343
}
332344

333345
const nonVisibleCharRegex = /[^\S ]/
334346
if (nonVisibleCharRegex.test(newSourceUrl)) {
335-
setError("URL contains non-visible characters other than spaces")
347+
setError(t("package-manager:sources.errors.nonVisibleChars"))
336348
return
337349
}
338350

339351
if (!isValidGitRepositoryUrl(newSourceUrl)) {
340-
setError("URL must be a valid Git repository URL (e.g., https://github.com/username/repo)")
352+
setError(t("package-manager:sources.errors.invalidGitUrl"))
341353
return
342354
}
343355

344356
const normalizedNewUrl = newSourceUrl.toLowerCase().replace(/\s+/g, "")
345357
if (sources.some((source) => source.url.toLowerCase().replace(/\s+/g, "") === normalizedNewUrl)) {
346-
setError("This URL is already in the list (case and whitespace insensitive match)")
358+
setError(t("package-manager:sources.errors.duplicateUrl"))
347359
return
348360
}
349361

350362
if (newSourceName) {
351363
if (newSourceName.length > 20) {
352-
setError("Name must be 20 characters or less")
364+
setError(t("package-manager:sources.errors.nameTooLong"))
353365
return
354366
}
355367

356368
if (nonVisibleCharRegex.test(newSourceName)) {
357-
setError("Name contains non-visible characters other than spaces")
369+
setError(t("package-manager:sources.errors.nonVisibleCharsName"))
358370
return
359371
}
360372

@@ -364,14 +376,14 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
364376
(source) => source.name && source.name.toLowerCase().replace(/\s+/g, "") === normalizedNewName,
365377
)
366378
) {
367-
setError("This name is already in use (case and whitespace insensitive match)")
379+
setError(t("package-manager:sources.errors.duplicateName"))
368380
return
369381
}
370382
}
371383

372384
const MAX_SOURCES = 10
373385
if (sources.length >= MAX_SOURCES) {
374-
setError(`Maximum of ${MAX_SOURCES} sources allowed`)
386+
setError(t("package-manager:sources.errors.maxSources", { max: MAX_SOURCES }))
375387
return
376388
}
377389

@@ -401,18 +413,15 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
401413

402414
return (
403415
<div>
404-
<h4 className="text-vscode-foreground mb-2">Configure Package Manager Sources</h4>
405-
<p className="text-vscode-descriptionForeground mb-4">
406-
Add Git repositories that contain package manager items. These repositories will be fetched when
407-
browsing the package manager.
408-
</p>
416+
<h4 className="text-vscode-foreground mb-2">{t("package-manager:sources.title")}</h4>
417+
<p className="text-vscode-descriptionForeground mb-4">{t("package-manager:sources.description")}</p>
409418

410419
<div className="mb-6">
411-
<h5 className="text-vscode-foreground mb-2">Add New Source</h5>
420+
<h5 className="text-vscode-foreground mb-2">{t("package-manager:sources.add.title")}</h5>
412421
<div className="flex flex-col gap-2 mb-2">
413422
<input
414423
type="text"
415-
placeholder="Git repository URL (e.g., https://github.com/username/repo)"
424+
placeholder={t("package-manager:sources.add.urlPlaceholder")}
416425
value={newSourceUrl}
417426
onChange={(e) => {
418427
setNewSourceUrl(e.target.value)
@@ -421,12 +430,11 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
421430
className="p-2 bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded"
422431
/>
423432
<p className="text-xs text-vscode-descriptionForeground mt-1 mb-2">
424-
Supported formats: HTTPS (https://github.com/username/repo), SSH
425-
([email protected]:username/repo.git), or Git protocol (git://github.com/username/repo.git)
433+
{t("package-manager:sources.add.urlFormats")}
426434
</p>
427435
<input
428436
type="text"
429-
placeholder="Display name (optional, max 20 chars)"
437+
placeholder={t("package-manager:sources.add.namePlaceholder")}
430438
value={newSourceName}
431439
onChange={(e) => {
432440
setNewSourceName(e.target.value.slice(0, 20))
@@ -439,15 +447,17 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
439447
{error && <p className="text-red-500 mb-2">{error}</p>}
440448
<Button onClick={handleAddSource}>
441449
<span className="codicon codicon-add mr-2"></span>
442-
Add Source
450+
{t("package-manager:sources.add.button")}
443451
</Button>
444452
</div>
445453
<h5 className="text-vscode-foreground mb-2">
446-
Current Sources{" "}
447-
<span className="text-vscode-descriptionForeground text-sm">({sources.length}/10 max)</span>
454+
{t("package-manager:sources.current.title")}{" "}
455+
<span className="text-vscode-descriptionForeground text-sm">
456+
{t("package-manager:sources.current.count", { current: sources.length, max: 10 })}
457+
</span>
448458
</h5>
449459
{sources.length === 0 ? (
450-
<p className="text-vscode-descriptionForeground">No sources configured. Add a source to get started.</p>
460+
<p className="text-vscode-descriptionForeground">{t("package-manager:sources.current.empty")}</p>
451461
) : (
452462
<div className="grid grid-cols-1 gap-2">
453463
{sources.map((source, index) => (
@@ -477,7 +487,7 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
477487
variant="ghost"
478488
size="icon"
479489
onClick={() => onRefreshSource(source.url)}
480-
title="Refresh this source"
490+
title={t("package-manager:sources.current.refresh")}
481491
className="text-vscode-foreground"
482492
disabled={refreshingUrls.includes(source.url)}>
483493
<span
@@ -487,6 +497,7 @@ const PackageManagerSourcesConfig: React.FC<PackageManagerSourcesConfigProps> =
487497
variant="ghost"
488498
size="icon"
489499
onClick={() => handleRemoveSource(index)}
500+
title={t("package-manager:sources.current.remove")}
490501
className="text-red-500">
491502
<span className="codicon codicon-trash"></span>
492503
</Button>

0 commit comments

Comments
 (0)