diff --git a/packages/cli/src/i18n/locales/de.js b/packages/cli/src/i18n/locales/de.js index 1144aa31c03..302a6385f94 100644 --- a/packages/cli/src/i18n/locales/de.js +++ b/packages/cli/src/i18n/locales/de.js @@ -1459,4 +1459,9 @@ export default { '{{region}}-Konfiguration erfolgreich aktualisiert. Modell auf "{{model}}" umgeschaltet.', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': 'Erfolgreich mit {{region}} authentifiziert. API-Schlüssel und Modellkonfigurationen wurden in settings.json gespeichert (gesichert).', + // =========================================================================== + // Insight Report - Language Support + // =========================================================================== + 'Generating insights in {{language}}...': + 'Generiere Einblicke auf {{language}}...', }; diff --git a/packages/cli/src/i18n/locales/en.js b/packages/cli/src/i18n/locales/en.js index 1c27b760fbb..18933ab3c55 100644 --- a/packages/cli/src/i18n/locales/en.js +++ b/packages/cli/src/i18n/locales/en.js @@ -1448,4 +1448,10 @@ export default { '{{region}} configuration updated successfully. Model switched to "{{model}}".', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).', + + // ============================================================================ + // Insight Report - Language Support + // ============================================================================ + 'Generating insights in {{language}}...': + 'Generating insights in {{language}}...', }; diff --git a/packages/cli/src/i18n/locales/ja.js b/packages/cli/src/i18n/locales/ja.js index 634cec49d7c..9c2a55aa41d 100644 --- a/packages/cli/src/i18n/locales/ja.js +++ b/packages/cli/src/i18n/locales/ja.js @@ -966,4 +966,10 @@ export default { '{{region}} の設定が正常に更新されました。モデルが "{{model}}" に切り替わりました。', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': '{{region}} での認証に成功しました。APIキーとモデル設定が settings.json に保存されました(バックアップ済み)。', + + // ============================================================================ + // Insight Report - Language Support + // ============================================================================ + 'Generating insights in {{language}}...': + '{{language}} でインサイトを生成中...', }; diff --git a/packages/cli/src/i18n/locales/pt.js b/packages/cli/src/i18n/locales/pt.js index 729ebbd7494..98749b07d4c 100644 --- a/packages/cli/src/i18n/locales/pt.js +++ b/packages/cli/src/i18n/locales/pt.js @@ -1453,4 +1453,9 @@ export default { 'Configuração do {{region}} atualizada com sucesso. Modelo alterado para "{{model}}".', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': 'Autenticado com sucesso com {{region}}. Chave de API e configurações de modelo salvas em settings.json (com backup).', + // =========================================================================== + // Insight Report - Language Support + // =========================================================================== + 'Generating insights in {{language}}...': + 'Gerando insights em {{language}}...', }; diff --git a/packages/cli/src/i18n/locales/ru.js b/packages/cli/src/i18n/locales/ru.js index 867de9b9ab6..b92a677d791 100644 --- a/packages/cli/src/i18n/locales/ru.js +++ b/packages/cli/src/i18n/locales/ru.js @@ -1463,4 +1463,9 @@ export default { 'Конфигурация {{region}} успешно обновлена. Модель переключена на "{{model}}".', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': 'Успешная аутентификация с {{region}}. API-ключ и конфигурации моделей сохранены в settings.json (резервная копия создана).', + // =========================================================================== + // Insight Report - Language Support + // =========================================================================== + 'Generating insights in {{language}}...': + 'Генерация инсайтов на {{language}}...', }; diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js index 5bc2bef9218..05a73e4df75 100644 --- a/packages/cli/src/i18n/locales/zh.js +++ b/packages/cli/src/i18n/locales/zh.js @@ -1281,4 +1281,10 @@ export default { '{{region}} 配置更新成功。模型已切换至 "{{model}}"。', 'Authenticated successfully with {{region}}. API key and model configs saved to settings.json (backed up).': '成功通过 {{region}} 认证。API Key 和模型配置已保存至 settings.json(已备份)。', + + // ============================================================================ + // Insight Report - Language Support + // ============================================================================ + 'Generating insights in {{language}}...': + '正在生成 {{language}} 的洞察报告...', }; diff --git a/packages/cli/src/services/insight/generators/DataProcessor.ts b/packages/cli/src/services/insight/generators/DataProcessor.ts index a3cda424e10..cbdf7998c8e 100644 --- a/packages/cli/src/services/insight/generators/DataProcessor.ts +++ b/packages/cli/src/services/insight/generators/DataProcessor.ts @@ -34,13 +34,27 @@ import { type Config, type ChatRecord, } from '@qwen-code/qwen-code-core'; +import type { SupportedLanguage } from '../../../i18n/index.js'; const logger = createDebugLogger('DataProcessor'); const CONCURRENCY_LIMIT = 4; +// Language display names for prompts +const LANGUAGE_DISPLAY_NAMES: Record = { + en: 'English', + zh: '中文 (Chinese)', + ja: '日本語 (Japanese)', + de: 'Deutsch (German)', + pt: 'Português (Portuguese)', + ru: 'Русский (Russian)', +}; + export class DataProcessor { - constructor(private config: Config) {} + constructor( + private config: Config, + private language: SupportedLanguage = 'en', + ) {} // Helper function to format date as YYYY-MM-DD private formatDate(date: Date): string { @@ -193,7 +207,8 @@ export class DataProcessor { }; const sessionText = this.formatRecordsForAnalysis(records); - const prompt = `${getInsightPrompt('analysis')}\n\nSESSION:\n${sessionText}`; + const languageInstruction = `\n\nIMPORTANT: Respond in ${LANGUAGE_DISPLAY_NAMES[this.language]}. All output text (brief_summary, underlying_goal, friction_detail) must be written in ${LANGUAGE_DISPLAY_NAMES[this.language]}.`; + const prompt = `${getInsightPrompt('analysis')}\n\nSESSION:\n${sessionText}${languageInstruction}`; try { const result = await this.config.getBaseLlmClient().generateJson({ @@ -384,12 +399,13 @@ export class DataProcessor { logger.info('Generating qualitative insights...'); const commonData = this.prepareCommonPromptData(metrics, facets); + const languageInstruction = `\n\nIMPORTANT: Respond in ${LANGUAGE_DISPLAY_NAMES[this.language]}. All output text must be written in ${LANGUAGE_DISPLAY_NAMES[this.language]}.`; const generate = async ( promptTemplate: string, schema: Record, ): Promise => { - const prompt = `${promptTemplate}\n\n${commonData}`; + const prompt = `${promptTemplate}${languageInstruction}\n\n${commonData}`; try { const result = await this.config.getBaseLlmClient().generateJson({ model: this.config.getModel(), diff --git a/packages/cli/src/services/insight/generators/StaticInsightGenerator.ts b/packages/cli/src/services/insight/generators/StaticInsightGenerator.ts index 99bcb9e266f..24eb4809e23 100644 --- a/packages/cli/src/services/insight/generators/StaticInsightGenerator.ts +++ b/packages/cli/src/services/insight/generators/StaticInsightGenerator.ts @@ -15,16 +15,22 @@ import type { } from '../types/StaticInsightTypes.js'; import { createDebugLogger, type Config } from '@qwen-code/qwen-code-core'; +import { + getCurrentLanguage, + type SupportedLanguage, +} from '../../../i18n/index.js'; const logger = createDebugLogger('StaticInsightGenerator'); export class StaticInsightGenerator { private dataProcessor: DataProcessor; private templateRenderer: TemplateRenderer; + private language: SupportedLanguage; constructor(config: Config) { - this.dataProcessor = new DataProcessor(config); - this.templateRenderer = new TemplateRenderer(); + this.language = getCurrentLanguage(); + this.dataProcessor = new DataProcessor(config, this.language); + this.templateRenderer = new TemplateRenderer(this.language); } // Ensure the output directory exists diff --git a/packages/cli/src/services/insight/generators/TemplateRenderer.ts b/packages/cli/src/services/insight/generators/TemplateRenderer.ts index 8b6f779f7d4..75c4a39ddfd 100644 --- a/packages/cli/src/services/insight/generators/TemplateRenderer.ts +++ b/packages/cli/src/services/insight/generators/TemplateRenderer.ts @@ -6,12 +6,26 @@ import { INSIGHT_JS, INSIGHT_CSS } from '@qwen-code/web-templates'; import type { InsightData } from '../types/StaticInsightTypes.js'; +import type { SupportedLanguage } from '../../../i18n/index.js'; + +// Language codes for HTML lang attribute +const HTML_LANG_CODES: Record = { + en: 'en', + zh: 'zh-CN', + ja: 'ja', + de: 'de', + pt: 'pt-BR', + ru: 'ru', +}; export class TemplateRenderer { + constructor(private language: SupportedLanguage = 'en') {} + // Render the complete HTML file async renderInsightHTML(insights: InsightData): Promise { + const htmlLang = HTML_LANG_CODES[this.language]; const html = ` - + @@ -38,6 +52,7 @@ export class TemplateRenderer { diff --git a/packages/cli/src/ui/commands/insightCommand.ts b/packages/cli/src/ui/commands/insightCommand.ts index 1693254bb4d..9a6b577ac6a 100644 --- a/packages/cli/src/ui/commands/insightCommand.ts +++ b/packages/cli/src/ui/commands/insightCommand.ts @@ -8,7 +8,11 @@ import type { CommandContext, SlashCommand } from './types.js'; import { CommandKind } from './types.js'; import { MessageType } from '../types.js'; import type { HistoryItemInsightProgress } from '../types.js'; -import { t } from '../../i18n/index.js'; +import { + t, + getCurrentLanguage, + getLanguageNameFromLocale, +} from '../../i18n/index.js'; import { join } from 'path'; import os from 'os'; import { StaticInsightGenerator } from '../../services/insight/generators/StaticInsightGenerator.js'; @@ -29,6 +33,19 @@ export const insightCommand: SlashCommand = { try { context.ui.setDebugMessage(t('Generating insights...')); + // Get current language and display a message + const currentLang = getCurrentLanguage(); + const langName = getLanguageNameFromLocale(currentLang); + context.ui.addItem( + { + type: MessageType.INFO, + text: t('Generating insights in {{language}}...', { + language: langName, + }), + }, + Date.now(), + ); + const projectsDir = join(os.homedir(), '.qwen', 'projects'); if (!context.services.config) { throw new Error('Config service is not available'); diff --git a/packages/web-templates/src/insight/src/Header.tsx b/packages/web-templates/src/insight/src/Header.tsx index e4f47f3abc4..f828bd224a5 100644 --- a/packages/web-templates/src/insight/src/Header.tsx +++ b/packages/web-templates/src/insight/src/Header.tsx @@ -1,6 +1,12 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import React from 'react'; import type { InsightData } from './types'; +import { t } from './i18n'; + +// Get current language from window or default to 'en' +const currentLang = + (typeof window !== 'undefined' && window.INSIGHT_LANGUAGE) || 'en'; +const tr = (key: string) => t(key, currentLang); // Header Component export function Header({ @@ -15,11 +21,11 @@ export function Header({ return (

- Qwen Code Insights + {tr('Qwen Code Insights')}

{totalMessages - ? `${totalMessages} messages across ${totalSessions} sessions` + ? `${totalMessages} ${tr('messages across')} ${totalSessions} ${tr('sessions')}` : 'Your personalized coding journey and patterns'} {dateRangeStr && ` | ${dateRangeStr}`}

@@ -54,25 +60,25 @@ export function StatsRow({ data }: { data: InsightData }) {
{totalMessages}
-
Messages
+
{tr('Messages')}
+{totalLinesAdded}/-{totalLinesRemoved}
-
Lines
+
{tr('Lines')}
{totalFiles}
-
Files
+
{tr('Files')}
{daysSpan}
-
Days
+
{tr('Days')}
{msgsPerDay}
-
Msgs/Day
+
{tr('Msgs/Day')}
); diff --git a/packages/web-templates/src/insight/src/Qualitative.tsx b/packages/web-templates/src/insight/src/Qualitative.tsx index bc877c96820..7b677ca02e5 100644 --- a/packages/web-templates/src/insight/src/Qualitative.tsx +++ b/packages/web-templates/src/insight/src/Qualitative.tsx @@ -3,9 +3,15 @@ import { useState } from 'react'; import { DashboardCards, HeatmapSection } from './Charts'; import type { InsightData, QualitativeData } from './types'; import { CopyButton, MarkdownText } from './Components'; +import { t } from './i18n'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import React from 'react'; +// Get current language from window or default to 'en' +const currentLang = + (typeof window !== 'undefined' && window.INSIGHT_LANGUAGE) || 'en'; +const tr = (key: string) => t(key, currentLang); + // ----------------------------------------------------------------------------- // Qualitative Insight Components // ----------------------------------------------------------------------------- @@ -16,34 +22,34 @@ export function AtAGlance({ qualitative }: { qualitative: QualitativeData }) { return (
-
At a Glance
+
{tr('At a Glance')}
- What's working:{' '} + {tr("What's working:")}{' '} {atAGlance.whats_working} - Impressive Things You Did → + {tr('Impressive Things You Did →')}
- What's hindering you:{' '} + {tr("What's hindering you:")}{' '} {atAGlance.whats_hindering} - Where Things Go Wrong → + {tr('Where Things Go Wrong →')}
- Quick wins to try:{' '} + {tr('Quick wins to try:')}{' '} {atAGlance.quick_wins} - Features to Try → + {tr('Features to Try →')}
- Ambitious workflows:{' '} + {tr('Ambitious workflows:')}{' '} {atAGlance.ambitious_workflows} - On the Horizon → + {tr('On the Horizon →')}
@@ -54,13 +60,13 @@ export function AtAGlance({ qualitative }: { qualitative: QualitativeData }) { export function NavToc() { return ( ); } @@ -87,7 +93,7 @@ export function ProjectAreas({ id="section-work" className="text-xl font-semibold text-slate-900 mt-8 mb-4" > - What You Work On + {tr('What You Work On')} {Array.isArray(projectAreas?.areas) && projectAreas.areas.length > 0 && ( @@ -97,7 +103,7 @@ export function ProjectAreas({
{area.name} - ~{area.session_count} sessions + ~{area.session_count} {tr('sessions')}
@@ -119,14 +125,14 @@ export function ProjectAreas({ {topGoals && Object.keys(topGoals).length > 0 && ( )} {topToolsObj && Object.keys(topToolsObj).length > 0 && ( )} @@ -151,7 +157,7 @@ export function InteractionStyle({ id="section-usage" className="text-xl font-semibold text-slate-900 mt-8 mb-4" > - How You Use Qwen Code + {tr('How You Use Qwen Code')}

@@ -159,7 +165,7 @@ export function InteractionStyle({

{interactionStyle.key_pattern && (
- Key pattern:{' '} + {tr('Key pattern:')}{' '} {interactionStyle.key_pattern}
)} @@ -189,7 +195,7 @@ export function ImpressiveWorkflows({ id="section-wins" className="text-xl font-semibold text-slate-900 mt-8 mb-4" > - Impressive Things You Did + {tr('Impressive Things You Did')} {impressiveWorkflows.intro && (

@@ -220,7 +226,7 @@ export function ImpressiveWorkflows({ {primarySuccess && Object.keys(primarySuccess).length > 0 && ( 0 && ( > = { + en: { + // Header + 'Qwen Code Insights': 'Qwen Code Insights', + 'messages across': 'messages across', + sessions: 'sessions', + + // Export + 'Export Card': 'Export Card', + Dark: 'Dark', + Light: 'Light', + + // At a Glance + 'At a Glance': 'At a Glance', + "What's working:": "What's working:", + "What's hindering you:": "What's hindering you:", + 'Quick wins to try:': 'Quick wins to try:', + 'Ambitious workflows:': 'Ambitious workflows:', + 'Impressive Things You Did →': 'Impressive Things You Did →', + 'Where Things Go Wrong →': 'Where Things Go Wrong →', + 'Features to Try →': 'Features to Try →', + 'On the Horizon →': 'On the Horizon →', + + // Navigation + 'What You Work On': 'What You Work On', + 'How You Use Qwen Code': 'How You Use Qwen Code', + 'Impressive Things': 'Impressive Things', + 'Where Things Go Wrong': 'Where Things Go Wrong', + 'Features to Try': 'Features to Try', + 'New Usage Patterns': 'New Usage Patterns', + 'On the Horizon': 'On the Horizon', + + // Stats + Messages: 'Messages', + Lines: 'Lines', + Files: 'Files', + Days: 'Days', + 'Msgs/Day': 'Msgs/Day', + + // Project Areas + 'What You Wanted': 'What You Wanted', + 'Top Tools Used': 'Top Tools Used', + + // Interaction Style + 'Key pattern:': 'Key pattern:', + + // Impressive Workflows + 'Impressive Things You Did': 'Impressive Things You Did', + "What Helped Most (Qwen's Capabilities)": + "What Helped Most (Qwen's Capabilities)", + Outcomes: 'Outcomes', + + // Friction Points + 'User Satisfaction': 'User Satisfaction', + 'Friction Categories': 'Friction Categories', + + // Improvements + 'QWEN.MD Additions': 'QWEN.MD Additions', + 'Usage Patterns': 'Usage Patterns', + Copy: 'Copy', + Copied: 'Copied!', + + // Memorable Moment + 'Memorable Moment': 'Memorable Moment', + + // Share Card + 'Share Your Insights': 'Share Your Insights', + 'Generated by Qwen Code': 'Generated by Qwen Code', + }, + zh: { + // Header + 'Qwen Code Insights': 'Qwen Code 洞察报告', + 'messages across': '条消息,跨越', + sessions: '个会话', + + // Export + 'Export Card': '导出卡片', + Dark: '深色', + Light: '浅色', + + // At a Glance + 'At a Glance': '一览', + "What's working:": '有效的方法:', + "What's hindering you:": '阻碍你的因素:', + 'Quick wins to try:': '快速尝试的技巧:', + 'Ambitious workflows:': '雄心勃勃的工作流:', + 'Impressive Things You Did →': '你的出色表现 →', + 'Where Things Go Wrong →': '问题出在哪里 →', + 'Features to Try →': '尝试的功能 →', + 'On the Horizon →': '未来展望 →', + + // Navigation + 'What You Work On': '工作内容', + 'How You Use Qwen Code': '使用方式', + 'Impressive Things': '出色表现', + 'Where Things Go Wrong': '问题所在', + 'Features to Try': '功能推荐', + 'New Usage Patterns': '新的使用模式', + 'On the Horizon': '未来展望', + + // Stats + Messages: '消息数', + Lines: '代码行', + Files: '文件数', + Days: '天数', + 'Msgs/Day': '消息/天', + + // Project Areas + 'What You Wanted': '你的目标', + 'Top Tools Used': '常用工具', + + // Interaction Style + 'Key pattern:': '关键模式:', + + // Impressive Workflows + 'Impressive Things You Did': '你的出色表现', + "What Helped Most (Qwen's Capabilities)": '最有帮助的功能', + Outcomes: '结果', + + // Friction Points + 'User Satisfaction': '用户满意度', + 'Friction Categories': '摩擦类别', + + // Improvements + 'QWEN.MD Additions': 'QWEN.MD 建议', + 'Usage Patterns': '使用模式', + Copy: '复制', + Copied: '已复制!', + + // Memorable Moment + 'Memorable Moment': '难忘时刻', + + // Share Card + 'Share Your Insights': '分享你的洞察', + 'Generated by Qwen Code': '由 Qwen Code 生成', + }, + ja: { + // Header + 'Qwen Code Insights': 'Qwen Code インサイト', + 'messages across': '件のメッセージ、', + sessions: 'セッション', + + // Export + 'Export Card': 'カードをエクスポート', + Dark: 'ダーク', + Light: 'ライト', + + // At a Glance + 'At a Glance': '概要', + "What's working:": 'うまくいっていること:', + "What's hindering you:": '妨げになっていること:', + 'Quick wins to try:': '簡単に試せること:', + 'Ambitious workflows:': '野心的なワークフロー:', + 'Impressive Things You Did →': 'あなたの素晴らしい成果 →', + 'Where Things Go Wrong →': '問題が発生する場所 →', + 'Features to Try →': '試すべき機能 →', + 'On the Horizon →': '将来の展望 →', + + // Navigation + 'What You Work On': '作業内容', + 'How You Use Qwen Code': 'Qwen Code の使用方法', + 'Impressive Things': '素晴らしい成果', + 'Where Things Go Wrong': '問題点', + 'Features to Try': '試す機能', + 'New Usage Patterns': '新しい使用パターン', + 'On the Horizon': '将来の展望', + + // Stats + Messages: 'メッセージ', + Lines: '行', + Files: 'ファイル', + Days: '日', + 'Msgs/Day': 'メッセージ/日', + + // Project Areas + 'What You Wanted': 'あなたの目標', + 'Top Tools Used': '使用したツール', + + // Interaction Style + 'Key pattern:': 'キーパターン:', + + // Impressive Workflows + 'Impressive Things You Did': 'あなたの素晴らしい成果', + "What Helped Most (Qwen's Capabilities)": '最も役立った機能', + Outcomes: '結果', + + // Friction Points + 'User Satisfaction': 'ユーザー満足度', + 'Friction Categories': '摩擦カテゴリ', + + // Improvements + 'QWEN.MD Additions': 'QWEN.MD 追加事項', + 'Usage Patterns': '使用パターン', + Copy: 'コピー', + Copied: 'コピー完了!', + + // Memorable Moment + 'Memorable Moment': '思い出深い瞬間', + + // Share Card + 'Share Your Insights': 'インサイトを共有', + 'Generated by Qwen Code': 'Qwen Code によって生成', + }, + de: { + // Header + 'Qwen Code Insights': 'Qwen Code Einblicke', + 'messages across': 'Nachrichten in', + sessions: 'Sitzungen', + + // Export + 'Export Card': 'Karte exportieren', + Dark: 'Dunkel', + Light: 'Hell', + + // At a Glance + 'At a Glance': 'Auf einen Blick', + "What's working:": 'Was funktioniert:', + "What's hindering you:": 'Was hindert Sie:', + 'Quick wins to try:': 'Schnelle Erfolge:', + 'Ambitious workflows:': 'Ambitionierte Workflows:', + 'Impressive Things You Did →': 'Ihre beeindruckenden Leistungen →', + 'Where Things Go Wrong →': 'Wo Dinge schiefgehen →', + 'Features to Try →': 'Ausprobierenswerte Funktionen →', + 'On the Horizon →': 'Ausblick →', + + // Navigation + 'What You Work On': 'Woran Sie arbeiten', + 'How You Use Qwen Code': 'Wie Sie Qwen Code verwenden', + 'Impressive Things': 'Beeindruckende Dinge', + 'Where Things Go Wrong': 'Problembereiche', + 'Features to Try': 'Ausprobierenswerte Funktionen', + 'New Usage Patterns': 'Neue Nutzungsmuster', + 'On the Horizon': 'Ausblick', + + // Stats + Messages: 'Nachrichten', + Lines: 'Zeilen', + Files: 'Dateien', + Days: 'Tage', + 'Msgs/Day': 'Nachr./Tag', + + // Project Areas + 'What You Wanted': 'Ihre Ziele', + 'Top Tools Used': 'Häufig genutzte Tools', + + // Interaction Style + 'Key pattern:': 'Hauptmuster:', + + // Impressive Workflows + 'Impressive Things You Did': 'Ihre beeindruckenden Leistungen', + "What Helped Most (Qwen's Capabilities)": 'Was am meisten half', + Outcomes: 'Ergebnisse', + + // Friction Points + 'User Satisfaction': 'Benutzerzufriedenheit', + 'Friction Categories': 'Reibungspunkte', + + // Improvements + 'QWEN.MD Additions': 'QWEN.MD Ergänzungen', + 'Usage Patterns': 'Nutzungsmuster', + Copy: 'Kopieren', + Copied: 'Kopiert!', + + // Memorable Moment + 'Memorable Moment': 'Denkwürdiger Moment', + + // Share Card + 'Share Your Insights': 'Einblicke teilen', + 'Generated by Qwen Code': 'Generiert von Qwen Code', + }, + pt: { + // Header + 'Qwen Code Insights': 'Qwen Code Insights', + 'messages across': 'mensagens em', + sessions: 'sessões', + + // Export + 'Export Card': 'Exportar Cartão', + Dark: 'Escuro', + Light: 'Claro', + + // At a Glance + 'At a Glance': 'Resumo', + "What's working:": 'O que está funcionando:', + "What's hindering you:": 'O que está dificultando:', + 'Quick wins to try:': 'Vitórias rápidas:', + 'Ambitious workflows:': 'Fluxos ambiciosos:', + 'Impressive Things You Did →': 'Suas Conquistas Impressionantes →', + 'Where Things Go Wrong →': 'Onde as Coisas Dão Errado →', + 'Features to Try →': 'Recursos para Experimentar →', + 'On the Horizon →': 'No Horizonte →', + + // Navigation + 'What You Work On': 'Em Que Você Trabalha', + 'How You Use Qwen Code': 'Como Você Usa Qwen Code', + 'Impressive Things': 'Conquistas Impressionantes', + 'Where Things Go Wrong': 'Onde as Coisas Dão Errado', + 'Features to Try': 'Recursos para Experimentar', + 'New Usage Patterns': 'Novos Padrões de Uso', + 'On the Horizon': 'No Horizonte', + + // Stats + Messages: 'Mensagens', + Lines: 'Linhas', + Files: 'Arquivos', + Days: 'Dias', + 'Msgs/Day': 'Mens./Dia', + + // Project Areas + 'What You Wanted': 'O Que Você Quis', + 'Top Tools Used': 'Ferramentas Mais Usadas', + + // Interaction Style + 'Key pattern:': 'Padrão principal:', + + // Impressive Workflows + 'Impressive Things You Did': 'Suas Conquistas Impressionantes', + "What Helped Most (Qwen's Capabilities)": 'O Que Mais Ajudou', + Outcomes: 'Resultados', + + // Friction Points + 'User Satisfaction': 'Satisfação do Usuário', + 'Friction Categories': 'Categorias de Atrito', + + // Improvements + 'QWEN.MD Additions': 'Adições QWEN.MD', + 'Usage Patterns': 'Padrões de Uso', + Copy: 'Copiar', + Copied: 'Copiado!', + + // Memorable Moment + 'Memorable Moment': 'Momento Memorável', + + // Share Card + 'Share Your Insights': 'Compartilhar Insights', + 'Generated by Qwen Code': 'Gerado por Qwen Code', + }, + ru: { + // Header + 'Qwen Code Insights': 'Qwen Code Инсайты', + 'messages across': 'сообщений в', + sessions: 'сессиях', + + // Export + 'Export Card': 'Экспорт карточки', + Dark: 'Тёмная', + Light: 'Светлая', + + // At a Glance + 'At a Glance': 'Вкратце', + "What's working:": 'Что работает:', + "What's hindering you:": 'Что мешает:', + 'Quick wins to try:': 'Быстрые победы:', + 'Ambitious workflows:': 'Амбициозные рабочие процессы:', + 'Impressive Things You Did →': 'Ваши впечатляющие достижения →', + 'Where Things Go Wrong →': 'Где что-то идёт не так →', + 'Features to Try →': 'Функции для проб →', + 'On the Horizon →': 'На горизонте →', + + // Navigation + 'What You Work On': 'Над чем вы работаете', + 'How You Use Qwen Code': 'Как вы используете Qwen Code', + 'Impressive Things': 'Впечатляющие вещи', + 'Where Things Go Wrong': 'Где что-то идёт не так', + 'Features to Try': 'Функции для проб', + 'New Usage Patterns': 'Новые шаблоны использования', + 'On the Horizon': 'На горизонте', + + // Stats + Messages: 'Сообщения', + Lines: 'Строки', + Files: 'Файлы', + Days: 'Дни', + 'Msgs/Day': 'Сообщ./день', + + // Project Areas + 'What You Wanted': 'Чего вы хотели', + 'Top Tools Used': 'Используемые инструменты', + + // Interaction Style + 'Key pattern:': 'Ключевой паттерн:', + + // Impressive Workflows + 'Impressive Things You Did': 'Ваши впечатляющие достижения', + "What Helped Most (Qwen's Capabilities)": 'Что помогло больше всего', + Outcomes: 'Результаты', + + // Friction Points + 'User Satisfaction': 'Удовлетворённость пользователя', + 'Friction Categories': 'Категории трений', + + // Improvements + 'QWEN.MD Additions': 'Дополнения QWEN.MD', + 'Usage Patterns': 'Шаблоны использования', + Copy: 'Копировать', + Copied: 'Скопировано!', + + // Memorable Moment + 'Memorable Moment': 'Запоминающийся момент', + + // Share Card + 'Share Your Insights': 'Поделиться инсайтами', + 'Generated by Qwen Code': 'Сгенерировано Qwen Code', + }, +}; + +// Helper function to get translation +export function t(key: string, lang: SupportedLanguage = 'en'): string { + return translations[lang]?.[key] ?? translations['en']?.[key] ?? key; +} diff --git a/packages/web-templates/src/insight/src/types.ts b/packages/web-templates/src/insight/src/types.ts index 4b14aeadf63..ebe3bdf9391 100644 --- a/packages/web-templates/src/insight/src/types.ts +++ b/packages/web-templates/src/insight/src/types.ts @@ -2,6 +2,9 @@ import type { InsightData } from '../../../src/services/insight/types/StaticInsightTypes'; import type { QualitativeInsights as QualitativeData } from '../../../src/services/insight/types/QualitativeInsightTypes'; +// Supported languages for insight report +export type SupportedLanguage = 'en' | 'zh' | 'ja' | 'de' | 'pt' | 'ru'; + declare global { interface Window { React: typeof import('react'); @@ -9,6 +12,7 @@ declare global { Chart: any; html2canvas: any; INSIGHT_DATA: InsightData; + INSIGHT_LANGUAGE?: SupportedLanguage; } }