Help us understand the problem. What is going on with this article?

日本語で書かれたLocalizable.stringをGoogle Translation APIで翻訳してstructファイルを自動作成するツールをgolangで作る

はじめに

以前Qiitaの記事でも書いた「Go言語でiOS開発ツールを作成する:Localizable.stringsファイルからenumを生成する」というツールを拡張して、

「日本語で書かれたLocalizable.stringをGoogle Translation APIで翻訳してstructファイルを自動作成するツールをgolangで作る」

ことに挑戦してみました。

挑戦結果のGitHubリポジトリーはこちら
https://github.com/BlueEventHorizon/EnumGenerator

結果

例えば下記のようなLocalizable.stringがあったとすると、

"あなたの心が正しいと思うことをしなさい。どっちにしたって批判されるのだから。" = "あなたの心が正しいと思うことをしなさい。どっちにしたって批判されるのだから。";
"前進をしない人は、後退をしているのだ。" = "前進をしない人は、後退をしているのだ。";
"どんなに悔いても過去は変わらない。どれほど心配したところで未来もどうなるものでもない。いま、現在に最善を尽くすことである。" = "どんなに悔いても過去は変わらない。どれほど心配したところで未来もどうなるものでもない。いま、現在に最善を尽くすことである。";
"最も重要な決定とは、何をするかではなく、何をしないかを決めることだ。" = "最も重要な決定とは、何をするかではなく、何をしないかを決めることだ。";
"人生は楽ではない。そこが面白い。" = "人生は楽ではない。そこが面白い。";
"自分で自分をあきらめなければ、人生に「負け」はない。" = "ダイアログを自分で自分をあきらめなければ、人生に「負け」はない。";

生成結果は以下のようになりました。

Swift
import Foundation

struct LocalizableStrings {
    static let doWhatYouThinkIsRightBecauseYouAre = "あなたの心が正しいと思うことをしなさい。どっちにしたって批判されるのだから。"
    static let thoseWhoDoNotMoveForwardAreMovingBackwards = "前進をしない人は、後退をしているのだ。"
    static let thePastDoesntChangeNoMatterHowMuch = "どんなに悔いても過去は変わらない。どれほど心配したところで未来もどうなるものでもない。いま、現在に最善を尽くすことである。"
    static let theMostImportantDecisionIsNotWhatYou = "最も重要な決定とは、何をするかではなく、何をしないかを決めることだ。"
    static let lifeIsNotEasyThatIsInteresting = "人生は楽ではない。そこが面白い。"
    static let ifYouDontGiveUpYourselfThereIsNoLosing = "自分で自分をあきらめなければ、人生に「負け」はない。"
}

そもそも Localizable.string の記述が変❗️というのは置いておいてください・・・

翻訳

go言語を使ってGoogle Cloud Platformを利用するのはSwiftよりも有利です。それは、Googleから

  • 十分なサンプルソースコードが提供されている。
  • go言語用のライブリが提供されている。

からです。
サンプルソースコードは下記から入手することができます。

https://github.com/GoogleCloudPlatform/golang-samples

またこのサンプルソースコード内で利用されているライブラリは、
下記のように組み込むことができます。

Shell
$ go get -u cloud.google.com/go/translate
$ go get -u golang.org/x/text/language
$ go get -u google.golang.org/api/option

このライブラリを利用すると、go言語からは下記のようにシンプルなコードで済んでしまいます。

Go
func TranslateText(targetLanguage, text string) (string, error) {
    ctx := context.Background()

    lang, err := language.Parse(targetLanguage)
    if err != nil {
        return "", err
    }

    client, err := translate.NewClient(ctx)
    if err != nil {
        return "", err
    }
    defer client.Close()

    resp, err := client.Translate(ctx, []string{text}, lang, nil)
    if err != nil {
        return "", err
    }
    result := resp[0].Text
    return result, nil
}

Google Translation APIを利用するには

Quickstart (Basic)
https://cloud.google.com/translate/docs/basic/setup-basic

から簡単に始めることができます。

  • GCP Console プロジェクトをセットアップする
  • 環境変数 GOOGLE_APPLICATION_CREDENTIALS を設定する

GCP Console プロジェクトをセットアップは上記のリンクから行えます。
またGOOGLE_APPLICATION_CREDENTIALSに設定すべき「サービスアカウントキーをが含むJSON」も上記で入手できますので、例えばmacの場合だと自分のホームディレクトリに置き、下記のようにタイプすると一時的に使用可能になります。

Shell
$ export GOOGLE_APPLICATION_CREDENTIALS=~/xxxxxx.json

恒久的に設定するには、bash環境であれば、 .bashrc や、 .bash_profile に書き込みましょう。

VSCodeでのデバッグ

VSCodeでは、上記のシェル環境のGOOGLE_APPLICATION_CREDENTIALSが有効では無いために、別途設定が必要です。
macであれば、.vscodeの下に、launch.jsonというファイルができれいるはずなので、

