From 1d97ae795c659302d67a56f7ac04b0c56d57e108 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 5 May 2025 22:56:21 -0400 Subject: [PATCH 1/2] Use Lucide icons and translations in the code block --- .../src/components/common/CodeBlock.tsx | 31 ++++++++++--------- webview-ui/src/i18n/locales/ca/chat.json | 9 ++++++ webview-ui/src/i18n/locales/de/chat.json | 9 ++++++ webview-ui/src/i18n/locales/en/chat.json | 9 ++++++ webview-ui/src/i18n/locales/es/chat.json | 9 ++++++ webview-ui/src/i18n/locales/fr/chat.json | 9 ++++++ webview-ui/src/i18n/locales/hi/chat.json | 9 ++++++ webview-ui/src/i18n/locales/it/chat.json | 9 ++++++ webview-ui/src/i18n/locales/ja/chat.json | 9 ++++++ webview-ui/src/i18n/locales/ko/chat.json | 9 ++++++ webview-ui/src/i18n/locales/pl/chat.json | 9 ++++++ webview-ui/src/i18n/locales/pt-BR/chat.json | 9 ++++++ webview-ui/src/i18n/locales/ru/chat.json | 9 ++++++ webview-ui/src/i18n/locales/tr/chat.json | 9 ++++++ webview-ui/src/i18n/locales/vi/chat.json | 9 ++++++ webview-ui/src/i18n/locales/zh-CN/chat.json | 9 ++++++ webview-ui/src/i18n/locales/zh-TW/chat.json | 9 ++++++ 17 files changed, 160 insertions(+), 15 deletions(-) diff --git a/webview-ui/src/components/common/CodeBlock.tsx b/webview-ui/src/components/common/CodeBlock.tsx index 1b295e7d1a3..2bc4527c032 100644 --- a/webview-ui/src/components/common/CodeBlock.tsx +++ b/webview-ui/src/components/common/CodeBlock.tsx @@ -4,6 +4,8 @@ import { useCopyToClipboard } from "@src/utils/clipboard" import { getHighlighter, isLanguageLoaded, normalizeLanguage, ExtendedLanguage } from "@src/utils/highlighter" import { bundledLanguages } from "shiki" import type { ShikiTransformer } from "shiki" +import { ChevronDown, ChevronUp, WrapText, AlignJustify, Copy, Check } from "lucide-react" +import { useAppTranslation } from "@src/i18n/TranslationContext" export const CODE_BLOCK_BG_COLOR = "var(--vscode-editor-background, --vscode-sideBar-background, rgb(30 30 30))" export const WRAPPER_ALPHA = "cc" // 80% opacity // Configuration constants @@ -34,13 +36,6 @@ interface CodeBlockProps { onLanguageChange?: (language: string) => void } -const ButtonIcon = styled.span` - display: inline-block; - width: 1.2em; - text-align: center; - vertical-align: middle; -` - const CodeBlockButton = styled.button` background: transparent; border: none; @@ -50,16 +45,23 @@ const CodeBlockButton = styled.button` margin: 0 0px; display: flex; align-items: center; + justify-content: center; opacity: 0.4; border-radius: 3px; pointer-events: var(--copy-button-events, none); margin-left: 4px; height: 24px; + width: 24px; &:hover { background: var(--vscode-toolbar-hoverBackground); opacity: 1; } + + /* Style for Lucide icons to ensure consistent sizing and positioning */ + svg { + display: block; + } ` const CodeBlockButtonWrapper = styled.div` @@ -229,6 +231,7 @@ const CodeBlock = memo( const preRef = useRef(null) const copyButtonWrapperRef = useRef(null) const { showCopyFeedback, copyWithFeedback } = useCopyToClipboard() + const { t } = useAppTranslation() // Update current language when prop changes, but only if user hasn't made a selection useEffect(() => { @@ -696,19 +699,17 @@ const CodeBlock = memo( WINDOW_SHADE_SETTINGS.transitionDelayS * 1000 + 50, ) }} - title={`${windowShade ? "Expand" : "Collapse"} code block`}> - {windowShade ? "⌄" : "⌃"} + title={t(`chat:codeblock.tooltips.${windowShade ? "expand" : "collapse"}`)}> + {windowShade ? : } )} setWordWrap(!wordWrap)} - title={`${wordWrap ? "Disable" : "Enable"} word wrap`}> - - {wordWrap ? "⟼" : "⤸"} - + title={t(`chat:codeblock.tooltips.${wordWrap ? "disable_wrap" : "enable_wrap"}`)}> + {wordWrap ? : } - - + + {showCopyFeedback ? : } )} diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 282cac6a64c..2dbf818edcf 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -233,6 +233,15 @@ "close": "Tancar navegador" } }, + "codeblock": { + "tooltips": { + "expand": "Expandir bloc de codi", + "collapse": "Contraure bloc de codi", + "enable_wrap": "Activar ajustament de línia", + "disable_wrap": "Desactivar ajustament de línia", + "copy_code": "Copiar codi" + } + }, "systemPromptWarning": "ADVERTÈNCIA: S'ha activat una substitució personalitzada d'instruccions del sistema. Això pot trencar greument la funcionalitat i causar un comportament impredictible.", "shellIntegration": { "title": "Advertència d'execució d'ordres", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 7d4a7990ebd..058c4436fc5 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -233,6 +233,15 @@ "close": "Browser schließen" } }, + "codeblock": { + "tooltips": { + "expand": "Code-Block erweitern", + "collapse": "Code-Block reduzieren", + "enable_wrap": "Zeilenumbruch aktivieren", + "disable_wrap": "Zeilenumbruch deaktivieren", + "copy_code": "Code kopieren" + } + }, "systemPromptWarning": "WARNUNG: Benutzerdefinierte Systemaufforderung aktiv. Dies kann die Funktionalität erheblich beeinträchtigen und zu unvorhersehbarem Verhalten führen.", "shellIntegration": { "title": "Befehlsausführungswarnung", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index f810143084f..05efd561a5e 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -233,6 +233,15 @@ "close": "Close browser" } }, + "codeblock": { + "tooltips": { + "expand": "Expand code block", + "collapse": "Collapse code block", + "enable_wrap": "Enable word wrap", + "disable_wrap": "Disable word wrap", + "copy_code": "Copy code" + } + }, "systemPromptWarning": "WARNING: Custom system prompt override active. This can severely break functionality and cause unpredictable behavior.", "shellIntegration": { "title": "Command Execution Warning", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index afabbb6f64d..84b40091d11 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -233,6 +233,15 @@ "close": "Cerrar navegador" } }, + "codeblock": { + "tooltips": { + "expand": "Expandir bloque de código", + "collapse": "Contraer bloque de código", + "enable_wrap": "Activar ajuste de línea", + "disable_wrap": "Desactivar ajuste de línea", + "copy_code": "Copiar código" + } + }, "systemPromptWarning": "ADVERTENCIA: Anulación de instrucciones del sistema personalizada activa. Esto puede romper gravemente la funcionalidad y causar un comportamiento impredecible.", "shellIntegration": { "title": "Advertencia de ejecución de comandos", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 0627715e619..4af00e9fc67 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -233,6 +233,15 @@ "close": "Fermer le navigateur" } }, + "codeblock": { + "tooltips": { + "expand": "Développer le bloc de code", + "collapse": "Réduire le bloc de code", + "enable_wrap": "Activer le retour à la ligne", + "disable_wrap": "Désactiver le retour à la ligne", + "copy_code": "Copier le code" + } + }, "systemPromptWarning": "AVERTISSEMENT : Remplacement d'instructions système personnalisées actif. Cela peut gravement perturber la fonctionnalité et provoquer un comportement imprévisible.", "shellIntegration": { "title": "Avertissement d'exécution de commande", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 62aedebafda..7845ca97ad2 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -233,6 +233,15 @@ "close": "ब्राउज़र बंद करें" } }, + "codeblock": { + "tooltips": { + "expand": "कोड ब्लॉक का विस्तार करें", + "collapse": "कोड ब्लॉक को संकुचित करें", + "enable_wrap": "वर्ड रैप सक्षम करें", + "disable_wrap": "वर्ड रैप अक्षम करें", + "copy_code": "कोड कॉपी करें" + } + }, "systemPromptWarning": "चेतावनी: कस्टम सिस्टम प्रॉम्प्ट ओवरराइड सक्रिय है। यह कार्यक्षमता को गंभीर रूप से बाधित कर सकता है और अनियमित व्यवहार का कारण बन सकता है.", "shellIntegration": { "title": "कमांड निष्पादन चेतावनी", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index ac5163c69a7..55e2d272627 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -233,6 +233,15 @@ "close": "Chiudi browser" } }, + "codeblock": { + "tooltips": { + "expand": "Espandi blocco di codice", + "collapse": "Comprimi blocco di codice", + "enable_wrap": "Attiva a capo automatico", + "disable_wrap": "Disattiva a capo automatico", + "copy_code": "Copia codice" + } + }, "systemPromptWarning": "ATTENZIONE: Sovrascrittura personalizzata delle istruzioni di sistema attiva. Questo può compromettere gravemente le funzionalità e causare comportamenti imprevedibili.", "shellIntegration": { "title": "Avviso di esecuzione comando", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index f31b8575a9a..6530e3f3c47 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -233,6 +233,15 @@ "close": "ブラウザを閉じる" } }, + "codeblock": { + "tooltips": { + "expand": "コードブロックを展開", + "collapse": "コードブロックを折りたたむ", + "enable_wrap": "折り返しを有効化", + "disable_wrap": "折り返しを無効化", + "copy_code": "コードをコピー" + } + }, "systemPromptWarning": "警告:カスタムシステムプロンプトの上書きが有効です。これにより機能が深刻に損なわれ、予測不可能な動作が発生する可能性があります。", "shellIntegration": { "title": "コマンド実行警告", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 1354a7cce82..827ec0cfea5 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -233,6 +233,15 @@ "close": "브라우저 닫기" } }, + "codeblock": { + "tooltips": { + "expand": "코드 블록 확장", + "collapse": "코드 블록 축소", + "enable_wrap": "자동 줄바꿈 활성화", + "disable_wrap": "자동 줄바꿈 비활성화", + "copy_code": "코드 복사" + } + }, "systemPromptWarning": "경고: 사용자 정의 시스템 프롬프트 재정의가 활성화되었습니다. 이로 인해 기능이 심각하게 손상되고 예측할 수 없는 동작이 발생할 수 있습니다.", "shellIntegration": { "title": "명령 실행 경고", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 0a7adbe7317..2597f2ba13d 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -233,6 +233,15 @@ "close": "Zamknij przeglądarkę" } }, + "codeblock": { + "tooltips": { + "expand": "Rozwiń blok kodu", + "collapse": "Zwiń blok kodu", + "enable_wrap": "Włącz zawijanie wierszy", + "disable_wrap": "Wyłącz zawijanie wierszy", + "copy_code": "Kopiuj kod" + } + }, "systemPromptWarning": "OSTRZEŻENIE: Aktywne niestandardowe zastąpienie instrukcji systemowych. Może to poważnie zakłócić funkcjonalność i powodować nieprzewidywalne zachowanie.", "shellIntegration": { "title": "Ostrzeżenie wykonania polecenia", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 0600ea3a85d..37820facbd2 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -233,6 +233,15 @@ "close": "Fechar navegador" } }, + "codeblock": { + "tooltips": { + "expand": "Expandir bloco de código", + "collapse": "Recolher bloco de código", + "enable_wrap": "Ativar quebra de linha", + "disable_wrap": "Desativar quebra de linha", + "copy_code": "Copiar código" + } + }, "systemPromptWarning": "AVISO: Substituição personalizada de instrução do sistema ativa. Isso pode comprometer gravemente a funcionalidade e causar comportamento imprevisível.", "shellIntegration": { "title": "Aviso de execução de comando", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 77ddc3cb227..5bd13934f1b 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -233,6 +233,15 @@ "close": "Закрыть браузер" } }, + "codeblock": { + "tooltips": { + "expand": "Развернуть блок кода", + "collapse": "Свернуть блок кода", + "enable_wrap": "Включить перенос строк", + "disable_wrap": "Отключить перенос строк", + "copy_code": "Копировать код" + } + }, "systemPromptWarning": "ПРЕДУПРЕЖДЕНИЕ: Активна пользовательская системная подсказка. Это может серьезно нарушить работу и вызвать непредсказуемое поведение.", "shellIntegration": { "title": "Предупреждение о выполнении команды", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 8003cdb0451..2ea0eaaf059 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -233,6 +233,15 @@ "close": "Tarayıcıyı kapat" } }, + "codeblock": { + "tooltips": { + "expand": "Kod bloğunu genişlet", + "collapse": "Kod bloğunu daralt", + "enable_wrap": "Satır kaydırmayı etkinleştir", + "disable_wrap": "Satır kaydırmayı devre dışı bırak", + "copy_code": "Kodu kopyala" + } + }, "systemPromptWarning": "UYARI: Özel sistem komut geçersiz kılma aktif. Bu işlevselliği ciddi şekilde bozabilir ve öngörülemeyen davranışlara neden olabilir.", "shellIntegration": { "title": "Komut Çalıştırma Uyarısı", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index ed913a6d6b4..7b9091dc08c 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -233,6 +233,15 @@ "close": "Đóng trình duyệt" } }, + "codeblock": { + "tooltips": { + "expand": "Mở rộng khối mã", + "collapse": "Thu gọn khối mã", + "enable_wrap": "Bật tự động xuống dòng", + "disable_wrap": "Tắt tự động xuống dòng", + "copy_code": "Sao chép mã" + } + }, "systemPromptWarning": "CẢNH BÁO: Đã kích hoạt ghi đè lệnh nhắc hệ thống tùy chỉnh. Điều này có thể phá vỡ nghiêm trọng chức năng và gây ra hành vi không thể dự đoán.", "shellIntegration": { "title": "Cảnh báo thực thi lệnh", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 961801edb10..0caff90987a 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -233,6 +233,15 @@ "close": "关闭浏览器" } }, + "codeblock": { + "tooltips": { + "expand": "展开代码块", + "collapse": "收起代码块", + "enable_wrap": "启用自动换行", + "disable_wrap": "禁用自动换行", + "copy_code": "复制代码" + } + }, "systemPromptWarning": "警告:自定义系统提示词覆盖已激活。这可能严重破坏功能并导致不可预测的行为。", "shellIntegration": { "title": "命令执行警告", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 03c64cc1807..884d86ddd7f 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -233,6 +233,15 @@ "close": "關閉瀏覽器" } }, + "codeblock": { + "tooltips": { + "expand": "展開程式碼區塊", + "collapse": "摺疊程式碼區塊", + "enable_wrap": "啟用自動換行", + "disable_wrap": "停用自動換行", + "copy_code": "複製程式碼" + } + }, "systemPromptWarning": "警告:自訂系統提示詞覆蓋已啟用。這可能嚴重破壞功能並導致不可預測的行為。", "shellIntegration": { "title": "命令執行警告", From 7bd85395147a84f025c2894d05e7b13fff40cd5d Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 5 May 2025 23:12:57 -0400 Subject: [PATCH 2/2] Fix tests --- .../common/__tests__/CodeBlock.test.tsx | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/webview-ui/src/components/common/__tests__/CodeBlock.test.tsx b/webview-ui/src/components/common/__tests__/CodeBlock.test.tsx index e7347067c29..28576c3c7d6 100644 --- a/webview-ui/src/components/common/__tests__/CodeBlock.test.tsx +++ b/webview-ui/src/components/common/__tests__/CodeBlock.test.tsx @@ -2,6 +2,23 @@ import { render, screen, fireEvent, act } from "@testing-library/react" import "@testing-library/jest-dom" import CodeBlock from "../CodeBlock" +// Mock the translation context +jest.mock("../../../i18n/TranslationContext", () => ({ + useAppTranslation: () => ({ + t: (key: string) => { + // Return fixed English strings for tests + const translations: { [key: string]: string } = { + "chat:codeblock.tooltips.copy_code": "Copy code", + "chat:codeblock.tooltips.expand": "Expand code block", + "chat:codeblock.tooltips.collapse": "Collapse code block", + "chat:codeblock.tooltips.enable_wrap": "Enable word wrap", + "chat:codeblock.tooltips.disable_wrap": "Disable word wrap", + } + return translations[key] || key + }, + }), +})) + // Mock shiki module jest.mock("shiki", () => ({ bundledLanguages: { @@ -11,6 +28,22 @@ jest.mock("shiki", () => ({ }, })) +// Mock all lucide-react icons with a proxy to handle any icon requested +jest.mock("lucide-react", () => { + return new Proxy( + {}, + { + get: function (obj, prop) { + // Return a component factory for any icon that's requested + if (prop === "__esModule") { + return true + } + return () =>
{String(prop)}
+ }, + }, + ) +}) + // Mock the highlighter utility jest.mock("../../../utils/highlighter", () => { const mockHighlighter = {