Exercism-JS/translation-service
2022-05-16 20:52:30 -05:00
..
.exercism completed ozans-playlist, 2022-05-16 12:57:26 -05:00
.eslintignore completed ozans-playlist, 2022-05-16 12:57:26 -05:00
.eslintrc completed ozans-playlist, 2022-05-16 12:57:26 -05:00
.gitignore completed ozans-playlist, 2022-05-16 12:57:26 -05:00
.npmrc completed ozans-playlist, 2022-05-16 12:57:26 -05:00
api.js completed ozans-playlist, 2022-05-16 12:57:26 -05:00
babel.config.js completed ozans-playlist, 2022-05-16 12:57:26 -05:00
errors.js completed ozans-playlist, 2022-05-16 12:57:26 -05:00
global.d.ts completed ozans-playlist, 2022-05-16 12:57:26 -05:00
HELP.md completed ozans-playlist, 2022-05-16 12:57:26 -05:00
HINTS.md completed ozans-playlist, 2022-05-16 12:57:26 -05:00
LICENSE completed ozans-playlist, 2022-05-16 12:57:26 -05:00
package.json completed ozans-playlist, 2022-05-16 12:57:26 -05:00
README.md completed ozans-playlist, 2022-05-16 12:57:26 -05:00
service.js completed translation-service 2022-05-16 20:52:30 -05:00
service.spec.js completed ozans-playlist, 2022-05-16 12:57:26 -05:00
yarn.lock completed ozans-playlist, 2022-05-16 12:57:26 -05:00

Translation Service

Welcome to Translation Service on Exercism's JavaScript Track. If you need help running the tests or submitting your code, check out HELP.md. If you get stuck on the exercise, check out HINTS.md, but try and solve it without using those first :)

Introduction

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

The methods promise.then(), promise.catch(), and promise.finally() are used to associate further action with a promise that becomes settled.

For example:

const myPromise = new Promise(function (resolve, reject) {
  let sampleData = [2, 4, 6, 8];
  let randomNumber = Math.ceil(Math.random() * 5);
  if (sampleData[randomNumber]) {
    resolve(sampleData[randomNumber]);
  } else {
    reject('An error occured!');
  }
});

myPromise
  .then(function (e) {
    console.log(e);
  })
  .catch(function (error) {
    throw new Error(error);
  })
  .finally(function () {
    console.log('Promise completed');
  });

Methods

These methods are available on Promise.prototype

then

The .then() method takes up to two arguments; the first argument is a callback function for the resolved case of the promise, and the second argument is a callback function for the rejected case. Each .then() returns a newly generated promise object, which can optionally be used for chaining.1

const promise1 = new Promise(function (resolve, reject) {
  resolve('Success!');
});

promise1.then(function (value) {
  console.log(value);
  // expected output: "Success!"
});

catch

A .catch() is just a .then() without a slot for a callback function for the case when the promise is resolved. It is used to handle rejected promises.2

const promise1 = new Promise((resolve, reject) => {
  throw 'An error occured';
});

promise1.catch(function (error) {
  console.error(error);
});
// expected output: An error occured

finally

When the promise is settled, i.e either fulfilled or rejected, the specified callback function is executed. This provides a way for code to be run whether the promise was fulfilled successfully or rejected once the Promise has been dealt with.3

function findDataById(id) {
  return new Promise(function (resolve, reject) {
    let sampleData = [1, 2, 3, 4, 5];
    if (sampleData[id]) {
      resolve(sampleData[id]);
    } else {
      reject(new Error('Invalid id'));
    }
  });
}

findDataById(4)
  .then(function (response) {
    console.log(response);
  })
  .catch(function (err) {
    console.error(err);
  })
  .finally(function () {
    console.log('Promise completed');
  });

Instructions

In this exercise, you'll be providing a TranslationService that provides basic translation services to free members, and advanced translation to premium members with quality assurances.

The API

You have found an outer space translation API that fulfills any translation request in a reasonable amount of time. You want to capitalize on this. The space translators are extremely fickle and hate redundancy, so they also provide API storage satellites where you can fetch past translations without bothering them.

