こんにちは、Yuiです。
この度、**ボタン一つで画像から文字起こし&翻訳できるアプリ**を作りました!
ボタン一つで写真から文字起こししたり、母国語に翻訳するアプリ作りました!!
— Yui🌘個人開発 (@yui_active) October 15, 2020
ボタン一つでコピー可能、多言語に対応してます。
登録不要で利用できます。#PicTranslator
拡散してもらえると私が喜びます!https://t.co/A28rXwMMB5
100日目#100日後に話題のwebサービスを立ち上げるワニ
機能としては下記のものをつけています。
- 自動で利用者のブラウザの言語を読み取ってデフォルト言語に設定
- ボタン一つで文字起こしされる
- ボタン一つでデフォルト言語(利用者が普段使っている言語)に翻訳される
- デフォルト言語以外に言語を変えたい場合、クリックで言語を変えることができる
- 言語を変えた場合、全体的に多言語化される
- 文字起こし&翻訳した後の文章はボタン一つで簡単にコピーできる
シンプルな作りで、誰が見てもすぐに使うことができるようなサービスを目指して作りました。
使った技術スタック
今回、APIの接続だけで完了するような簡単なアプリなので、DB設計は必要ありませんでした。
というわけで、使ったのは下記だけです。
- Vue.js(フレームワークはVuetify利用)→フロントエンド
- vue-clipboard2→クリックしたらコピーできるように利用
- axios→APIとの通信のために利用
- vue-i18n→多言語化のために利用
- API→Cloud Vision APIとCloud Translation APIを利用
上記で大体かかった時間は合計30時間ぐらいでした。
デザイン→1時間
画面設計→5時間
API接続→10分
多言語化→2時間
残りはレイアウトの微調整とかでこだわった部分で時間がかかりました。笑
若干ハマったところ
今回少し詰まったところとしてはplaceholderだけv-bindさせて使う必要があるということと、自動で利用者のブラウザの言語を読み取るという部分があります。
まず、今回多言語化をしたので、i18nの書き方に従い、
<div>{{$t('message.welcome')}}</div>
のように書く必要があります。
ただ、placeholderの文字を多言語化するにあたって、どういう風にかけば良いか悩みました。
//ファイルアップロード部分
<v-file-input
v-model="file"
@change="setImage"
@click:clear="clearData"
accept="image/*"
prepend-icon="mdi-camera"
placeholder="ここにプレースホルダーに表示させる文字" //<=この部分をどう多言語化する?
></v-file-input>
その部分に関して書いてあるものが少なく少し悩んだのですが、公式ドキュメントを見るとどうやらv-bindさせて書けば良さそうだったので、以下のようにして書きました。
//ファイルアップロード部分
<v-file-input
v-model="file"
@change="setImage"
@click:clear="clearData"
accept="image/*"
prepend-icon="mdi-camera"
:placeholder="$t('message.welcome')"
></v-file-input>
これでOK。ちなみに今回すでに文字起こしや翻訳をした後に再度違う画像をアップしたときに、過去の文字起こし・翻訳結果のデータが画面に残ってるままでは奇妙だったので、新しい写真をアップした段階でその結果を消すために@click:clear="clearData"
を書いています。
また、自動で利用者のブラウザの言語を読み取る部分に関しては、今回多言語化対応をしていますが、もし自分が英語話者だったとして、デフォルト言語が日本語だったらその時点で見る気失せますよね?
ということで、利用者の言語に合わせて表示を切り替える必要がありました。
そのためにmain.js
に以下を追加
const browserLanguage = function() {
var ua = window.navigator.userAgent.toLowerCase();
try {
// chromeは以下で利用者のブラウザ言語を取得できる
if (ua.indexOf('chrome') != -1) {
return (
navigator.languages[0] ||
navigator.browserLanguage ||
navigator.language ||
navigator.userLanguage
).substr(0, 2);
}
// それ以外(例えばIEなど)は下記で取得する必要がある
else {
return (
navigator.browserLanguage ||
navigator.language ||
navigator.userLanguage
).substr(0, 2);
}
} catch (e) {
return undefined;
}
};
//上記で取得した言語をデフォルト言語として設定
let defaultLang;
//今回日本語、英語、フランス語、ドイツ語、中国語のみに対応してるので、その中にブラウザで検出した言語が入ってるかどうか確認
const langs = ['ja', 'en', 'fr', 'de', 'zh']
if (langs.includes(browserLanguage())) {
defaultLang = browserLanguage();
} else {
//もし上記の言語外の場合はデフォルト言語を英語にする
defaultLang = 'en';
}
jsでブラウザの取得できるのは知ってたんですが、chromeしかやり方を知らなかったので、それ以外に対応させるのに色々と調べました。
また、条件文で以下のようにざっくりと書いたらうごくには動くんですが、ESLintでno-constant-conditionで怒られたので上記のように書き直しました。
if ( browserLanguage() == 'ja' || 'en' || 'fr' || 'de' || 'zh') {
defaultLang = browserLanguage();
} else {
defaultLang = 'en';
}
ほかは特に詰まることはなかったです。
工夫した点
今回は**できるだけシンプルに!**というのを目指して作りました。
なので、説明文はなくてもわかるように作りました。
結果、このようになりました。
画像をドラッグすると、こんな感じで文字起こしすると翻訳するのボタンが選べるようになります。
また、翻訳言語に関しては、もちろん英語やドイツ語など多言語にその場で選ぶようにすることもできました。
が、画像を翻訳したいとなったときに、**わざわざ母国語以外に翻訳するか?**という気持ちから、母国語に翻訳できるようにということで、ボタン一つで表示の言語に翻訳という形にしました。
また、もし表示の言語と母国語が違う(翻訳したい言語が違う)という場合は右上のボタンから違う言語に変換することもできます。
後はコピーした後の動きなどを少し工夫。
このレイアウトがな〜〜気に入らないんだよなあ〜〜〜〜〜 https://t.co/u80VW5N72z pic.twitter.com/71b9T92YZt
— Yui🌒個人開発 (@yui_active) October 12, 2020
これをこう。
すごい微妙に改善した
— Yui🌒個人開発 (@yui_active) October 12, 2020
正直結局これで落ち着くならtootlipで組んだりalertで組んだりしてた時間がすべて無駄になったと思ったけど、まあシンプルなのが一番良い
後は文字起こしと翻訳のボタンのところにアイコンを追加したい
何かいいのあるかな https://t.co/eDIroyJtNw pic.twitter.com/DtQi0C5DAx
そして右上の言語のボタンが何を表すのかわかりにくかなと思い、tootlipをその部分に利用。
もちろんこの部分も多言語化対応済み。
例えば英語で見てるときは英語で表示されるようになっています。
こだわりたかったけど時間の都合で省略した部分
今回どうしても省略した部分としては、OGPの多言語化です。
これは諸々の設定があまりにも面倒だったので、代わりに日本語と英語を両方表示するようにしました。
最後に
今回、作ったときはこんなに簡単なアプリを世の中に出してごめんなさい...という気持ちだったのですが、出してみると意外と好評で嬉しかったです。
これのLineBot版としてほんやくこんにゃくんも前に出したので、よかったら使ってみてください。
画像を送信するだけで、勝手に画像内の言語を認識して何でも日本語に変えてくれるLineBot作りました!
— Yui🌒個人開発 (@yui_active) October 5, 2020
英語、中国語、ドイツ語、フランス語あたりは動作確認してます!(他の言語でもOK)
良いな〜と思ったら拡散してもらえると嬉しいです!
これからwebアプリ化もします! pic.twitter.com/PrAG1o1gHO
また、Product Huntにも出してます!良ければvoteお願いします。