From 60c0f8aaf3775c2f9e6338527c2c95f5007eea52 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 31 Mar 2021 11:47:08 +0800 Subject: [PATCH] feat: click to navigate to detection, close #509 --- .vscode/settings.json | 1 + locales/de.json | 1 + locales/en.json | 2 + locales/es.json | 1 + locales/fr.json | 1 + locales/ja.json | 1 + locales/nb-NO.json | 1 + locales/nl-NL.json | 1 + locales/pt-BR.json | 1 + locales/ru.json | 1 + locales/sv-SE.json | 1 + locales/uk-UA.json | 1 + locales/zh-CN.json | 1 + locales/zh-TW.json | 1 + package.json | 9 ++++ src/commands/commands.ts | 1 + src/commands/deepl.ts | 44 +++++++++---------- src/commands/detectHardStrings.ts | 11 +++-- src/commands/gotoRange.ts | 21 +++++++++ src/commands/index.ts | 2 + src/extraction/parsers/types.ts | 4 ++ src/views/items/Base.ts | 8 +++- src/views/items/CurrentFileExtractionItem.ts | 9 ++-- src/views/items/FeedbackItem.ts | 5 ++- src/views/items/HardStringDetectResultItem.ts | 21 +++++++-- tsconfig.json | 1 + 26 files changed, 116 insertions(+), 35 deletions(-) create mode 100644 src/commands/gotoRange.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ac1650d..3938dc6d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,4 +60,5 @@ "vue", "html" ], + "typescript.tsdk": "node_modules/typescript/lib", } diff --git a/locales/de.json b/locales/de.json index 8a43003f..cce309b2 100644 --- a/locales/de.json +++ b/locales/de.json @@ -198,6 +198,7 @@ "review.translation_candidates": "Übersetzungskanditaten", "review.unknown_user": "Unbekannt", "view.current_file": "Aktuelle Datei", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/en.json b/locales/en.json index dd474367..8b80a4a3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -9,6 +9,7 @@ "command.duplicate_key": "Duplicate key", "command.edit_key": "Edit translation", "command.fulfill_keys": "Fulfill keys with empty strings", + "command.go_to_range": "Go to range", "command.insert_key": "Insert key", "command.locale_visibility_hide": "Hide locale", "command.locale_visibility_show": "Show locale", @@ -199,6 +200,7 @@ "review.unknown_user": "Unknown", "view.current_file": "Current file", "view.current_file_hard_strings": "Hard-coded strings", + "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "Keys in use", "view.current_file_keys_not_found": "Keys not found", "view.help_feedback": "Help & Feedback", diff --git a/locales/es.json b/locales/es.json index d8e8c68a..1927c865 100644 --- a/locales/es.json +++ b/locales/es.json @@ -198,6 +198,7 @@ "review.translation_candidates": "Traducciones candidatas", "review.unknown_user": "Desconocido", "view.current_file": "Archivo actual", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/fr.json b/locales/fr.json index da056e84..d5683ed1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -198,6 +198,7 @@ "review.translation_candidates": "", "review.unknown_user": "", "view.current_file": "Fichier ouvert", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/ja.json b/locales/ja.json index d7b08af4..a5af6050 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -198,6 +198,7 @@ "review.translation_candidates": "", "review.unknown_user": "", "view.current_file": "現在のファイル", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/nb-NO.json b/locales/nb-NO.json index 4ea6e6e5..137c5f37 100644 --- a/locales/nb-NO.json +++ b/locales/nb-NO.json @@ -198,6 +198,7 @@ "review.translation_candidates": "", "review.unknown_user": "", "view.current_file": "Denne filen", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/nl-NL.json b/locales/nl-NL.json index e7541cd3..00a01870 100644 --- a/locales/nl-NL.json +++ b/locales/nl-NL.json @@ -198,6 +198,7 @@ "review.translation_candidates": "", "review.unknown_user": "", "view.current_file": "Huidige bestand", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/pt-BR.json b/locales/pt-BR.json index 3ba4d102..37ed1ef8 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -198,6 +198,7 @@ "review.translation_candidates": "", "review.unknown_user": "", "view.current_file": "Arquivo atual", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/ru.json b/locales/ru.json index ba3c67ce..b64bcbcb 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -198,6 +198,7 @@ "review.translation_candidates": "Кандидаты на перевод", "review.unknown_user": "Неизвестно", "view.current_file": "Текущий файл", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/sv-SE.json b/locales/sv-SE.json index 279983aa..bcf99d3c 100644 --- a/locales/sv-SE.json +++ b/locales/sv-SE.json @@ -198,6 +198,7 @@ "review.translation_candidates": "Översättningskandidater", "review.unknown_user": "Okänd", "view.current_file": "Nuvarande fil", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/uk-UA.json b/locales/uk-UA.json index dc364f17..b43e6dda 100644 --- a/locales/uk-UA.json +++ b/locales/uk-UA.json @@ -198,6 +198,7 @@ "review.translation_candidates": "Кандидати на переклад", "review.unknown_user": "Невідомо", "view.current_file": "Поточний файл", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 0b09359f..57770b7c 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -198,6 +198,7 @@ "review.translation_candidates": "候选翻译", "review.unknown_user": "未知", "view.current_file": "当前文件", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index fe562525..69c337a5 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -198,6 +198,7 @@ "review.translation_candidates": "翻譯候選", "review.unknown_user": "未知", "view.current_file": "當前檔案", + "view.current_file_hard_strings": "", "view.current_file_hard_strings_unknown": "", "view.current_file_keys_in_use": "", "view.current_file_keys_not_found": "", diff --git a/package.json b/package.json index 32a1b606..3f043c3e 100644 --- a/package.json +++ b/package.json @@ -355,6 +355,11 @@ "command": "i18n-ally.deepl-usage", "category": "%extname%", "title": "%command.deepl_usage%" + }, + { + "command": "i18n-ally.go-to-range", + "category": "%extname%", + "title": "%command.go_to_range%" } ], "menus": { @@ -446,6 +451,10 @@ { "command": "i18n-ally.duplicate-key", "when": "false" + }, + { + "command": "i18n-ally.go-to-range", + "when": "false" } ], "view/item/context": [ diff --git a/src/commands/commands.ts b/src/commands/commands.ts index 3b4a2cb1..f501c2bb 100644 --- a/src/commands/commands.ts +++ b/src/commands/commands.ts @@ -4,6 +4,7 @@ export const enum Commands { config_display_language = 'i18n-ally.config-display-language', config_source_language = 'i18n-ally.config-source-language', config_locales = 'i18n-ally.config-locales', + go_to_range = 'i18n-ally.go-to-range', set_display_language = 'i18n-ally.set-display-language', set_source_language = 'i18n-ally.set-source-language', extract_text = 'i18n-ally.extract-text', diff --git a/src/commands/deepl.ts b/src/commands/deepl.ts index 18462843..86839a7f 100644 --- a/src/commands/deepl.ts +++ b/src/commands/deepl.ts @@ -7,33 +7,33 @@ import i18n from '~/i18n' import { Config } from '~/core' import { abbreviateNumber } from '~/utils' -const m: ExtensionModule = (ctx) => { - async function deepAuth() { - const apiKey = Config.deeplApiKey +async function deepAuth() { + const apiKey = Config.deeplApiKey - if (!apiKey) { - return window.showErrorMessage( - i18n.t('prompt.deepl_api_key_required'), - ) - } + if (!apiKey) { + return window.showErrorMessage( + i18n.t('prompt.deepl_api_key_required'), + ) + } - try { - const deeplUsage = await usage() + try { + const deeplUsage = await usage() - window.showInformationMessage( - i18n.t( - 'prompt.deepl_usage', - abbreviateNumber(deeplUsage.character_count), - abbreviateNumber(deeplUsage.character_limit), - ), - i18n.t('prompt.button_discard'), - ) - } - catch (err) { - window.showErrorMessage(i18n.t('prompt.deepl_error_get_usage')) - } + window.showInformationMessage( + i18n.t( + 'prompt.deepl_usage', + abbreviateNumber(deeplUsage.character_count), + abbreviateNumber(deeplUsage.character_limit), + ), + i18n.t('prompt.button_discard'), + ) + } + catch (err) { + window.showErrorMessage(i18n.t('prompt.deepl_error_get_usage')) } +} +const m: ExtensionModule = (ctx) => { return [ commands.registerCommand(Commands.deepl_usage, deepAuth), ] diff --git a/src/commands/detectHardStrings.ts b/src/commands/detectHardStrings.ts index d4d32299..d8f30e23 100644 --- a/src/commands/detectHardStrings.ts +++ b/src/commands/detectHardStrings.ts @@ -30,8 +30,13 @@ export async function DetectHardStrings() { for (const framework of frameworks) { const temp = framework.detectHardStrings?.(doc) - if (temp && temp.length) - result.push(...temp) + if (temp && temp.length) { + result.push(...temp.map(i => ({ + ...i, + document: doc, + editor, + }))) + } } editor.setDecorations( @@ -70,7 +75,7 @@ export async function DetectHardStrings() { .filter(Boolean), ) - window.showInformationMessage(result.map(i => i.text).join('\n')) + // window.showInformationMessage(result.map(i => i.text).join('\n')) return result } diff --git a/src/commands/gotoRange.ts b/src/commands/gotoRange.ts new file mode 100644 index 00000000..3ac35c54 --- /dev/null +++ b/src/commands/gotoRange.ts @@ -0,0 +1,21 @@ +import { commands, Range, Selection, TextEditor, TextEditorRevealType, window } from 'vscode' +import { Commands } from '~/extension' +import { ExtensionModule } from '~/modules' + +export function GoToRange(editor: TextEditor, range: Range) { + if (editor && range) { + editor.selection = new Selection( + range.end, + range.start, + ) + editor.revealRange(editor.selection, TextEditorRevealType.InCenter) + } +} + +const m: ExtensionModule = () => { + return [ + commands.registerCommand(Commands.go_to_range, GoToRange), + ] +} + +export default m diff --git a/src/commands/index.ts b/src/commands/index.ts index 0754964e..ecb07f9a 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -11,6 +11,7 @@ import refreshUsageReport from './refreshUsageReport' import editor from './openEditor' import review from './review' import deepl from './deepl' +import gotoRange from './gotoRange' const m: ExtensionModule = (ctx) => { return flatten([ @@ -25,6 +26,7 @@ const m: ExtensionModule = (ctx) => { editor(ctx), review(ctx), deepl(ctx), + gotoRange(ctx), ]) } diff --git a/src/extraction/parsers/types.ts b/src/extraction/parsers/types.ts index 08bfa4c0..e78b8c7a 100644 --- a/src/extraction/parsers/types.ts +++ b/src/extraction/parsers/types.ts @@ -1,7 +1,11 @@ +import { TextDocument, TextEditor } from 'vscode' + export interface DetectionResult { text: string start: number end: number + document?: TextDocument + editor?: TextEditor isDynamic?: boolean fullText?: string fullStart?: number diff --git a/src/views/items/Base.ts b/src/views/items/Base.ts index 6398d5c5..2d5ff663 100644 --- a/src/views/items/Base.ts +++ b/src/views/items/Base.ts @@ -2,6 +2,8 @@ import { ExtensionContext, TreeItem } from 'vscode' import { Config } from '~/core' export abstract class BaseTreeItem extends TreeItem { + private _label = '' + constructor( public readonly ctx: ExtensionContext, ) { @@ -13,10 +15,12 @@ export abstract class BaseTreeItem extends TreeItem { } protected getLabel() { - return '' + return this._label } - protected setLabel(value: string) {} + protected setLabel(value: string) { + this._label = value + } // @ts-expect-error get label() { diff --git a/src/views/items/CurrentFileExtractionItem.ts b/src/views/items/CurrentFileExtractionItem.ts index 8bfc78ca..86c870b8 100644 --- a/src/views/items/CurrentFileExtractionItem.ts +++ b/src/views/items/CurrentFileExtractionItem.ts @@ -4,9 +4,11 @@ import { BaseTreeItem } from './Base' import { HardStringDetectResultItem } from './HardStringDetectResultItem' import i18n from '~/i18n' import { CurrentFile } from '~/core' +import { DetectionResult } from '~/extraction' export class CurrentFileExtractionItem extends BaseTreeItem { collapsibleState = TreeItemCollapsibleState.Collapsed + result: DetectionResult[] | undefined constructor(readonly provider: CurrentFileLocalesTreeProvider) { super(provider.ctx) @@ -28,11 +30,12 @@ export class CurrentFileExtractionItem extends BaseTreeItem { } async getChildren() { - const strings = await CurrentFile.detectHardStrings() + if (!this.result) + this.result = await CurrentFile.detectHardStrings() - if (strings == null) + if (this.result == null) return [] - return strings.map(i => new HardStringDetectResultItem(this.ctx, i)) + return this.result.map(i => new HardStringDetectResultItem(this.ctx, i)) } } diff --git a/src/views/items/FeedbackItem.ts b/src/views/items/FeedbackItem.ts index 25909773..3e9ddeec 100644 --- a/src/views/items/FeedbackItem.ts +++ b/src/views/items/FeedbackItem.ts @@ -7,7 +7,10 @@ export class FeedbackItem extends BaseTreeItem { constructor(ctx: ExtensionContext, define: FeedbackItemDefintion) { super(ctx) this.getLabel = () => define.text - this.iconPath = define.icon.startsWith('$') ? define.icon : this.getIcon(define.icon) + this.iconPath = define.icon.startsWith('$') + ? define.icon + : this.getIcon(define.icon) + if (define.desc) this.tooltip = define.desc if (define.command) { diff --git a/src/views/items/HardStringDetectResultItem.ts b/src/views/items/HardStringDetectResultItem.ts index b818f1de..b08387ab 100644 --- a/src/views/items/HardStringDetectResultItem.ts +++ b/src/views/items/HardStringDetectResultItem.ts @@ -1,6 +1,7 @@ -import { ExtensionContext, TreeItemCollapsibleState } from 'vscode' +import { ExtensionContext, Range, TreeItemCollapsibleState } from 'vscode' import { BaseTreeItem } from './Base' import { DetectionResult } from '~/extraction' +import { Commands } from '~/commands' export class HardStringDetectResultItem extends BaseTreeItem { collapsibleState = TreeItemCollapsibleState.None @@ -10,9 +11,21 @@ export class HardStringDetectResultItem extends BaseTreeItem { public readonly detection: DetectionResult, ) { super(ctx) - } - getLabel() { - return this.detection.text.trim() + this.label = this.detection.text.trim() + + if (this.detection.editor && this.detection.document) { + this.command = { + title: 'Go To', + command: Commands.go_to_range, + arguments: [ + this.detection.editor, + new Range( + this.detection.document.positionAt(this.detection.fullStart ?? this.detection.start), + this.detection.document.positionAt(this.detection.fullEnd ?? this.detection.end), + ), + ], + } + } } } diff --git a/tsconfig.json b/tsconfig.json index 6405f3d5..a6ad1d38 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "resolveJsonModule": true, "declaration": true, "moduleResolution": "node", + "skipLibCheck": true, "allowSyntheticDefaultImports": true, "noUnusedLocals": true, "paths": {