NCMBとMonaca、DeepL APIを使って翻訳アプリを作る（その1：画面の説明とSDKの導入）

NCMBとMonacaを使ってデモアプリを作ってみます。今回はDeepL APIを使った翻訳アプリです。翻訳結果をNCMBのデータストアに保存し、後で確認できるようにします。データストアにデータを保存したり、逆に取り出すのはよくあるケースなので、様々な場面で応用できるはずです。

今回は画面の説明とSDKの導入までを進めます。

## コードについて

今回のコードは[NCMBMania/monaca_translation_app: MonacaとNCMB、DeepL APIを使った翻訳アプリです](https://github.com/NCMBMania/monaca_translation_app)にアップロードしてあります。実装時の参考にしてください。

## 利用技術について

今回は次のような組み合わせになっています。

- Monaca
- NCMB JavaScript SDK
- Framework7

## 仕様について

今回はシンプルにするために認証は利用していません。入力されたテキストデータと、DeepL APIで翻訳したデータをデータストアに保存します。履歴画面では最大10件のデータを取得、一覧表示します。

## 利用する機能について

翻訳アプリで利用するNCMBの機能は次の通りです。

- データストア
  - 翻訳データの保存
  - 翻訳データの検索

## 画面について

今回は以下の4画面を使います。

### www/index.html

タブを2つ表示します。1つ目は翻訳画面（www/pages/translations.html）、2つ目は履歴画面（www/pages/histories.html）を呼び出します。

```html
<div id="app">
	<!-- Views/Tabs container -->
	<div class="views tabs safe-areas">
		<!-- Tabbar for switching views-tabs -->
		<div class="toolbar toolbar-bottom tabbar-labels">
			<div class="toolbar-inner">
				<a href="#view-home" class="tab-link tab-link-active">
					<i class="icon f7-icons if-not-md">house_fill</i>
					<i class="icon material-icons if-md">home</i>
					<span class="tabbar-label">翻訳</span>
				</a>
				<a href="#view-history" class="tab-link">
					<i class="icon f7-icons if-not-md">square_list_fill</i>
					<i class="icon material-icons if-md">view_list</i>
					<span class="tabbar-label">履歴</span>
				</a>
			</div>
		</div>
		<!-- Your main view/tab, should have "view-main" class. It also has "tab-active" class -->
		<div id="view-home" class="view view-main view-init tab tab-active" data-url="/translations/">
		</div>
		<div id="view-history" class="view view-main view-init tab" data-url="/histories/">
		</div>
	</div>
</div>  
```

![monaca-translation-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/9b105dd6-e239-7d8a-4a43-9b3776837568.jpeg)



### www/prages/translations.html

翻訳実行画面です。日本語を入力して、翻訳するボタンをタップするとDeepL APIを使って英語に翻訳します。翻訳処理がうまくいったら、日本語と英語をNCMBのデータストアへ保存します。

```html
<div class="page">
	<div class="navbar">
		<div class="navbar-bg"></div>
		<div class="navbar-inner">
			<div class="title">翻訳</div>
		</div>
	</div>
	<div class="page-content">
		<div class="list no-hairlines-md">
			<form id="translation">
				<ul>
					<li class="item-content item-input">
						<div class="item-inner">
							<div class="item-title item-label">日本語</div>
							<div class="item-input-wrap">
								<textarea class="resizable" name="text" placeholder="翻訳するテキストを入力してください">Monacaを使ってアプリ開発を行おう！</textarea>
							</div>
						</div>
					</li>
					${translatedText !== '' ?
					$h`
					<li class="item-content item-input">
						<div class="item-inner">
							<div class="item-title item-label">英訳</div>
							<div class="item-input-wrap">
								${translatedText}
							</div>
						</div>
					</li>
					`
					:
					''
					}
				</ul>
				<div class="block">
					<button class="button button-fill" @click=${addTranslate}>翻訳する</Button>
				</div>
			</form>
		</div>
	</div>
</div>
```

![monaca-translation-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/b103575a-36a6-7e6b-343b-2a0bf2877c52.jpeg)


### www/prages/histories.html

翻訳履歴データを検索、結果を一覧表示する画面です。最初は日本語だけを表示します。

```html
<div class="page">
	<div class="navbar">
		<div class="navbar-bg"></div>
		<div class="navbar-inner">
			<div class="title">翻訳</div>
		</div>
	</div>
	<div class="page-content">
		<div class="list links-list">
			<ul>
				${translations.value.map(translation => $h`
					<li><a href="/translations/${translation.objectId}">${translation.original}</a></li>
				`)}
			</ul>
		</div>
	</div>
</div>
```

![monaca-translation-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/68b8d70c-4a1f-930d-aa4b-a03e717fbc50.jpeg)


### www/prages/translation.html

一覧でタップされた翻訳履歴の詳細表示を行うViewです。一覧から渡されたデータストアオブジェクトを表示します。

```html
<div class="page">
	<div class="navbar">
		<div class="navbar-bg"></div>
		<div class="navbar-inner">
			<div class="left">
				<a href="#" class="link back">
					<i class="icon icon-back"></i>
					<span class="if-not-md">戻る</span>
				</a>
			</div>
			<div class="title">翻訳</div>
		</div>
	</div>
	<div class="page-content">
		<div class="block-title">日本語</div>
		<div class="block">
			<p>${translation.original}</p>
		</div>
		<div class="block-title">英訳</div>
		<div class="block">
			<p>${translation.translate}</p>
		</div>
	</div>
</div>
```

![monaca-translation-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/22fab7e6-ba17-48e3-86a3-9dbd0b9653a2.jpeg)


### SDKのインストール

今回はMonacaのJS/CSSコンポーネントの追加と削除より、NCMBを追加します。アプリのテンプレートはFramework7のJavaScript版（VueやReactではなく）を選択しています。

## NCMBのAPIキーを取得

[mBaaSでサーバー開発不要！ | ニフクラ mobile backend](https://mbaas.nifcloud.com/)にてアプリを作成し、アプリケーションキーとクライアントキーを作成します。

## DeepLのAPI認証キーを取得

[DeepL翻訳：世界一高精度な翻訳ツール](https://www.deepl.com/translator)にて開発者登録し、API認証キーを取得します。

## js/config.jsonの作成

js/config.jsonを作成し、その中に先ほど取得したNCMBのAPIキー、DeepLのAPI認証キーをそれぞれ設定します。内容は次のようになります。

```json
{
	"applicationKey": "YOUR_APPLICATION_KEY",
	"clientKey": "YOUR_CLIENT_KEY",
	"deepLAuthKey": "YOUR_DEEPL_AUTH_KEY"
}
```

## 初期化

初期化は `js/app.js` にて行います。config.jsonを読み込む関係上、非同期処理内にて行います。cordovaの有無（アプリまたはプレビューの違いを検知）によって初期化時のイベント処理を変えています。

```js
// NCMBの初期化用
const event = window.cordova ? 'deviceready' : 'DOMContentLoaded';
document.addEventListener(event, async (e) => {
	// この中に処理を書きます
});
```

config.jsonの内容を読み込んで、NCMBとFramework7の初期化を行います。

```js
window.config = await (await fetch('./js/config.json')).json();
window.ncmb = new NCMB(config.applicationKey, config.clientKey);
window.app = new Framework7({
	name: 'My App', // App name
	theme: 'auto', // Automatic theme detection
	el: '#app', // App root element
	// App store
	store: store,
	// App routes
	routes: routes,
});
```

これでNCMBの初期化が完了します。

## ルーティング設定

今回は翻訳画面、履歴一覧画面、履歴詳細画面の3つがあります。これを `js/routes.js` に定義します。

```js
const routes = [
  {
    path: '/',
    url: './index.html',
  },
  // 翻訳画面
  {
    path: '/translations/',
    componentUrl: './pages/translations.html',
  },
  // 履歴詳細画面
  {
    path: '/translations/:objectId',
    componentUrl: './pages/translation.html',
  },
  // 履歴一覧画面
  {
    path: '/histories/',
    componentUrl: './pages/histories.html',
  },
  // Default route (404 page). MUST BE THE LAST
  {
    path: '(.*)',
    url: './pages/404.html',
  },
];
```

## ストアの設定

履歴一覧と詳細では同じ履歴データを扱うので、ストアに定義をします。これは `js/store.js` に定義します。

```js
const createStore = Framework7.createStore;
const store = createStore({
  state: {
    // 翻訳履歴一覧が入る
    translations: [
    ]
  },
  getters: {
    // 翻訳履歴一覧のゲッター
    translations({ state }) {
      return state.translations;
    }
  },
  actions: {
    // 翻訳履歴の追加用（一件）
    addTranslate({ state }, translation) {
      state.translations = [...state.translations, translation];
    },
    // 翻訳履歴の追加用（一括）
    addTranslates({ state }, translations) {
      state.translations = [...state.translations, ...translations];
    },
  },
})
```

## まとめ

今回は翻訳アプリの仕様と画面、NCMBの初期化までを解説しました。次は[翻訳処理とデータ登録を解説します](https://qiita.com/goofmint/items/1ff6caae08add6a4301c)。