Fetching a translation

api.fetch(text) fetches a translation of text from the API storage and returns a promise that provides two values:

  • translation: the actual translation
  • quality: the quality expressed as a number

If a translation is not found in the API storage, the API throws a NotAvailable error. Translations can be added using the api.request method. If 'text' is not translatable, the API throws an Untranslatable error.

api.fetch('jIyaj');
// => Promise({ resolved: 'I understand' })

Requesting a translation

Some translations are sure to exist, but haven't been added to the API storage yet. That's the difference between NotAvailable ( not in storage, but can be requested ) and Untranslatable ( cannot be translated ).

api.request(text, callback) requests that a translation of text be performed and added into the API storage. On completion the callback function is called.

  • On success callback is passed undefined: this indicates the translation was successful and is accessible using the api.fetch method.
  • On failure callback is passed an error: this indicates something went wrong. The outspace API is unstable, which means that the API fails often. If that happens, it is okay to api.request again.
api.request('majQa');
// => Promise({ resolved: undefined })

⚠ Warning! ⚠

The API works its magic by teleporting in the various translators when a `request` comes in.
This is a very costly action, so it shouldn't be called when a translation *is* available.
Unfortunately, not everyone reads the manual, so there is a system in place to kick-out bad actors.

If an `api.request` is called for `text` is available, the API throws an `AbusiveClientError` for this call, **and every call after that**.
Ensure that you *never* request a translation if something has already been translated.

1. Fetch a translation, ignoring the quality

The free service only provides translations that are currently in the API storage.

Implement a method free(text) that provides free members with translation that already exist in the API storage. Ignore the quality and forward any errors thrown by the API. ``

  • Returns the translation if it can be retrieved, regardless of its quality
  • Forwards any error from the translation API
  • Uses the api.fetch method (api.fetch returns a promise)
service.free('jIyaj');
// => Promise<...> resolves "I understand."

service.free("jIyajbe'");
// => Promise<...> rejects Error("Not yet translated")

2. Fetch a batch of translations, all-or-nothing

Implement a method batch([text, text, ...]) for free members that translates an array of text using the free service, returning all the translations, or a single error.

  • Resolves with all the translations (in the same order), if they are all available
  • Rejects with the first error that is encountered
  • Rejects with a BatchIsEmpty error if no texts are given
service.batch(['jIyaj', "majQa'"]);
// => Promise<...> resolves ["I understand.", "Well done!"]

service.batch(['jIyaj', "jIyajbe'"]);
// => Promise<...> rejects new Error("Not yet translated")

service.batch([]);
// => Promise<...> rejects BatchIsEmpty()

3. Request a translation, retrying at most 2 times

Implement a premium user method request(text), that requests a translation be added to the API storage. The request should automatically retry if a failure occurs.
It should perform no more than 3 calls for the same request (don't upset the space translators!!!).

  • If api.request does not return an error, resolve with undefined
  • If api.request returns an error, retry at most two times
  • If you run out of retries, reject with the last error received
service.request("jIyajbe'");
// => Promise<...> resolves (with nothing), can now be retrieved using the fetch API

4. Fetch a translation, inspect the quality, or request it

Implement a premium user method premium(text, quality) to fetch a translation. If a translation is NotAvailable, request the translation and fetch it after its been added to the API storage. The method should only return the translation if it meets a certain quality threshold.

  • If api.fetch resolves, check the quality before resolving
  • If api.fetch rejects, request the translation instead
  • If api.request rejects, forward the error
service.premium("jIyajbe'", 100);
// => Promise<...> resolves "I don't understand."

service.premium("'arlogh Qoylu'pu'?", 100);
// => Promise<...> rejects QualityThresholdNotMet()

service.premium("'arlogh Qoylu'pu'?", 40);
// => Promise<...> resolves "What time is it?"

N.B.

The correct translation of `'arlogh Qoylu'pu'?` is **How many times has it been heard?**.

Source

Created by

  • @SleeplessByte

Contributed to by

  • @AndrewLawendy