launch.json

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "env": {
                "GOOGLE_APPLICATION_CREDENTIALS": "クレデンシャルへのフルパス/xxxxx.json"
            },
            "args": [""]
        }
    ]
}

"env"にクレデンシャルへのフルパスで書きます。なぜか、 ~/xxxxx.json というような記法ではダメなようです。

追記2020/01/19
${env:HOME}/xxxxx.jsonでうまく行きます。mizutoki79さん、ありがとうございました。

go言語のサンプルソースコードについて

多すぎて書ききれないので割愛します。
こちらを見るだけでその多さがわかると思います。

https://github.com/GoogleCloudPlatform/golang-samples

Swiftのサンプルソースコードについて

サンプルソースコードは提供されています。
下記から入手可能です。

https://github.com/GoogleCloudPlatform/ios-docs-samples

しかしながら現在のところはサンプルソースコードが存在するサービスはそれほど多くはないようです。
go言語と違って直ぐ書けます😭

サービス 説明
speech Samples that demonstrate the Cloud Speech API.
dialogflow Samples that demonstrate the Dialogflow API.
solutions Samples that demonstrate systems built on Google Cloud Platform.
screensaver A screensaver that features Google Cloud Platform products.
text-to-speech Samples that demonstrate the Cloud Text to Speech API.
natural-language Samples that demonstrate the Cloud Natural language

後処理

翻訳結果だけを見ると以下のようになっていました。

 Do what you think is right. Because you are criticized for either. <== "あなたの心が正しいと思うことをしなさい。どっちにしたって批判されるのだから。"
 Those who do not move forward are moving backwards. <== "前進をしない人は、後退をしているのだ。"
 The past doesn&#39;t change no matter how much you regret. No matter how worried you are, what will happen to the future. Now, do your best now. <== "どんなに悔いても過去は変わらない。どれほど心配したところで未来もどうなるものでもない。いま、現在に最善を尽くすことである。"
 The most important decision is not what you do, but what you do. <== "最も重要な決定とは、何をするかではなく、何をしないかを決めることだ。"
 Life is not easy. That is interesting. <== "人生は楽ではない。そこが面白い。"
 If you don&#39;t give up yourself, there is no “losing” in your life. <== "自分で自分をあきらめなければ、人生に「負け」はない。"

キャメルケースにするためのコードは既に作成済みですが、Google Translation APIの結果に使用できない文字が多く含まれています。
スペースや、ブランク、'や“”もあります。
これらを削除、または置換していく必要があります。
go言語では文字列置換のための関数が用意されていますので、下記のようなコードを書くことで、これらの不要な文字を削除・置換することが容易です。

Go
replacer := strings.NewReplacer(" ", "_", ".", "_", "+", "_", "-", "_")
keyword = replacer.Replace(keyword)

replacer = strings.NewReplacer("\"", "", "?", "", "!", "", "“", "", "”", "", ":", "", "[", "", "]", "", "`", "", "'", "")
keyword = replacer.Replace(keyword)

replacer = strings.NewReplacer("#", "", "$", "", "%", "", "=", "", "@", "", "\\", "", "(", "", ")", "", ",", "", "/", "")
keyword = replacer.Replace(keyword)

replacer = strings.NewReplacer("&39;", "", "&amp;", "", "&quot;", "")
keyword = replacer.Replace(keyword)

keyword = strings.Replace(keyword, ";", "", -1)

keyword = convertToCamelCase(keyword)

また、単純に全ての翻訳結果を採用してしまうとものすごく長い変数名になってしまうので、どこかで断ち切る必要があります。意味的に良い場所で断ち切るのは至難の技ですので、文字数で制限することにします。

しかし、単語の途中でブツ切れるのはかっこよくありません。
そこで、キャメルケースを生成する関数を手直しして下記のように変更しました。

Go

func convertToCamelCase(text string) string {
    if text == "" {
        return text
    }

    var keyword string
    var foundUnderScore = false
    for i := 0; i < len(text); i++ {
        letter := text[i : i+1]
        if letter == "_" {
            // ====== ここで文字数制限する ======
            if i > 40 {
                break
            }
            foundUnderScore = true
            continue
        }
        if foundUnderScore {
            foundUnderScore = false
            keyword = keyword + strings.ToUpper(letter)
        } else {
            keyword = keyword + letter
        }
    }

    head := keyword[:1]
    rest := keyword[1:]
    keyword = strings.ToLower(head) + rest

    return keyword
}

まとめ

go言語は、C/C++に近いローレベル(いろんな意味で)の言語でありながら、ライブラリのパワーが凄まじいと思います。
単なるローカルなツール作成だけではなく、サーバサイドでも大活躍する言語ですので、Objective-Cに慣れ親しんだ‼️iOSエンジニアの方は一度試してみてはいかがでしょうか。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした