Skip to content

Commit

Permalink
Added command to duplicate and translate the selected text
Browse files Browse the repository at this point in the history
  • Loading branch information
soerenuhrbach committed Mar 3, 2024
1 parent d4d9a04 commit 200e1a7
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to the "vscode-deepl" extension will be documented in this f

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

### 1.1.1

- Added command "DeepL: Duplicate and translate" which duplicates and translates the selected text.

### 1.1.0

- Removed the command "Translate from ... to ... below original text"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The following commands are available to translate texts:
|DeepL: Translate to ...|alt+shift+t|Asks for the target language and translates the selected text into the target language
|DeepL: Translate from ... to ...|alt+ctrl+shift+t|Asks for source and target language and translates the selected text from the source language into the target language
|DeepL: Translate and paste from clipboard|ctrl+shift+v|Translates the clipboard content and paste it
|DeepL: Translate and paste from clipboard|ctrl+shift+d|Duplicates and translates the selected text

The commands are accessible via the command pallette.

Expand Down Expand Up @@ -67,6 +68,10 @@ Dont use this extension if you dont agree with their privacy policy!

## Release Notes

### 1.1.1

- Added command "DeepL: Duplicate and translate" which duplicates and translates the selected text.

### 1.1.0

- Removed the command "Translate from ... to ... below original text"
Expand Down
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@
"command": "deepl.translateAndPasteFromClipboard",
"title": "DeepL: Translate and paste from clipboard",
"shortTitle": "Translate and paste from clipboard"
},
{
"command": "deepl.duplicateAndTranslate",
"title": "DeepL: Duplicate and translate",
"shortTitle": "Duplicate and translate"
}
],
"menus": {
Expand Down Expand Up @@ -254,6 +259,12 @@
"when": "!isInDiffEditor",
"key": "ctrl+shift+v",
"mac": "cmd+shift+v"
},
{
"command": "deepl.duplicateAndTranslate",
"when": "!isInDiffEditor",
"key": "ctrl+shift+d",
"mac": "cmd+shift+d"
}
]
},
Expand Down
95 changes: 75 additions & 20 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type GetTargetAndSourceLanguageRequest = {
forceSourceLanguagePrompt: boolean;
};

