株式会社ライブキャストロゴ 株式会社ライブキャスト

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(クリップボードを監視編)の続きです。

前回、実装していなかったgoogle翻訳API呼び出しの部分を実装していきたいと思います。

flashcast:フリーで働くITエンジニア集団のブログ: ActionScript3.0でJSONを読み込む方法を参考に思い出しながら、実装しました。方法、内容はあまり変わっていません。

as3corelibが新しくなっていましたので、最新のas3corelib-.92.1.zipをダウンロードして利用しています。

APIを呼び出す部分は、別クラスにしました。

package
{
	import com.adobe.serialization.json.JSON;

	import flash.net.URLVariables;

	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;

	public class TranslateManager
	{
		private var service:HTTPService;

		public function TranslateManager()
		{
		}

		public function initTranslateManager():void {
			service = new HTTPService();
			service.url = "http://ajax.googleapis.com/ajax/services/language/translate";
			service.method = "post";
			service.addEventListener(ResultEvent.RESULT, onResult);
			service.addEventListener(FaultEvent.FAULT, onFault);
		}

		public function Translate(v:String, q:String, languageFrom:String, languageTo:String):void {
			var forms:URLVariables = new URLVariables();

			forms.v = v;
			forms.q = q;
			forms.format = "text";
			forms.langpair = languageFrom + "|" + languageTo;
			service.request = forms;
			service.send();
		}

		private function onResult(event:ResultEvent):void {
			var json:Object = JSON.decode(event.result.toString());

			if (json.responseStatus == 200) {
				if (json.responseData.translatedText != "") {
					trace(json.responseData.translatedText);
				}
				else {
					trace("翻訳失敗...");
				}
			}
			else {
				trace("翻訳失敗...");
			}
		}

		private function onFault(event:FaultEvent):void {
			trace("翻訳失敗...n" + event.fault.message);
		}

	}
}
翻訳結果のフォーマットを指定するために、32行目のようにformatパラメータを渡します。デフォルトはhtmlでエンコーディングされた結果が得られます。今回は、ブラウザに表示するわけではないのでtextにしています。

とりあえず、値が変わったときにAPIを呼び出すようにしたので、メインのロジックには、上記クラスのインスタンスを生成して、関数をコールする部分を追加しています。

package
{
	import mx.binding.utils.ChangeWatcher;
	import mx.core.Application;
	import mx.events.PropertyChangeEvent;

	public class TranslatorSample4Base extends Application
	{
		private var imanager:IconManager;
		private var cmanager:ClipboardManager;
		private var gmanager:TranslateManager;

		private var gmodel:TranslateModel;

		public function TranslatorSample4Base():void {
		}

		public function initApp():void {
			gmodel = new TranslateModel();

			imanager = new IconManager();
			cmanager = new ClipboardManager();
			gmanager = new TranslateManager();

			imanager.initIconManager();
			cmanager.initClipboardManager(gmodel);
			gmanager.initTranslateManager();

			ChangeWatcher.watch(gmodel, '_original', onClipboardChangeHandler);
		}

		private function onClipboardChangeHandler(event:PropertyChangeEvent):void {
			gmanager.Translate("1.0", gmodel.Original, "en", "ja");
		}
	}
}

それと、前回まではカスタムイベントクラスを作って、そのイベントが発生した際に翻訳にいくようにしていました(上記ソースの29行目のところです)。

cmanager.addEventListener(TranslatorSampleEvent.CLIPBOARD_CHANGE, onClipboardChangeHandler);

ここは、ChangeWatcherクラスを利用することにしました。

ChangeWatcher クラスは、バインド可能な Flex プロパティと共に使用できるユーティリティメソッドを定義します。 これらのメソッドを使用すると、バインド可能プロパティが更新されるたびに実行されるイベントハンドラを定義できます。

ChangeWatcher – ActionScript 3.0 言語およびコンポーネントリファレンスより引用。

ということで、この部分を以下のようにしています。

ChangeWatcher.watch(gmodel, '_original', onClipboardChangeHandler);

このために、新たにModelクラスを作成しました。

package
{
	[Bindable]
	public class TranslateModel
	{
		public var _original:String;

		public function TranslateModel()
		{
		}

		public function set Original(original:String):void {
			_original = original;
		}

		public function get Original():String {
			return _original;
		}

	}
}

カスタムイベントとイベントを発生させる部分は不要になってしまいましたので、イベントを発生させていた部分は以下のように非常にシンプルになりました。

package
{
	import flash.desktop.Clipboard;
	import flash.desktop.ClipboardFormats;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	public class ClipboardManager extends EventDispatcher
	{
		private var timer:Timer;
		private var _gmodel:TranslateModel;

		public function ClipboardManager()
		{
		}

		public function initClipboardManager(gmodel:TranslateModel):void {
			_gmodel = gmodel;

			timer = new Timer(1000);
			timer.addEventListener(TimerEvent.TIMER, onTimerHandler);

			if (Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) {
				_gmodel.Original = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT) as String;
			}

			timer.start();
		}

		private function onTimerHandler(event:TimerEvent):void {
			if (Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) {
				var clipboard:String = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT) as String;

				if (clipboard != _gmodel.Original) {
					_gmodel.Original = clipboard;
				}
			}
		}

	}
}

わかりにくいですが、以下が、実行した結果になります。
翻訳結果をデバッグトレースしています。

sample4

よくよく考えると、このやり方だと、クリップボードにコピーされると、何でもかんでもインターネットを流れてしまいます。

要件の

翻訳元の文章は、インターネットを流れるので、ユーザが意図しない翻訳は極力避ける。

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!より引用。

に反します。

う~ん、どうしよう・・・
とりあえず作戦を考えたいと思います。

サンプルソース

サンプルソースをダウンロードできるようにしておきます。

※ クリップボードにコピーした文字が無条件にgoogleに送られるので、利用時には注意してください。