2017年振り返り、2018年の目標

遅くなりましたが2017年の振り返りと2018年まとめ

2017年の振り返り

技術関連としてはアプリとサービスを何個か作りました。
特にうち1つはプライベートですが、仲間と一緒に作り上げたので楽しかった。
コミュニティも立ち上げましたが、拠点が変わったので今後どうするかについては悩みどころ。。
2017年は本格的にに英語の勉強を始めました、2018年の目標にも掲げて居ます。

2018年の目標

技術目標

  • 拠点が沖縄→東京に移ったのでコミュニティに積極的に参加する。
  • 月1で学びたい技術を採用したアプリ(orWebサービス)を構築する。

 技術先行ではなく実際に動くアプリ、サービスを主軸として構築していきたい。

  • 1アプリごとに有益なソースがあれば抜き出しGithubに公開していく。
  • アウトプットとして、学んだ技術をブログに書いて行く。

(週1記事目度で目標)


英語目標

TOEIC 800点以上

リスニング、リーディングの目標としてのスコア。
ただしスピーキングの部分は鍛えられないので別で英会話も並行する。

英会話 週5時間

オンライン英会話で実施します。
1日1時間、休み2日ぐらいを見込んでます。

英語の目標に関して

今年中に英語目標を達成できれば後は日常的に
英語に関わる機会を作ることにして英語を喋れるようになった認定をする。

2018年末年始ハッカソン Xamarinで音読プレイヤー

年末年始に勉強&復習がてら2つのアプリ作っています。
1つめのアプリが一区切りついたのでリリース前に仕様整理を兼ねてまとめます。

どんなアプリ?

音読に特化したミュージックプレイヤー。
英語勉強用に作りました。Qiitaの記事とかでも紹介されているのでそちらをご参照頂ければ
学年ビリのアホが1年半でTOEICスコアを300点から840点に上げた英語勉強法の話 - Qiita

欲しかった仕様

再生リスト読込

音読に利用している素材は基本的にiTunesの再生リストで管理しているので
iTunesより再生リストから読み込んで操作できることが必須条件。

スピリット(スラッシュリーディング)区切りでの再生

1つの音声ファイルの特定部分をリピートを簡単にする機能が欲しかった。
詳細は機能紹介の項目にて記述します。

リピーティングを簡単にするための機能

"スピリット(スラッシュリーディング)区切りでの再生"を利用してリピーティングも
簡単にできるようにしたかった機能です。詳細は機能紹介の項目にて記述します。

再生速度の変更

再生速度の変更、Podcastで実装されてますね。
欲しかった機能です。

秒単位の前後移動

特定の秒単位スキップ機能です。
PodcastやYoutubeアプリで実装されています。

その他、基本的な機能

必要最低限な曲単位の前後移動など。

アプリ紹介

画面
f:id:furugen098:20180105005516p:plain

各機能

動画(gif)を交えての説明

スピリット(スラッシュリーディング)区切りでの再生/移動

主な手順
①対象の音声ファイルを再生しながらフラグ(オレンジ)を起てる。
②フラグを一度立てれば移動ボタンで自由に移動が可能。
f:id:furugen098:20180105010246g:plain
③フラグリピートボタンをONにすればフラグ間での自動リピート可能
f:id:furugen098:20180105010406g:plain

リピーティングを簡単にするための機能

主な手順
①フラグが立っている状態でリピートモード(画像参照)に変更
②フラグまで再生されるとフラグ間の再生時間分、一時停止状態になります。
 画像では1つめのフラグと2つめのフラグ間が約11秒あるため、約11秒一時停止しています。
 この間にリピーティングを行います。
f:id:furugen098:20180105011130g:plain

再生速度の変更

0.5〜2.0倍速
再生時間の表示は倍率で増減するのではなく再生時間の表示を遅く/早くしています。
f:id:furugen098:20180105011637g:plain

秒単位の前後移動

10秒単位でのスキップとしました。
f:id:furugen098:20180105011804g:plain

その他の基本的な動作は省略。
各フラグのステータスは音声ファイルごとに保存される仕様になっていますので、
一度フラグ設定してしまえば通常のミュージックプレイヤーと同じ感覚で利用できます。

まとめ

リピーティング用の音声ファイルを作るのが大変でしたので音読プレイヤーを作成しました。
個人用に作りましたが、音読による語学学習をされている方に是非使ってもらえたら嬉しい限りです。
開発内情としては本アプリはXamarin Formsで実装しましたがプラットフォーム特有のプログラムはポインタの座標取得と音楽再生&再生リストの取得程度なのでAndroid版の対応も簡単なはず。
一緒にリリースしたいですが、取り急ぎ必要なiOS版を作りました。
もう少し修正してiOS版はリリースしたいと思います。

フィリピン留学の備忘録  授業開始〜1週目