async function getTargetAndSourceLanguage (request: GetTargetAndSourceLanguageRequest): Promise<{ targetLanguage: TargetLanguageCode, sourceLanguage: SourceLanguageCode | undefined }> {
async function getTargetAndSourceLanguage (request: GetTargetAndSourceLanguageRequest = { forceSourceLanguagePrompt: false, forceTargetLanguagePrompt: false }): Promise<{ targetLanguage: TargetLanguageCode, sourceLanguage: SourceLanguageCode | undefined }> {
let targetLanguage = state.targetLanguage ?? getDefaultTargetLanguage();
if (request.forceTargetLanguagePrompt || !targetLanguage) {
targetLanguage = await showTargetLanguagePrompt() ?? state.targetLanguage ?? getDefaultTargetLanguage();
Expand Down Expand Up @@ -68,18 +68,8 @@ function translateSelections(selections: vscode.Selection[], request: { targetLa
return null;
}

debug.write(
sourceLanguage
? `Start translating '${text}' to '${targetLanguage}'`
: `Start translating '${text}' from '${sourceLanguage}' to '${targetLanguage}'`
);
const result = await deepl.translate(text, sourceLanguage, targetLanguage);
progress.report({ increment });
debug.write(
result
? `Successfully translated '${text}' to '${result.text}'! (Source: '${result.detectedSourceLang}', Target: '${targetLanguage}')`
: `'${text}' could not be translated to '${targetLanguage}! (Reason: DeepL-API returned no translation)'`
);
return result;
})
);
Expand Down Expand Up @@ -122,7 +112,9 @@ function createTranslateSelectionsCommand(request: GetTargetAndSourceLanguageReq
await configureSettings();
}

const selections = vscode.window.activeTextEditor?.selections?.filter(selection => !selection.isEmpty);
const selections = vscode.window.activeTextEditor
?.selections
?.filter(selection => !selection.isEmpty);
if (!selections || selections.length === 0) {
return;
}
Expand All @@ -134,9 +126,71 @@ function createTranslateSelectionsCommand(request: GetTargetAndSourceLanguageReq
export const setTargetLangauge = async () => state.targetLanguage = await showTargetLanguagePrompt();
export const configureSettings = async () => state.apiKey = await showApiKeyPrompt();

export const translate = createTranslateSelectionsCommand({ forceTargetLanguagePrompt: false, forceSourceLanguagePrompt: false });
export const translateTo = createTranslateSelectionsCommand({ forceTargetLanguagePrompt: true, forceSourceLanguagePrompt: false });
export const translateFromTo = createTranslateSelectionsCommand({ forceTargetLanguagePrompt: true, forceSourceLanguagePrompt: true });
export const translate = createTranslateSelectionsCommand({
forceTargetLanguagePrompt: false,
forceSourceLanguagePrompt: false
});
export const translateTo = createTranslateSelectionsCommand({
forceTargetLanguagePrompt: true,
forceSourceLanguagePrompt: false
});
export const translateFromTo = createTranslateSelectionsCommand({
forceTargetLanguagePrompt: true,
forceSourceLanguagePrompt: true
});

export const duplicateAndTranslate = async () => {
const editor = vscode.window.activeTextEditor;
const selections = editor?.selections;
if (!selections || selections.length === 0) {
return;
}

const { targetLanguage, sourceLanguage } = await getTargetAndSourceLanguage();

return displayTranslationNotification(async progress => {
const increment = 100 / 2 / selections.length;

const translationResults = await Promise.all(
selections.map(async selection => {
const duplicateWholeLine = selection.isEmpty && selection.isSingleLine;
const range = duplicateWholeLine
? editor.document.lineAt(selection.start.line).range
: new vscode.Range(
selection.start.line,
selection.start.character,
selection.end.line,
selection.end.character
);
const text = editor.document.getText(range);
const result = await deepl.translate(
text,
sourceLanguage,
targetLanguage
);
progress.report({ increment });

return {
text,
range,
result,
duplicateWholeLine
};
})
);

await editor.edit((editor: vscode.TextEditorEdit) => {
for (const translationResult of translationResults) {
const replacement = translationResult.duplicateWholeLine
? `${translationResult.text}\n${translationResult.result.text}`
: `${translationResult.text}${translationResult.result.text}`;

editor.replace(translationResult.range, replacement);
progress.report({ increment });
}
});
});
};

export const translateAndPasteFromClipboard = async () => {
const selections = vscode.window.activeTextEditor?.selections;
Expand All @@ -149,14 +203,15 @@ export const translateAndPasteFromClipboard = async () => {
return;
}

const { targetLanguage, sourceLanguage } = await getTargetAndSourceLanguage({
forceSourceLanguagePrompt: false,
forceTargetLanguagePrompt: false
});
const { targetLanguage, sourceLanguage } = await getTargetAndSourceLanguage();

return displayTranslationNotification(async (progress) => {
const increment = 100 / 2 / selections.length;
const translatedClipboardText = await deepl.translate(clipboardText, sourceLanguage, targetLanguage);
const translatedClipboardText = await deepl.translate(
clipboardText,
sourceLanguage,
targetLanguage
);
progress.report({ increment: increment * selections.length });

vscode.window.activeTextEditor?.edit((editor: vscode.TextEditorEdit) => {
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export const COMMAND_TRANSLATE = 'deepl.translate';
export const COMMAND_TRANSLATE_TO = 'deepl.translateTo';
export const COMMAND_TRANSLATE_FROM_TO = 'deepl.translateFromTo';
export const COMMAND_TRANSLATE_AND_PASTE_FROM_CLIPBOARD = 'deepl.translateAndPasteFromClipboard';
export const COMMAND_DUPLICATE_AND_TRANSLATE = 'deepl.duplicateAndTranslate';
export const COMMAND_SET_TARGET_LANGAUGE = 'deepl.setTargetLanguage';
6 changes: 5 additions & 1 deletion src/deepl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ const handleTranslationFailure = async <T extends string | string[]>(texts: T, r

export async function translate<T extends string | string[]>(texts: T, sourceLanguage: SourceLanguageCode | undefined, targetLanguage: TargetLanguageCode, retries: number = 1): Promise<T extends string ? TextResult : TextResult[]> {
const translator = createTranslator(state.apiKey!);
debug.write(
sourceLanguage
? `Start translating '${texts}' to '${targetLanguage}'`
: `Start translating '${texts}' from '${sourceLanguage}' to '${targetLanguage}'`
);
const results = await translator.translateText(
texts,
sourceLanguage ?? null,
Expand All @@ -82,7 +87,6 @@ export async function translate<T extends string | string[]>(texts: T, sourceLan
tagHandling: state.tagHandling || undefined
}
);

const wasTranslationSuccessful = typeof texts === "string"
? (results as TextResult).text !== texts
: (results as TextResult[]).filter((result, index) => result.text === texts[index]).length === 0;
Expand Down
5 changes: 3 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as vscode from 'vscode';
import { setup } from './state';
import { createStatusBarItem } from './status-bar';
import { configureSettings, translate, translateFromTo, translateTo, translateAndPasteFromClipboard, setTargetLangauge } from './commands';
import { COMMAND_CONFIGURE, COMMAND_TRANSLATE, COMMAND_TRANSLATE_FROM_TO, COMMAND_TRANSLATE_TO, COMMAND_TRANSLATE_AND_PASTE_FROM_CLIPBOARD, COMMAND_SET_TARGET_LANGAUGE } from './constants';
import { configureSettings, translate, translateFromTo, translateTo, translateAndPasteFromClipboard, setTargetLangauge, duplicateAndTranslate } from './commands';
import { COMMAND_CONFIGURE, COMMAND_TRANSLATE, COMMAND_TRANSLATE_FROM_TO, COMMAND_TRANSLATE_TO, COMMAND_TRANSLATE_AND_PASTE_FROM_CLIPBOARD, COMMAND_SET_TARGET_LANGAUGE, COMMAND_DUPLICATE_AND_TRANSLATE } from './constants';

export async function activate(context: vscode.ExtensionContext) {
await setup(context);
Expand All @@ -14,6 +14,7 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand(COMMAND_TRANSLATE_FROM_TO, translateFromTo));
context.subscriptions.push(vscode.commands.registerCommand(COMMAND_TRANSLATE_AND_PASTE_FROM_CLIPBOARD, translateAndPasteFromClipboard));
context.subscriptions.push(vscode.commands.registerCommand(COMMAND_SET_TARGET_LANGAUGE , setTargetLangauge));
context.subscriptions.push(vscode.commands.registerCommand(COMMAND_DUPLICATE_AND_TRANSLATE , duplicateAndTranslate));
}

export function deactivate() {}

0 comments on commit 200e1a7

Please sign in to comment.