Cloud Translation API Version3(v3beta1)をPHPから。

Google Translation APIを使おうと

翻訳といえば最近だとGoogle翻訳、Google翻訳な私です。
昔はエキサイト翻訳だったりGoo翻訳だったり・・・だった記憶がありますが
それももはや遠い記憶です。
Googleさんの場合ここらへんのAPIがたくさんあるし、MLやAIで精度を高めたりしてくれているので

こりゃいいや

で早速、PHPのライブラリをば頂きに参ったのです。

が・・・

https://cloud.google.com/translate/docs/quickstart-client-libraries-v3?hl=ja

・・・・・・・・・

・・・・・・・・・

・・・・

・・

え・・・

PHPどこ?

ベータ版だからないのだろうか?

もしかしてベータ版だから今一番HOTな言語でしかライブラリがないのだろうか?
そうだとすると待っておくと言う手もあります。
そもそもベータ版ですから仕様はちょこちょこと変更されてしまうので。
でも使ってみたいですよね

なのでREST APIを叩けるように実装しました。

第一の関門 POSTやGETを投げる。


PHPには非常に便利な関数が存在しております。
いや・・・cURL使えって話でしょうけど便利だからついつい使っちゃいます。
API叩くなら特にcURLにしなさいよと言われるんですがそれでも私は・・・

file_get_contentsを愛してやみません。
ローカルのファイルはもちろんまさか・・・URL越しのデータを取得したり、
POSTやらまでできてしまう万能感を愛してやみません。
もちろん気に食わない方はその部分をcURLにすることもよろしいかと。

ちなみにGoogleCloudPlatformにて

「Cloud Translation API」を有効にして、認証情報で「サービスアカウントキーのJSON」バージョンは先に作っておきましょう。

では早速作ってみましょう。

class HttpClient {
protected $_url;
function __construct($url = null) {
$this->_url = $url;
}
public function get($data = array(), $head = array()) {

if ($data) {
$getd = http_build_query($data, "". "&");
}
if ($head) {
$sendHeader = $head;
}
else {
$sendHeader = array(
            'Cache-Control: no-store',
"Content-Type: application/x-www-form-urlencoded",
);
}


$context = array(
"http" => array(
"protocol_version" => "1.1",
"method" => "GET",
"header" => implode("\r\n", $sendHeader),
"ignore_errors" => true
)
);

if ($getd) {
$response = file_get_contents($this->_url . "?{$getd}", false, stream_context_create($context));
}
else {
$response = file_get_contents($this->_url, false, stream_context_create($context));
}
$pos = strpos($http_response_header[0], '200');
if ($pos === false) {
return array(
'status' => 'error',
'error' => $http_response_header[0],
'responce_header' => implode("\n", $http_response_header),
'body' => $response,
);
}
else {
return array(
'status' => 'success',
'body' => $response
);
}
}

public function post($data, $head = array() , $modeJson = false) {
$postd = http_build_query($data, "", "&");
if ($head) {
$sendHeader = $head;
if ($modeJson) {
$postd = $data;
}
else {
$sendHeader[] = "Content-Length: " . strlen($posted);
}
}
else {
$sendHeader = array(
            'Cache-Control: no-store',
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: " . strlen($postd),
);
}
$context = array(
"http" => array(
"protocol_version" => "1.1",
"method" => "POST",
"header" => implode("\r\n", $sendHeader),
"content" => $postd,
"ignore_errors" => true
)
);
$response = file_get_contents($this->_url, false, stream_context_create($context));
$pos = strpos($http_response_header[0], '200');
if ($pos === false) {
return array(
'status' => 'error',
'error' => $http_response_header[0],
'responce_header' => implode("\n", $http_response_header),
'body' => $response,
);
}
else {
return array(
'status' => 'success',
'body' => $response
);
}

}
}

と言うことでHTTPでGETとPOSTするのができました。

JWT(JsonWebToken)を使おう。

OAuth2ではJWTと使ってTokenを取得することにします。
ということでネットのソースやら何やらを色々参考にしながら必要最低限、
JWTを作れるものを