1週間が経過しました。
1ヶ月の滞在ですが本当すぎるのが早い。
ネイティブとの会話は沖縄から帰ってからさらにやらないとな…。
滞在プランとしては、とにかく自然に日常会話ができることがゴール。
全授業の先生に対して毎時世間話することでスキルを向上を狙っています。
そう考えるとやっぱり英語日記は大分効率が良いんですよね。
あと私が通っている学校では週末に英語のプレゼンテーションチャレンジあり、
2〜5人の目安でプレゼンテーションをやってます。
テーマは毎週変わりますが、来週はフリーテーマということでチャレンジしてみようかなと思ってます。
正直まだほとんど喋れてないので不安ですが、とりあえずやってみようの精神で頑張ります。

あと週末はジンベエザメとシュノーケリングできるオスロブへ行く予定です!

フィリピン留学の備忘録  授業開始2、3日目

2日目と3日目をまとめて。
初日も感じたことですが、複数の講師の方がいるため、世間話(というか昨日どう過ごした?)を毎回する。

続きを読む

JavaでMicrosoft Translator テキスト APIを使って翻訳(日本語→英語)

Microsoft Translator テキスト APIをJavaで試してみました。

意外とJavaのサンプルソースが見つからなかったので参考になればと思い公開します。
key,tokenUrl,transUrlを環境に合わせて変更してもらえればすぐに利用利用可能です。
ちなみに、keyは発行したご自身のものを利用してする必要がありますが、2017/11/05時点では
tokenUrl(認証用トークンAPI-URL)
https://api.cognitive.microsoft.com/sts/v1.0/issueToken
transUrl(翻訳用API-URL)
https://api.microsofttranslator.com/V2/http.svc/TranslateArray
です。

ソース

@Component
public class TranslatorAPI {

    @Value("${translation.subscriptionKey}")
    private String key;

    @Value("${translation.tokenApi.url}")
    private String tokenUrl;

    @Value("${translation.transApi.url}")
    private String transUrl;

    /**
     * 対象文字列を英語に翻訳します。
     * @param words 対象文字
     * @return 翻訳結果
     */
    public String[] translator(String... words) {
        return translatorPOSTToEN(words);
    }

    /**
     * トークンを取得します。
     */
    private String tokenPOST() {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost postMethod = new HttpPost(tokenUrl);

            // Header
            postMethod.setHeader("Content-Type", "application/json");
            postMethod.setHeader("Accept", "application/jwt");
            postMethod.setHeader("Ocp-Apim-Subscription-Key", key);

            try (CloseableHttpResponse response = httpClient.execute(postMethod)) {
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    return EntityUtils.toString(entity, StandardCharsets.UTF_8);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 翻訳APIにポストします。
     */
    private String[] translatorPOSTToEN(String... words) {
        List<String> rtnWords = new ArrayList<String>();

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {

            HttpPost postMethod = new HttpPost(transUrl);

            // header
            // 認証トークンを取得
            String token = tokenPOST();
            String authKey = "Bearer " + token;
            postMethod.setHeader("Content-Type", "application/xml");
            postMethod.setHeader("Authorization", authKey);

            // 翻訳ワード
            StringBuilder transWords = new StringBuilder();
            for (String word : words) {
                transWords.append("<string xmlns='http://schemas.microsoft.com/2003/10/Serialization/Arrays'>");
                transWords.append(word);
                transWords.append("</string>");
            }
            StringBuilder requestSB = new StringBuilder();
            requestSB.append("<TranslateArrayRequest>");
            requestSB.append("<AppId />");
            requestSB.append("<Texts>");
            requestSB.append(transWords.toString());
            requestSB.append("</Texts>");
            // 翻訳対象言語を指定
            requestSB.append("<To>en</To>");
            requestSB.append("</TranslateArrayRequest>");

            postMethod.setEntity(new StringEntity(requestSB.toString(),
                    StandardCharsets.UTF_8));

            try (CloseableHttpResponse response = httpClient.execute(postMethod)) {
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    String res = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    InputSource inputSource = new InputSource(new StringReader(res));
                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder documentBuilder = factory.newDocumentBuilder();
                    Document document = documentBuilder.parse(inputSource);

                    // 翻訳対象文字列文のソートを実行
                    Element root = document.getDocumentElement();
                    NodeList rootChildren = root.getChildNodes();
                    for (int i = 0; i < rootChildren.getLength(); i++) {
                        Node node = rootChildren.item(i);
                        if (node.getNodeType() == Node.ELEMENT_NODE) {
                            Element element = (Element) node;
                            String val = element.getElementsByTagName("TranslatedText").item(0).getFirstChild().getNodeValue();
                            rtnWords.add(val);
                        }
                    }
                }
            }
        } catch (ParserConfigurationException | SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return rtnWords.toArray(new String[rtnWords.size()]);
    }

}

確認

呼び出し
        // サンプル
        String[] words = tranApi.translator("これはペンです", "りんごはおいしい");
        for (String word : words) {
            System.out.println(word);
        }
出力結果
This is a pen.
Apple delicious