仕事でちょっとした翻訳(辞書)APIが欲しくて色々と吟味した結果 MS Translator API がよさそうとなったので使ってみました。

ちなみに他の候補としては

  • Google Translate API
  • デ辞蔵

がありましたが、前者は料金、後者はAPIがイケてないという理由で却下しました。

先に参考にしたページなど

大まかな流れ

基本的に上に書いた Getting Started… の通りに進めます

Access Token 取得のための key が何を指すのかわかりづらいですが、 Getting Started / Microsoft Cognitive Services を見ればもう少しわかりやすく書いてあり、 [All Services] -> subscribe している Translator API -> [Keys] にいくと

  • ACCOUNT NAME
  • KEY 1
  • KEY 2

とあり、 KEY 1 ないしは KEY 2 が Subscription Key となります。わかりづらい

認証

Authentication Token API for Microsoft Cognitive Services Translator API / Microsoft Cognitive Services を見ればわかりますが、 POST で https://api.cognitive.microsoft.com/sts/v1.0/issueToken にリクエストを送れば Access Token が手に入ります。

有効期限は 10 分と短めです。

ヘッダーに Ocp-Apim-Subscription-Key: <your-key> を埋め込むか、 URL のパラメターとして ?Subscription-Key=<your-key> を含めるかで送れます。

Ruby で書くと以下のようになります

require 'net/http'

SUBSCRIPTION_KEY = 'your-key'
ACCESS_TOKEN_URL = 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken'

uri = URI(ACCESS_TOKEN_URL)
req = Net::HTTP::Post.new(uri)
req['Ocp-Apim-Subscription-Key'] = SUBSCRIPTION_KEY

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(req)
end

res.body

今まで横着して Faraday やら HTTParty を使ってましたが、今回 net/http 使ってみました

これで十分ですね :smiley:

翻訳 API を叩く

  • 1つの text だけ翻訳: http://api.microsofttranslator.com/V2/Http.svc/Translate
  • 複数の text を翻訳: http://api.microsofttranslator.com/V2/Http.svc/TranslateArray

多分後者を使いたくなることの方が多いんじゃないかと思うので、ここでは後者のみサンプルコードを置いておきます

require 'net/http'
require 'rexml/document'

TRANSLATE_ARRY_URL = 'http://api.microsofttranslator.com/V2/Http.svc/TranslateArray'

# さっき取得した access token
token = 'xxx'

uri = URI(TRANSLATE_ARRY_URL)
req = Net::HTTP::Post.new(uri)

texts = words.map { |w|
  "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">#{w}</string>"
}.join

# en -> ja を想定してます
# option も設定できますが、今回は割愛します
xml_body = <<~BODY
  <TranslateArrayRequest>
    <AppId />
    <From>en</From>
    <Texts>#{texts}</Texts>
    <To>ja</To>
  </TranslateArrayRequest>
BODY
req.body = xml_body

req['Authorization'] = "Bearer #{token}"
req.content_type = 'text/xml'

res = Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(req) }

doc = REXML::Document.new(res.body)

exit unless doc.root.elements['TranslateArrayResponse']

results = doc.root.elements.collect('TranslateArrayResponse') do |e|
  e.elements['TranslatedText']&.text
end

puts results

XML ってのがイケてないですが、今回は目を瞑ります。仕方ない!

意外と少ないコードで実現できるのでよかったです。

日々更新はしていくかもしれませんが、 Translate のコードも見たい場合は 自分の gist を見てください

いやはや便利だ