mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-21 05:52:35 +08:00
* feat(vscode): add Persian (Farsi) UI language
Add Farsi (fa) as a first-class UI locale for the VS Code extension, with
automatic right-to-left layout (the extension already supports RTL via Arabic).
- Register fa in language-utils (Locale union, LOCALES, RTL_LOCALES),
language.tsx (label + merged dict layers), kiloclaw, the extension-host and
cli-backend translation bundles, and both package.json language enums.
- Add complete fa.ts dictionaries for all kilo-vscode i18n namespaces
(sidebar, agent manager, kiloclaw, extension host, autocomplete, cli-backend).
- Extend i18n tests to enforce fa key completeness and placeholder alignment.
Persian language contributed by Babak Safabahar.
* fix(vscode): translate remaining Persian UI strings
* fix(vscode): make question dock and suggestions RTL-aware
The interactive question dock pinned option labels/descriptions to the left
via a hardcoded text-align: left, so they rendered left-aligned even under an
RTL locale (Persian/Arabic). Use logical text-align: start and logical padding
on the header, and add dir=auto to question text, option label/description,
collapsed preview, review rows and the suggestion text so mixed-script content
renders with correct bidi.
Contributed by Babak Safabahar.
* fix(i18n): sync Persian translations with latest en.ts
Resync fa.ts after rebasing on main:
- Translate the 27 newly added English keys into Persian.
- Remove the 23 obsolete memory.* keys that no longer exist in en.ts.
- Translate error.chain.configDirectoryTypo and other single-quoted values
that were previously left in English.
All {{placeholder}} tokens are preserved; brand/technical terms (MCP, VS Code,
Vercel, Kilo Code, TerminalBench) intentionally stay untranslated. The i18n
key-completeness and placeholder-alignment tests pass.
Contributed by Babak Safabahar.
* fix(i18n): sync Persian translations with latest main
Translate the 45 newly added keys after rebasing on upstream main, including
the four session.prompts.* keys requested by the reviewer:
- session.prompts.navLabel -> ناوبر پرامپت
- session.prompts.tick -> پرامپت {{index}} از {{total}}: {{prompt}}
- session.prompts.noAnswer -> هنوز پاسخی وجود ندارد
- session.prompts.queued -> در صف انتظار
All {{placeholder}} tokens preserved; brand terms stay untranslated.
i18n tests pass (32/32). Contributed by Babak Safabahar.
* fix(i18n): improve contextual accuracy of 8 Persian translations
Revise the 8 keys flagged by the reviewer as too literal:
- migration.whatsNew.features.agentManager.title: was 'مدیر عامل'; now 'Agent Manager' (product name, not translated)
- agentManager.dialog.createWorktree: was 'ایجاد درختکاری'; now 'ایجاد Worktree' (git technical term)
- agentManager.dialog.versionHint: 'worktree' kept in English
- sidebar.session.configureWorktree.tooltip: 'worktree'/'Agent Manager' kept in English
- sidebar.session.showChanges.tooltip.empty: 'working tree' kept in English
- diffViewer.source.unstaged.tooltip: 'working tree'/'stage' kept in English
- settings.language.description: phrasing improved
- prompt.placeholder.default: already natural; minor polish
Also sync fa.ts with any additional new keys added since the last commit.
i18n tests pass (32/32). Contributed by Babak Safabahar.
* Update packages/kilo-vscode/webview-ui/src/i18n/fa.ts
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
---------
Co-authored-by: Johnny Eric Amancio <johnnyeric@gmail.com>
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
import { describe, it, expect } from "bun:test"
|
|
import { normalizeLocale, resolveTemplate } from "../../webview-ui/src/context/language-utils"
|
|
|
|
describe("normalizeLocale", () => {
|
|
it("returns 'en' for English", () => {
|
|
expect(normalizeLocale("en")).toBe("en")
|
|
expect(normalizeLocale("en-US")).toBe("en")
|
|
expect(normalizeLocale("en-GB")).toBe("en")
|
|
})
|
|
|
|
it("returns 'zh' for Simplified Chinese", () => {
|
|
expect(normalizeLocale("zh")).toBe("zh")
|
|
expect(normalizeLocale("zh-CN")).toBe("zh")
|
|
expect(normalizeLocale("zh-Hans")).toBe("zh")
|
|
})
|
|
|
|
it("returns 'zht' for Traditional Chinese", () => {
|
|
expect(normalizeLocale("zht")).toBe("zht")
|
|
expect(normalizeLocale("zh-Hant")).toBe("zht")
|
|
expect(normalizeLocale("zh-TW")).toBe("zht")
|
|
expect(normalizeLocale("zh-HK")).toBe("zht")
|
|
expect(normalizeLocale("zh-MO")).toBe("zht")
|
|
expect(normalizeLocale("zh-hant-TW")).toBe("zht")
|
|
})
|
|
|
|
it("returns 'de' for German", () => {
|
|
expect(normalizeLocale("de")).toBe("de")
|
|
expect(normalizeLocale("de-AT")).toBe("de")
|
|
})
|
|
|
|
it("returns 'ko' for Korean", () => {
|
|
expect(normalizeLocale("ko")).toBe("ko")
|
|
expect(normalizeLocale("ko-KR")).toBe("ko")
|
|
})
|
|
|
|
it("returns 'fa' for Persian", () => {
|
|
expect(normalizeLocale("fa")).toBe("fa")
|
|
expect(normalizeLocale("fa-IR")).toBe("fa")
|
|
})
|
|
|
|
it("returns 'no' for Norwegian Bokmål", () => {
|
|
expect(normalizeLocale("nb")).toBe("no")
|
|
expect(normalizeLocale("nb-NO")).toBe("no")
|
|
})
|
|
|
|
it("returns 'no' for Norwegian Nynorsk", () => {
|
|
expect(normalizeLocale("nn")).toBe("no")
|
|
})
|
|
|
|
it("returns 'br' for Portuguese", () => {
|
|
expect(normalizeLocale("pt")).toBe("br")
|
|
expect(normalizeLocale("pt-BR")).toBe("br")
|
|
expect(normalizeLocale("pt-PT")).toBe("br")
|
|
})
|
|
|
|
it("falls back to 'en' for unknown locale", () => {
|
|
expect(normalizeLocale("xx")).toBe("en")
|
|
expect(normalizeLocale("xyz-ZZ")).toBe("en")
|
|
})
|
|
|
|
it("is case-insensitive", () => {
|
|
expect(normalizeLocale("EN")).toBe("en")
|
|
expect(normalizeLocale("DE")).toBe("de")
|
|
expect(normalizeLocale("ZH-HANT")).toBe("zht")
|
|
})
|
|
})
|
|
|
|
describe("resolveTemplate", () => {
|
|
it("returns text unchanged when no params", () => {
|
|
expect(resolveTemplate("hello world")).toBe("hello world")
|
|
})
|
|
|
|
it("returns text unchanged when params is undefined", () => {
|
|
expect(resolveTemplate("no {{var}} here", undefined)).toBe("no {{var}} here")
|
|
})
|
|
|
|
it("interpolates a single variable", () => {
|
|
expect(resolveTemplate("Hello {{name}}!", { name: "World" })).toBe("Hello World!")
|
|
})
|
|
|
|
it("interpolates multiple variables", () => {
|
|
const result = resolveTemplate("{{a}} + {{b}} = {{c}}", { a: "1", b: "2", c: "3" })
|
|
expect(result).toBe("1 + 2 = 3")
|
|
})
|
|
|
|
it("replaces missing variable with empty string", () => {
|
|
expect(resolveTemplate("{{missing}}", {})).toBe("")
|
|
})
|
|
|
|
it("handles numeric variable values", () => {
|
|
expect(resolveTemplate("count: {{n}}", { n: 42 })).toBe("count: 42")
|
|
})
|
|
|
|
it("handles whitespace around key in braces", () => {
|
|
expect(resolveTemplate("{{ name }}", { name: "test" })).toBe("test")
|
|
})
|
|
|
|
it("leaves unrelated text intact", () => {
|
|
const result = resolveTemplate("prefix {{x}} suffix", { x: "VALUE" })
|
|
expect(result).toBe("prefix VALUE suffix")
|
|
})
|
|
})
|