I am using DeepL API to translate documents. As you can see in their documentation, after call the API with the file to translate, you can call an endpoint to know the state of the translation. This endpoint, returns an estimation of the remainding seconds. When this endopoint returns a state of "done", you can download the translated file.
I have managed to recursively call the endpoint to check the status of the translation and call download when the status is done. What I want now is to show a popup while the translation is being done. So I've added a showLoaderPopup state to true before the first call, but I need to wait for everything finished to set the state to false. The problem is that the call to the TranslateFile
method is returning before the file has been downloaded, so something inside the promises must not be well configured.
This is my code:
async TranslateFile(files: FileList, inputLang: string, outputLang: string){
const formData = new FormData();
if(inputLang) formData.append('source_lang', inputLang);
formData.append('target_lang', outputLang);
formData.append('file', files.item(0), files.item(0).name);
const documentType = files.item(0).type;
const requestOptions = this.getRequestFileOpt(formData);
return await this.getFileResponse(requestOptions, documentType);
}
// FUNCTION THAT SEND THE FILE TO TRANSLATE AND CALL RECURSIVE FUNC FOR THE FIRST TIME
async getFileResponse(requestOptions: RequestInit, documentType: string) {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
await fetch(`https://api.deepl.com/v2/document?auth_key=${apiKey}`, requestOptions)
.then(result => result.json())
.then(async (document: any) => {
await setTimeout(async() => {
return await this.checkDocumentTranslationState(document, documentType);
}, 2000);
})
}
// RECURSIVE FUNCTION TO CHECK TRANSLATION STATE
async checkDocumentTranslationState(document: any, documentType: string): Promise<boolean> {
const myHeaders = new Headers();
return await fetch(`https://api.deepl.com/v2/document/${document.document_id}?auth_key=${apiKey}&document_key=${document.document_key}`,{method: 'POST', headers: myHeaders})
.then(result => result.json())
.then(async (documentState: any) => {
if(documentState.status === "done")
return this.downloadToClient(await fetch(`https://api.deepl.com/v2/document/${document.document_id}/result?auth_key=${apiKey}&document_key=${document.document_key}`,{method: 'POST', headers: myHeaders}), documentType);
else if(documentState.status === "error") return false;
else {
let seconds_remaining = Number(documentState.seconds_remaining);
setTimeout(async () => {
return await this.checkDocumentTranslationState(document, documentType);
}, (seconds_remaining && !Number.isNaN(seconds_remaining) && (seconds_remaining < 5000)) ? (seconds_remaining) : 2000);
}
});
}
// FUNCTION TO DOWNLOAD FILE
async downloadToClient(response: any, documentType: string): Promise<boolean> {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
let fileName = "TranslatedFile";
if(documentType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") fileName += ".docx";
else if(documentType === "application/vnd.openxmlformats-officedocument.presentationml.presentation") fileName += ".pptx";
else if(documentType === "application/pdf") fileName += ".pdf";
else fileName += ".txt";
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
return true;
}
I think the main problem your facing is that your mixing up concepts with async await
and Promise then
. Try to stick to one and avoid using recursion.
I IMO cleaned up the code for you maybe now it's more understandable and easier to debug your error if it even exists anymore.
async TranslateFile(
files: FileList,
inputLang: string,
outputLang: string
): Promise<boolean> {
const formData = new FormData();
if (inputLang) formData.append("source_lang", inputLang);
formData.append("target_lang", outputLang);
formData.append("file", files.item(0), files.item(0).name);
const documentType = files.item(0).type;
const requestOptions = this.getRequestFileOpt(formData);
return await this.getFileResponse(requestOptions, documentType);
}
async getFileResponse(
requestOptions: RequestInit,
documentType: string
): Promise<boolean> {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
const result = await fetch(
`https://api.deepl.com/v2/document?auth_key=${apiKey}`,
requestOptions
);
const document = await result.json();
await this.awaiter(2000);
return await this.checkDocumentTranslationState(document, documentType);
}
async checkDocumentTranslationState(
document: any,
documentType: string
): Promise<boolean> {
const myHeaders = new Headers();
while (true) {
try {
const result = await fetch(
`https://api.deepl.com/v2/document/${document.document_id}?auth_key=${apiKey}&document_key=${document.document_key}`,
{ method: "POST", headers: myHeaders }
);
const documentState = await result.json();
if (documentState.status === "done") {
const response = await fetch(
`https://api.deepl.com/v2/document/${document.document_id}/result?auth_key=${apiKey}&document_key=${document.document_key}`,
{ method: "POST", headers: myHeaders }
);
const blob = await response.blob();
return this.downloadToClient(blob, documentType);
} else if (documentState.status === "error") {
return false;
} else {
const seconds_remaining = Number(documentState.seconds_remaining);
await this.awaiter(
seconds_remaining &&
!Number.isNaN(seconds_remaining) &&
seconds_remaining < 5000
? seconds_remaining
: 2000
);
}
} catch (e) {
console.log(e);
return false;
}
}
}
async downloadToClient(blob: Blob, documentType: string): Promise<boolean> {
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
let fileName = "TranslatedFile";
if (
documentType ===
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)
fileName += ".docx";
else if (
documentType ===
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
)
fileName += ".pptx";
else if (documentType === "application/pdf") fileName += ".pdf";
else fileName += ".txt";
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
return true;
}
awaiter(millis: number): Promise<void> {
return new Promise((res) => {
setTimeout(res, millis);
});
}