Skip to content

Commit

Permalink
Improved authentication handling (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
soerenuhrbach authored Mar 8, 2024
1 parent b8ce30c commit 627c0f0
Showing 1 changed file with 94 additions and 32 deletions.
126 changes: 94 additions & 32 deletions src/deepl.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as vscode from 'vscode';
import * as debug from './debug';
import { state } from './state';
import { Language, SourceLanguageCode, TargetLanguageCode, TextResult, Translator } from 'deepl-node';
import { EXTENSION_IDENTIFIER } from './constants';
import { showSourceLanguagePrompt, showTargetLanguagePrompt } from './prompts';
import { showApiKeyPrompt, showSourceLanguagePrompt, showTargetLanguagePrompt } from './prompts';
import { AuthorizationError, Language, SourceLanguageCode, TargetLanguageCode, TextResult, Translator } from 'deepl-node';

enum ResolveUnsuccessfulTranslationActions {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand All @@ -12,6 +12,11 @@ enum ResolveUnsuccessfulTranslationActions {
CHANGE_TARGET_LANGUAGE = 'Change target language and try again'
}

enum ResolveAuthenticationError {
// eslint-disable-next-line @typescript-eslint/naming-convention
CHANGE_API_KEY = 'Change api key and try again'
}

const cache = {
targetLanguages: [] as readonly Language[],
sourceLanguages: [] as readonly Language[],
Expand Down Expand Up @@ -65,38 +70,77 @@ const handleTranslationFailure = async <T extends string | string[]>(texts: T, r
return results;
};

const handleAuthorizationFailure = async (): Promise<{ apiKeyUpdated: boolean }> => {
let apiKeyUpdated = false;

const selectedAction = await vscode.window.showWarningMessage(
'Authentication failed!',
{
detail: 'Please check if you are api key correct.',
modal: true
},
ResolveAuthenticationError.CHANGE_API_KEY
);

if (selectedAction === ResolveAuthenticationError.CHANGE_API_KEY) {
const newApiKey = await showApiKeyPrompt();
if (newApiKey && newApiKey !== state.apiKey) {
apiKeyUpdated = true;
state.apiKey = newApiKey;
}
}

return { apiKeyUpdated };
};

export async function translate<T extends string | string[]>(texts: T, sourceLanguage: SourceLanguageCode | undefined, targetLanguage: TargetLanguageCode, retries: number = 1): Promise<T extends string ? TextResult : TextResult[]> {
if (!state.apiKey) {
state.apiKey = await showApiKeyPrompt();
}

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,
targetLanguage,
{
formality: state.formality || undefined,
glossary: state.glossaryId || undefined,
ignoreTags: state.ignoreTags || undefined,
nonSplittingTags: state.nonSplittingTags || undefined,
splittingTags: state.splittingTags || undefined,
preserveFormatting: state.preserveFormatting || undefined,
splitSentences: state.splitSentences || undefined,
tagHandling: state.tagHandling || undefined

try {
const results = await translator.translateText(
texts,
sourceLanguage ?? null,
targetLanguage,
{
formality: state.formality || undefined,
glossary: state.glossaryId || undefined,
ignoreTags: state.ignoreTags || undefined,
nonSplittingTags: state.nonSplittingTags || undefined,
splittingTags: state.splittingTags || undefined,
preserveFormatting: state.preserveFormatting || undefined,
splitSentences: state.splitSentences || undefined,
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;

return !wasTranslationSuccessful && retries > 0
? handleTranslationFailure(texts, results, sourceLanguage, targetLanguage, retries - 1)
: results;
} catch (e: unknown) {
if (e instanceof AuthorizationError && retries > 0) {
const { apiKeyUpdated } = await handleAuthorizationFailure();
if (apiKeyUpdated) {
return translate(texts, sourceLanguage, targetLanguage, retries - 1);
}
}
);
const wasTranslationSuccessful = typeof texts === "string"
? (results as TextResult).text !== texts
: (results as TextResult[]).filter((result, index) => result.text === texts[index]).length === 0;

return !wasTranslationSuccessful && retries > 0
? handleTranslationFailure(texts, results, sourceLanguage, targetLanguage, retries)
: results;
throw e;
}
}

export async function getTargetLanguages() {
export async function getTargetLanguages(retries: number = 1) {
if (!state.apiKey) {
debug.write('Could not load target languages - api key is not configured!');
return [];
Expand All @@ -106,13 +150,22 @@ export async function getTargetLanguages() {
return cache.targetLanguages;
}

const translator = createTranslator(state.apiKey);
const languages = await translator.getTargetLanguages();
cache.targetLanguages = languages;
return languages;
try {
const translator = createTranslator(state.apiKey);
cache.targetLanguages = await translator.getTargetLanguages();
} catch (e: unknown) {
if (e instanceof AuthorizationError && retries > 0) {
const { apiKeyUpdated } = await handleAuthorizationFailure();
if (apiKeyUpdated) {
return getTargetLanguages(retries - 1);
}
}
}

return cache.targetLanguages;
}

export async function getSourceLanguages() {
export async function getSourceLanguages(retries: number = 1) {
if (!state.apiKey) {
debug.write('Could not load source languages - api key is not configured!');
return [];
Expand All @@ -122,8 +175,17 @@ export async function getSourceLanguages() {
return cache.sourceLanguages;
}

const translator = createTranslator(state.apiKey);
const languages = await translator.getSourceLanguages();
cache.sourceLanguages = languages;
return languages;
try {
const translator = createTranslator(state.apiKey);
cache.sourceLanguages = await translator.getSourceLanguages();
} catch (e) {
if (e instanceof AuthorizationError && retries > 0) {
const { apiKeyUpdated } = await handleAuthorizationFailure();
if (apiKeyUpdated) {
return getSourceLanguages(retries - 1);
}
}
}

return cache.sourceLanguages;
}

0 comments on commit 627c0f0

Please sign in to comment.