class JWT {
public $_support =  array(
"HS256" => array("hash_hmac", "sha256"),
"HS512" => array("hash_hmac", "sha512"),
"HS384" => array("hash_hmac", "sha384"),
"RS256" => array("openssl", "sha256"),
"RS384" => array("openssl", "sha384"),
"RS512" => array("openssl", "sha512"),
);
protected $_key;

function __construct($key) {
$this->_key = $key;
}
public function encode($body, $header = array("typ" => "JWT", "alg" => "RS256")) {
$iat = time();
$exp = $iat + 3600;

$head = $this->urlsafeB64Encode(json_encode($header));
$body['iat'] = $iat;
$body['exp'] = $exp;
$payload = $this->urlsafeB64Encode(json_encode($body));
$signing = $this->sign($head . "." . $payload);
return $head . "." . $payload . "." . $this->urlsafeB64Encode($signing);
}
protected function sign($msg, $alg = 'RS256') {
if (empty($this->_support[$alg])) {
throw new Exception("error no JWT algorithm");
}
list($func, $algorithm) = $this->_support[$alg];
if ($func == "hash_hmac") {
return hash_hmac($algorithm, $msg, $this->_key, true);
}
else if ($func == "openssl") {
$s = '';
$success = openssl_sign($msg, $s, $this->_key, $algorithm);
if ($success) {
return $s;
}
else {
throw new Exception("open ssl sign error.");
}
}
}
public function urlsafeB64Decode($input){ 
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
public function urlsafeB64Encode($input) {
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
}
作成しました。
うん・・・Excaptionとかの甘さが際立ってます。
申し訳ない。申し訳ない限りです。

GoogleとのOAuth2


GoogleのAPIを叩くにはこのOAuth2を叩いて認証し、そして
一時的なTokenを発行してもらう必要があります。
受け取ったTokenをHeadの要素に付けることでAPIは叩けるようになります。
もちろん最初に発行したサービスアカウントに適切な権限が必要にないりますのでその点はご注意を
さて・・・では・・・

class GoogleOAuth2 {
protected $_scope;
protected $_json;
protected $_token;
protected $_grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";

function __construct($scope, $jsonKey) {
$this->_scope = $scope;
$this->_json = json_decode($jsonKey, true);
}
public function token() {
$jwt = new JWT($this->_json['private_key']);
$jwtData = $jwt->encode(array("iss" =>  $this->_json['client_email'],"aud" => $this->_json['token_uri'],"scope" => $this->_scope));
$client = new HttpClient($this->_json['token_uri']);
$body = $client->post(array('grant_type' => $this->_grantType,'assertion' =>$jwtData));
error_log(var_export($body, true));
if (empty($body['body'])) {
throw Exception("not token");
}
return json_decode($body['body'], true);
}
}

JWT形式のデータを送って、認証を確立し、Tokenをもらいます。

翻訳しようじゃないか

早速翻訳です。
まぁ色々なやり方があるのですが一番シンプルに。

class GoogleTranslate {
const SCOPE = "https://www.googleapis.com/auth/cloud-translation";
const BASEURL = "https://translation.googleapis.com/v3beta1/projects/";
protected $_sourceJson;
protected $_json;
protected $_source;
protected $_target;
function __construct($json, $source = "ja", $target = "en") {
$this->_sourceJson = $json;
$this->_json = json_decode($json, true);
$this->_source = $source;
$this->_target = $target;
}
public function translation($text) {
$google = new GoogleOAuth2(self::SCOPE, $this->_sourceJson);
$token = $google->token();
$url = self::BASEURL . $this->_json['project_id'] . ":translateText";
$xiclient = new HttpClient($url);
$httpHeader[] = "Authorization: Bearer " . $token['access_token'];
$httpHeader[] = "Content-type: application/json; charset=utf-8";

$request = array(
"sourceLanguageCode" => $this->_source,
"targetLanguageCode" => $this->_target,
"contents" => $text
);
$reqjson = json_encode($request);
$translate = $xiclient->post($reqjson, $httpHeader, true);
$translateArr = json_decode($translate['body'], true);
return $translateArr;
}
}

こうしました。

これを一枚のPHPのなかに押し込んでます。
それがいいか悪いかはまぁ・・・別として・・・

使ってみよう。

では使ってみましょう。

まずはGCPから取得しておいたサービアカウントの「JSON」ファイルを読みます。

このときもfile_get_contentsで取得してしまいましょう。
PHPで一番楽だな・・・と思うのはこの関数のおかげです・・・はい。

で使うときはこうです。

$file = "XXXXXXX.json"; ← GCPで取得した「サービスアカウントキー」のJSON
$json = file_get_contents($file);
$googleTranslate = new GoogleTranslate($json);
$text = array(
'こんにちは',
'オッス!オラ悟空!',
'オラ腹減ったぞ!'
);
$d = $googleTranslate->translation($text);

結果は以下になりました。

array(1) {
["translations"]=>
array(3) {
[0]=>
array(1) {
["translatedText"]=>
string(5) "Hello"
}
[1]=>
array(1) {
["translatedText"]=>
string(14) "Oss! Ora Goku!"
}
[2]=>
array(1) {
["translatedText"]=>
string(15) "I'm hungry!"
}
}
}

あくまでサンプルでございますがとりあえず
翻訳はできます。


エラー処理やらなにやらは、是非ご利用頂く方々で実装をよろしくお願いいたします・・・
ライブラリがはやく提供されますように。

2019-10-31 17:21:03

Writer:ゆたさん

HomePagehome Twitter Facebook
「Cloud Translation API Version3(v3beta1)をPHPから。」をシェアしませんか?

最新ページ

  • プログラマーの美徳

    プログラマーには三大美徳があります。この三大美徳を言い始めたのは、「Larry Wall」氏でございます。Perlの生みの親としても大変有名人ですね。美徳・・・...
  • User-AgentがなくなるのでUser-Agent Client Hints(UA-CH)がやってくる話

    ユーザーエージェントが無くなるかもしれない・・・が来年になりそうですが、実際にやってくる感じをひしひしと感じています。前回のエージェントが無くなる件について・・...
  • ThinkPad トラックポイント キーボード II

    6月はじめに予約してたんですがようやく届きました。先週の金曜日ぐらいに。有線に比べて重い(当たり前)以前の有線のものをずっと使ってました。ずっと使っていたと言い...
  • 今後のNagareに追加しようとしていることなど・・・

    まずはゲームです現在開発中のゲームを兎にも角にも完成させなければなりません。今現在の進捗ですと予定していた7月のベータテストはいつの間にか アルファテスト1 ぐ...
  • FF7Rを初めてFF7オリジナルをやりたくなるなど。

    FF7Rの次はまだか次はまだですかね?オリジナルを少し遊んでみたくなりました。なつかしい。で自分的に色々忘れている(忘らるる都)なので、ここにメモがてらやること...