Google Cloud FunctionsからGoogle Cloud Translationを試してみる

前回、FirebaseでGoogle Cloud Functionsを使ってみました。

- [FirebaseのCloud FunctionsからGoogle Cloud Translationを試してみる](https://qiita.com/suzuki-navi/items/2600dc5c804daa4dc90c)

今回はFirebaseを使わずに、素のGoogle Cloud Functionsで同じ題材をやってみました。

# Cloud FunctionsのHello, World!

`function.js` という名前でJavaScriptのソースコードを書きます。

```javascript
exports.helloWorld = function (req, res) {
    console.log("Hello, console.log!");
    res.send('Hello, World!');
};
```

`function.js` という名前である必要があるみたいです。デプロイは以下のコマンド。

```console
$ gcloud functions deploy hello_world --runtime=nodejs12 --entry-point=helloWorld --trigger-http --allow-unauthenticated
```

デプロイ時にコンソールにこのCloud FunctionのURLが表示されますが、以下のようなURLです。

`https://us-central1-xxxxxxxx.cloudfunctions.net/hello_world`

このURLにブラウザでアクセスすると `Hello, World!` と表示されます。

Cloud Functionsのログを見てみます。

```console
$ gcloud functions logs read hello_world
LEVEL  NAME         EXECUTION_ID  TIME_UTC                 LOG
D      hello_world  jqwsqgteu8tt  2021-05-16 13:23:36.513  Function execution took 10 ms, finished with status code: 304
       hello_world  jqwsqgteu8tt  2021-05-16 13:23:36.511  Hello, console.log!
D      hello_world  jqwsqgteu8tt  2021-05-16 13:23:36.504  Function execution started
```

# Cloud FunctionsからCloud Translation APIを呼び出してみる

[前回](https://qiita.com/suzuki-navi/items/2600dc5c804daa4dc90c)の記事に書いたCloud Translation API有効化は完了済みとします。

`package.json` ファイルを用意します。内容は以下のみ。

```json
{
  "dependencies": {
    "@google-cloud/translate": "*"
  }
}
```

`function.js` の内容を以下のようにします。ほとんど[前回](https://qiita.com/suzuki-navi/items/2600dc5c804daa4dc90c)の記事のサンプルコードそのままです。

```javascript
const { TranslationServiceClient } = require("@google-cloud/translate").v3;

const projectId = "xxxxxxxx";
const location = "us-central1";

// 言語判定
async function detectLanguage(text) {
    const translationClient = new TranslationServiceClient();
    const req = {
        parent: translationClient.locationPath(projectId, location),
        content: text,
        mimeType: "text/plain"
    };
    const res = await translationClient.detectLanguage(req);
    let sourceLang = null;
    for (const elem of res) {
        if (elem == null) // なぜかnullがレスポンスに含まれる
            continue;
        return elem["languages"][0]["languageCode"];
    }
}

// 翻訳
async function translate(text, sourceLang, targetLang) {
    const translationClient = new TranslationServiceClient();
    const req = {
        parent: translationClient.locationPath(projectId, location),
        contents: [text],
        mimeType: "text/plain",
        sourceLanguageCode: sourceLang,
        targetLanguageCode: targetLang,
    };
    const res = await translationClient.translateText(req);
    for (const elem of res) {
        if (elem == null) // なぜかnullがレスポンスに含まれる
            continue;
        return elem["translations"][0]["translatedText"];
    }
}

async function sample(text) {
    const result = {};
    result["original"] = text;

    // 言語判定
    const sourceLang = await detectLanguage(text);

    // 翻訳
    for (const targetLang of ["en", "ja", "zh-TW", "zh-CN", "ko"]) {
        if (targetLang == sourceLang) // Target language can't be equal to source language. というエラーを防ぐため
            continue;
        const targetText = await translate(text, sourceLang, targetLang);
        result[targetLang] = targetText;
    }

    return result;
}

exports.helloWorld = async function (req, res) {
  sample("Hello, World!").then(result => {
    console.log(result);
    res.send(result);
  }).catch(err => {
    console.log(err);
  });
};
```

これをデプロイして、ブラウザでアクセスすると無事以下のように表示されました。

```
{"original":"Hello, World!","ja":"こんにちは世界！","zh-TW":"你好，世界！","zh-CN":"你好，世界！","ko":"안녕하세요, 세계!"}
```