CodeIgniterでDB連携した翻訳ボタンを実装してみる

K-POPのダンスを習い始めようかと思っています。キリョウです。
最近リープモーションを買ったので何かに活かしたいです。


本日はサイトに翻訳機能ボタンを作った話。
順序は以下。

# DB翻訳ボタンの実装順序
１. jsのダウンロード
２. 翻訳データの作成
３. 任意のviewファイルに翻訳ボタンを設置する
４. フッターのviewファイルにjsのスクリプトを貼り付ける
5. コントローラーで翻訳したいページにデータ受け渡しを設定
6. 翻訳部分のviewファイルに変更の目印を貼り付ける
７. modelにデータを返す機能を追加する（説明がヘビー）

# 必要な知識と今回の前提
・Igniterのコントローラーの役割とかがわかる
・Igniter内でJavascriptの設置方法がわかる
・databaseは連携してあってMYSQLにデータを作れる
・コントローラー内でviewファイルを組み合わせて作るパターン
・読解力()

Javascriptが出てきますが中身の理解はいらないです。初心者向けですが、説明がややこしい。
ではいってみよう。



## １.jsのダウンロード

下記からtranslate.jsをダウンロードして、jsのフォルダに設置。
http://www.openxrest.com/translatejs/


## ２翻訳データの作成

DBにテーブルを作って、日本語と英語のカラムと各データを入れる。
ここでは例として、nameとname_en、summaryとsummary_enを作成。
ポイント。
・シングルクォーテーションは使えますが、ダブルクォーテーションは使わないでください。
・最終的にHTMLとして出力されるため、タグを入れることができます。（`<br>`）
・データベース内での手打ちの改行はしないでください。

| id | work_name | work_name_en | summary | summary_en |
|:-:|:-:|:-:|:-:|:-:|
| 1 | ハンバーグ | Hunburg | 肉 | nice meat |
| 2 | ポテト | Potato | 芋だよ | this is imo |


## ３任意のviewファイルに翻訳ボタンを設置する

ここでは翻訳ボタンを、よくありがちなヘッダーのナビメニューの横にペロッと貼ります。
ボタンはもちろんテキストでも画像でもお好みで。
要素内にclassとdata-valueという項目を設定します。

```html
<span class="lang_selector trn" data-value="jp">JP</span>
<span class="lang_selector trn" data-value="en">EN</span>
```

*ポイント*
・translate.jsはjqueryなので、まだ置いていなかった人は、viewファイルのhead内に`<script src="jquery.js"/>`を入れておいてください。


## ４フッターのviewファイルにjsのスクリプトを貼り付ける

下記を、`</body>`の直前に貼ります。ここでtranslate.jsのリンクを貼ります。
手順3で、head内に貼っても大丈夫なはずですが、こっちの方が画面表示が軽そうな気がします。

```html
<script src="<?=base_url();?>js/jquery.translate.js"></script>
<script>
$(function() {
  var t = <?=$honyaku?>;
  var _t = $('body').translate({lang: "en", t: t});
  var str = _t.g("translate");
  console.log(str);
  $(".lang_selector").click(function(ev) {
    var lang = $(this).attr("data-value");
    _t.lang(lang);
    console.log(lang);
    ev.preventDefault();
  });
});
</script>
```


*ポイント*
・ここで指定した、`"<?=$honyaku>"`という関数でデータの受け渡しを行います。必要に応じて変更してください。


## 5コントローラーで翻訳したいページにデータ受け渡しを設定

まずは、コントローラーのコンストラクタに下記を追加。

```php
class Web extends CI_controller {
	private $data;//受け渡し用の変数を作ります
	public function __construct(){
	parent::__construct();
	$this->load->database();	// データベース設定ファイルの読み込み
	$this->load->model("j_model");	// モデルの読み込み
}
```


後ほどj_modelというモデルファイルを作成していきます。
コンストラクタの後に、下記のようにworksページを作成していたとします。

```php
	public function works(){
		$this->load->view('header');
		$this->load->view('works');
		$this->load->view('footer');
	}
```

下記のように、変数にj_modelファイル内のgetJsonAllファンクションの結果を入れます。

```php
	public function works() {
		$data['query'] = $this->j_model->getData();//全データを取るやつ
		$data['honyaku'] = $this->j_model->getHonyaku();//翻訳用の文字列を取るやつ
		$this->load->view('header');
		$this->load->view('works',$data);//受け渡し用の変数追加
		$this->load->view('footer',$data);//受け渡し用の変数追加
	}
```

## 6翻訳部分のviewファイルに変更の目印を貼り付ける

ここではworkというviewファイルになります。
このファイルには、コントローラーから渡された、`$query`と、`$honyaku`という変数が利用できます。
foreachで、idの数の分繰り返しています。（ここではハンバーグとポテトの２回分繰り返されます）



