このエントリーは、JavaFX Advent Calendar 2014, 11日目のおまけです。
昨日は @toruwest さんの「JavaFXのTreeViewでアニメーションしてみる」でした。
明日は @skrb さんの「Java Advent Calendarと一緒になにか書きます」です。
JavaFX Advent Calendar 2014、6日目の Katsumi Kokuzawa さんの「JavaFXでMarkdownエディタを作る」を読んで
リアルタイムに入力されたテキストが変換され表示されるのって格好いいなぁって思ったので自分もチャレンジしてみた。
私は英語が駄目な残念な人間なので Google さんと JavaFX さんに助けてもらうことにしました。
翻訳と音声は java-google-translate-text-to-speech を利用させていただきました。
翻訳は下記 FXMLDocumentController クラスのソースコード 145 行目から 152 行目までのところで処理をしています。
文字を一部置き換えているのはエラーが出るためのその場しのぎの適当な対応です。
それと長文になるとエラーが出ます。
そういう仕様なのかバグなのか、使い方が悪いのかは解りません。(^_^;)
とりあえず的な(使い物にならない)翻訳機を作ったよというお話しでした。
動画とプログラムのコードを貼っておきます。
package jp.yucchi.javafx.google.translater;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
/**
*
* @author Yucchi
*/
public class JavaFXGoogleTranslater extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
loader.load();
AnchorPane root = loader.getRoot();
Scene scene = new Scene(root);
FXMLDocumentController controller = loader.getController();
controller.setStage(stage);
stage.setResizable(false);
stage.setTitle("JavaFX Google Translater");
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package jp.yucchi.javafx.google.translater;
import com.gtranslate.Audio;
import com.gtranslate.Language;
import com.gtranslate.Translator;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import javazoom.jl.decoder.JavaLayerException;
/**
*
* @author Yucchi
*/
public class FXMLDocumentController implements Initializable {
@FXML
private Label jp;
@FXML
private Label en;
@FXML
private TextArea jTextArea;
@FXML
private TextArea eTextArea;
@FXML
private Button clearButton;
@FXML
private Button eSpeakButton;
@FXML
private ProgressIndicator progressIndicator;
private ExecutorService service;
private Task task;
@FXML
private void clearButtonAction(ActionEvent event) {
jTextArea.setText("");
eTextArea.setText("");
if (!task.isCancelled()) {
task.cancel();
}
}
@FXML
private void eSpeakButtonAction(ActionEvent event) {
eSpeakButton.setVisible(false);
progressIndicator.setVisible(true);
task = new Task() {
@Override
protected Void call() throws Exception {
InputStream sound = null;
try {
Audio audio = Audio.getInstance();
sound = audio.getAudio(eTextArea.getText(), Language.ENGLISH);
audio.play(sound);
} catch (IOException | JavaLayerException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
sound.close();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
@Override
protected void succeeded() {
eSpeakButton.setVisible(true);
progressIndicator.setVisible(false);
}
;
@Override
protected void cancelled() {
eSpeakButton.setVisible(true);
progressIndicator.setVisible(false);
}
@Override
protected void failed() {
eSpeakButton.setVisible(true);
progressIndicator.setVisible(false);
}
};
service.submit(task);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
progressIndicator.setVisible(false);
service = Executors.newSingleThreadExecutor();
eSpeakButton.disableProperty()
.bind(
Bindings.when(eTextArea.textProperty().isEmpty())
.then(true)
.otherwise(false));
clearButton.disableProperty()
.bind(
Bindings.when(jTextArea.textProperty().isEmpty().and(eTextArea.textProperty().isEmpty()))
.then(true)
.otherwise(false));
jTextArea.textProperty().addListener(observable -> {
final String s = ((StringProperty) observable).get();
// エラー出るため適当に置き換え
final String _s = s.replaceAll("\\r\\n|\\r|\\n", "").replaceAll("。", ".").replaceAll("、", "").replaceAll("?", "?").replaceAll("!", "!");
Translator translate = Translator.getInstance();
String englishText = translate.translate(_s, Language.JAPANESE, Language.ENGLISH);
eTextArea.setText(englishText);
});
}
void setStage(Stage stage) {
stage.setOnCloseRequest(we -> {
if (service != null && !service.isShutdown()) {
service.shutdownNow();
}
Platform.exit();
System.exit(0);
});
}
}
これで英語力が上がるとうれしいけど努力しないでってのは完全に無理な話しですね。
JavaFX 楽しい!