```html
<?php　foreach($query->result()as $row):?>

<div class="trn" data-trn-key="work<?=$row->id?>name">										<?=$row->work_name?></div>
<div class="trn" data-trn-key="summary<?=$row->id?>name">										<?=$row->summary_name?></div>

<?php endforeach;?>
```


*ポイント*
・classにtrnを、data-trn-keyという項目に、好きな名前を設定します。すべて同じdata-trn-keyの値になると、すべて同じ翻訳の値になってしまうため、案件のidを入れてforeachで回す分だけ、動的に追加します。
・idの位置は、`work<?=$row->id?>name`など真ん中に入れてください。
※DBのテーブルを使用せず、それぞれ固有のdata-trn-keyを設定する場合はworknameなど、お好きな文字列をどうぞ！



## ７modelにデータを返す機能を追加する
コントローラーで呼び出している、J_model.phpを作成します。
ちょっとここがヘビーです。まずは全部貼ってください。「a-数字」のところが変更部分です。


```php
<?php
class J_model extends CI_Model {


/**
 * getData
 * テーブルkiryoから全データを取得して,データを戻り値として返す
 */
function getData() {
		$this->db->select("*");
		return $this->db->get("kiryo");     //a-1
	}

/**
 * getJsonAll
 * テーブルkiryoから全データを取得して,JSONに成形して返す
 */
function getJsonAll() {
		$this->db->select("*");
		$query = $this->db->get("kiryo");   //a-1
		$honyaku= array();
		while ($row = $query->unbuffered_row()){
			$honyaku[] = array(
				'work'.$row->id.'name' => array(   //a-2
								'jp'=> $row->work_name,
								'en'=> $row->work_name_en
								),
				'summary'.$row->id.'name' => array(
								'jp'=> $row->summary,
								'en'=> $row->summary_en
								)
				);
		};
		header('Content-type: application/json; charset=utf-8');
		header('X-Content-Type-Options: nosniff');
		$honyaku = json_encode($honyaku,JSON_UNESCAPED_UNICODE);
		
		$trim1 = array("\"en\"","\"jp\"","}},{\"work","\"summary","\"work","name\"");   //a-3
		$trim2 = array("en","jp","},work","summary","work","name");   //a-4
		$houyaku = str_replace($trim1, $trim2, $honyaku);
		$honyaku = trim( $honyaku, "[] \\" );
		$this->output->set_header('Content-type: text/html; charset=utf-8');
		return $honyaku;
}
```

getDataではすべての情報を取り出しています。
getJsonAllでは何をやっているかというと、、、
DBに接続して、データをすべて取り出しJSONとして出力。
その後、js内で使用するために、trimやstr_replaceで文字列を変更し、サーバーに送信されるヘッダー情報をhtml文書に戻しています。最後に、整形し終わった文字列を`$honyaku`に入れて返します。

a-1
テーブル名をお使いのものに適宜変更してください。

a-2
これは、'work１name'というタグをviewファイル内で使用する目的があります。
'workname１'や'１workname'だと、JSON出力後の文字列の加工がうまくいきません。
※DBのテーブルを使用せず、それぞれ固有のdata-trn-keyを設定する場合は、while文はいりません。`'work'.$row->id.'name'`ではなく、'workname'にして、`'jp'=>'ハンバーグ','en'=>'Hunburg'`などここに直接打ち込めます。

a-3,a-4
JSONに変換した際、'jp'は"jp"として出力されます。
これだとtranslate.jsが動かないため、"jp"をjpに変換します。（"はエスケープしてあります。）
a-3にJSONの文字を、a-4に変更後の文字を入れています。
ここではまた、"work1name"をwork1nameと変更したいため、"workをwork、name"をnameと分解して変更しています。
※DBのテーブルを使用せず、それぞれ固有のdata-trn-keyを設定し、なおかつwhile文がなくmodelに翻訳内容を書いてしまう場合は、`$trim1 = array("\"en\"","\"jp\"","\"workname\"","\"summary\"");`で大丈夫です。

ご利用のDBに合わせてカスタマイズするのは下記の通りです。

変更なし
"jp"→jp
"en"→en
カスタマイズ
}},{"work→},work　　　　　--配列の先頭 b-1
"work→work        --配列の先頭
"summary→summary  --先頭以外の配列要素
name"→name        --worknameとsummarynameの共通の末尾name

*ポイント*
・配列の初めの要素
a-2の配列（work_nameやclient_name）では、while文で要素を複数回取りだしているため、配列の一番初めの要素(ここではwork_name)は、}},{"workと区切り用の括弧が無駄に出力されてしまいます。これを},workに変える必要があるため、配列の先頭の要素は、b−１のように変更する項目が一つ多くなります。

・文字列の変更に関しては、jsにJSONparserというJSONをjsに使えるよう変更する機能はあるようなのですが、要件が厳密で、うまく適用されませんでした。




## おしまい 


以上！！！
多分もっといいやり方もあるんだろうけど、ボタンの反応もかなり良いので個人的には良かったな〜と思ってます。~~マークダウンのコード引用むずすぎかよ~~