まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2018/01

「国際化」に対応したウェブアプリケーションを Node.js で作る方法を調べたので、メモ替わりに残しておきます。

ここでの「国際化(internationalization, i18n)」はウェブブラウザで設定した言語によって自動的に英語表記にしたり、日本語にしたり、・・・という切り替えを行えるようなものです。自動翻訳とかそういうものではありません。またブラウザで設定した言語は HTTP リクエスト時に "Accept-Language" ヘッダで送信されることになるので、後述の動作確認は curl コマンドでこのヘッダを指定して行っています。

このような国際化対応アプリケーションを Node.js で、正確には Node.js + Express + EJS の環境で作ってみました。

Node.js で国際化対応アプリケーションを作る場合、i18n というパッケージを使うのが手っ取り早いです:
https://www.npmjs.com/package/i18n

ソースコード(app.js)はこんな感じにしました。余計な部分を削ぎ落として、最小限必要な部分だけを残しています(赤字部分が i18n 関連の箇所です):
//. app.js

var express = require( 'express' ),
    fs = require( 'fs' ),
    ejs = require( 'ejs' ),
    i18n = require( 'i18n' ),
    request = require( 'request' ),
    session = require( 'express-session' ),
    app = express();

var port = 3000;

app.set( 'views', __dirname + '/public' );
app.set( 'view engine', 'ejs' );

i18n.configure({
  locales: ['en', 'ja'],
  directory: __dirname + '/locales'
});
app.use( i18n.init );

app.get( '/', function( req, res ){
  res.render( 'index' );
});

app.listen( port );
console.log( "server starting on " + port + " ..." );

今回は英語(en)と日本語(ja)に対応したアプリケーションにしました。

また '/' にアクセスした時に ejs の index テンプレートを使った画面が表示されるような内容にしています。ちなみに index テンプレート(public/index.ejs)の内容は以下のようになっています:
<html>
<head>
<title><%= __('subject') %></title>
</head>
<body>
<h1><%= __('subject') %></h1>
<hr/>
<%= __('body') %>
</body>
</html>


テンプレート内で subject と body という2つの変数を使った表記を行っています。実際にはこれらの部分に言語設定に合わせた内容が表示されることになります。

そして言語ファイルを以下のように用意します:

(英語用: locales/en.json)
{
  "subject": "subject",
  "body": "body"
}


(日本語用: locales/ja.json)
{
  "subject": "サブジェクト",
  "body": "本文"
}

英語設定で利用した場合、上記の subject 変数部分は "subject", body 変数部分は "body" と表示されます。また日本語設定の場合、それぞれ "サブジェクト" と "本文" となります。


これで準備できました。 npm install して実行(node app)します:
$ npm install
$ node app

確認は別の端末から curl で行いました。まずは Accept-Language を en(英語)にしてアクセス:
$ curl http://localhost:3000/ -H 'Accept-Language: en'

<html>
<head>
<title>subject</title>
</head>
<body>
<h1>subject</h1>
<hr/>
body
</body>
</html>
>

次は日本語設定でアクセスした場合:
$ curl http://localhost:3000/ -H 'Accept-Language: ja'

<html>
<head>
<title>サブジェクト</title>
</head>
<body>
<h1>サブジェクト</h1>
<hr/>
本文
</body>
</html>


期待通りに動いています!


アプリケーションの国際化そのものはこれだけで出来ました。そして問題になるのは「どうやって色んな言語用の JSON リソースファイルを用意するか?」です。1つ1つ翻訳サービスなどを使いながら作る、という方法もありますが、そんな言語リソースファイルの翻訳作業は IBM Cloud の Globalization Pipeline サービスを使うと英語のリソースファイルから各言語に翻訳したリソースファイルをまとめて作ることができてとても便利です。このサービスについては以前のブログで使い方も含めて紹介しているので参照ください:
Globalization Pipeline サービスがリリースされました!


と、最後は宣伝でしたw

IBM Cloud(Bluemix) のアカウントを所有していると、マネージドサービスとして利用できる GitLab が使えるようになります。サーバーのインストールなどは不要で、プライベートリポジトリを作成することも可能です:
2018011701


使い勝手は GitLab そのものだと思ってください。Issues 管理の機能も使えますし、IBM Cloud の Continous Delivery サービスと連携した Delivery Pipeline による DevOps サービスの一部としても利用できるようになっています。アカウントをお持ちの方は、単にプライベートリポジトリが使える Git として考えるだけでも便利だと思うので、是非活用してください。


ところで、この IBM Cloud の Git を使って Java のアプリケーションコードを管理しようと、作成したリポジトリから Eclipse の Git 機能を使って clone を試みた際に、稀に以下のようなエラーメッセージに遭遇し、クローンに失敗することがあります:
  :
  :
!MESSAGE https://git.ng.bluemix.net/dotnsf/javatest.git: cannot open git-upload-pack
!STACK 0
org.eclipse.jgit.api.errors.TransportException: https://git.ng.bluemix.net/dotnsf/javatest.git: cannot open git-upload-pack
  at org.eclipse.jgit.api.LsRemoteCommand.call(LsRemoteCommand.java:196)
  at org.eclipse.egit.core.op.ListRemoteOperation.run(ListRemoteOperation.java:99)
  at org.eclipse.egit.ui.internal.clone.SourceBranchPage$8.run(SourceBranchPage.java:324)
  at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:121)
Caused by: org.eclipse.jgit.errors.TransportException: https://git.ng.bluemix.net/dotnsf/javatest.git: cannot open git-upload-pack
  at org.eclipse.jgit.transport.TransportHttp.connect(TransportHttp.java:499)
  at org.eclipse.jgit.transport.TransportHttp.openFetch(TransportHttp.java:308)
  at org.eclipse.jgit.api.LsRemoteCommand.call(LsRemoteCommand.java:175)
  :
  :

「git-upload-pack がオープンできない」という耳慣れないエラーメッセージで、実はこのメッセージそのものからは原因の追求が難しいものでした。同じようなエラーに遭遇する人が現れた場合に備えて、自分の経験と回避策を紹介します。

エラーメッセージそのものからはわかりにくにのですが、実は直接の原因は暗号化方式の不一致による通信エラーでした。

まず上記で紹介した IBM Cloud の Git 機能を https 接続で使う場合の暗号化方式には TLS v1.2 を使う必要があります:
https://console.bluemix.net/docs/services/ContinuousDelivery/git_working.html#git_local


さて、Eclipse が使う Java のバージョンが 1.8 以上であれば、デフォルト設定のままで TLS v1.2 が使われます。したがってこの場合は何もしなくてもそのまま IBM Cloud の Git を利用することができます。

一方、Eclipse の Java バージョンが 1.7 以下だった場合、デフォルト設定で採用される通信方式は TLS v1.1 以下です。つまり条件を満たしていないことになります。そしてこの条件で Git に接続しようとすると上記のようなエラーメッセージが表示されてしまうのでした。


では、このエラーメッセージが出た場合の解決策はどうすればいいのでしょうか? 1つの方法としてJava のバージョンを 1.8 以上にするという簡単な方法があります。Java 1.8 以上であれば上記のように(デフォルトで) TLS v1.2 が使われるので、この条件を満たすことができるようになります。

ただ何らかの事情で Java 1.8 を導入するわけにはいかない場合もあると思っています。そのような場合は以下の1行を eclipse.ini に追加した上で Eclipse を起動する、という方法もあります:
  :
  :
-Dhttps.protocols=TLSv1.2

この記述により、Java が 1.7 以下であっても強制的に https 接続時の暗号化方式を TLS v1.2 に指定することができ、やはり上記のエラーを回避することができるようになります。


IBM Cloud 以外の Git でも、同様のエラーメッセージが出た場合にはこの対策が有効だと思っています。頭の片隅に入れながら、無料で便利な IBM Cloud の Git を是非使ってみてください。


2018 年最初のブログエントリはちとマジメなマンホールマップネタにします。

2010 年夏のリリースから7年半近くもの間に多くのマンホールファンの皆様に愛され、成長を続けてきたマンホールマップですが、リリース当初の小規模運営時には想定していなかった問題にも多く直面してきました(コストとか、容量とか、プラットフォームの仕様変更とか、・・・)。そしてその都度問題を先送り解決しながら成長してきました。

そんな問題の中で、未解決だったことの1つが「利用規約」および「プライバシーポリシー」でした。端的な言い方をすると「マンホールマップにアップロードした画像の著作権はどうなるのか?」という問題です。サービス開始当初はいわば「一部のマニア向けサービス」であり、当時存在していなかった位置情報付きマンホール情報共有サービスとしての物珍しさから、細かいことを気にする人も少なかったように思えます(僕が知らなかっただけかもしれませんが)。

時は流れ、ユーザーや業界の努力、そして街歩き等他の趣味と合わせる形での認知度もあがり、マンホール探しそのものが趣味として認知されつつあるようになってきました。同時にマニアの域を超えて、広く一般の人がマンホールに興味を持つようになり、マンホールマップは(色々なこだわりは残しつつも)マニア向けではないサービスとしての変革が求められるようになってきました。

さて利用規約およびプライバシーポリシーの問題です。実はこれまでマンホールマップには明確な利用規約およびプライバシーポリシーの明示がありませんでした。昨年だけでこの点での質問を何度かいただくようになり、そろそろサービス提供側としての対応が求められていることを認識しました。という背景もあり、2018 年最初のアップデートに併せて遅ればせながらマンホールマップの利用規約およびプライバシーポリシーを用意する運びとなりました:
利用規約
プライバシーポリシー


PC版ページ(http://manholemap.juge.me/)ではトップページの一番下に、
2018010401


モバイル向けページ(http://manholemap.juge.me/m.jsp)ではトップページのメニューの最後に、それぞれリンクが付いています:
2018010402


これら2つのページの内容は利用するウェブブラウザの言語設定によって日本語または英語で表示されるようになっています。以下の補足については日本語をベースとしています。

以下は(2018/01/04 時点での)特に利用規約に関する内容を補足したものです。上記2ページを読んだだけだと「結局アップロードした画像の著作権はどうなってるの?」という問題の答がわかりにくいと思っているので、その点を解説しています。

利用規約内には以下のようにかかれています(2018/01/04):
ユーザーが投稿した写真(画像)の著作権について

Juge.Me およびマンホールマップでは、ユーザーが本サービスに、またはこれを通じて投稿するいかなるユーザーコンテンツについても、その所有権を主張しません。 ただしユーザーは、ユーザーが本サービスに、またはこれを通じて投稿するユーザーコンテンツを、Juge.Me およびマンホールマップが http://manholemap.juge.me/privacy.jsp に掲載されている本サービスのプライバシーポリシーに従って利用する、非独占的かつ無料、譲渡可能かつ再許諾権付きの世界的使用許諾を付与するものとします。 またユーザーが投稿したマンホールマップ内の画像はマンホールマップのページ単位で第三者がシェア/共有することについては同意するものとします。

マンホールマップ側ではその著作権を「主張しない」ことを明言しています。つまり写真の著作権は投稿者にあり続けます。著作権についてはこの点を明確にしました。

ただし以下の2点に注意してください:
(1) ただしユーザーは、ユーザーが本サービスに、またはこれを通じて投稿するユーザーコンテンツを、Juge.Me およびマンホールマップが http://manholemap.juge.me/privacy.jsp に掲載されている本サービスのプライバシーポリシーに従って利用する、非独占的かつ無料、譲渡可能かつ再許諾権付きの世界的使用許諾を付与するものとします。

(2) またユーザーが投稿したマンホールマップ内の画像はマンホールマップのページ単位で第三者がシェア/共有することについては同意するものとします。

(1) はユーザー(投稿者)が投稿する画像コンテンツについて、マンホールマップ側に対して、
  • 「非独占的に(マンホールマップだけのものではなく、他の SNS 等に投稿することができる)」
  • 「無料(その際、投稿者に著作権料は支払われない)」
  • 「譲渡可能かつ再許諾権付き(マンホールマップ側の判断で他のメディアやサービスに画像を提供することができる)」
という条件を付与する、という意図を含んでいます。

実際のところ、これまでもマンホールマップ内のコンテンツは誰でも利用可能な API によってアクセスすることができ、その API によって多くの関連サービスが生まれてきていました。加えてマンホールマップでは画像の全体的な色に近い色で画像に枠を付けて表示するなどの加工を行った上で表示しています。それらを明文化した形になります。

また、(2) は画像としての勝手な再利用は制限していますが、マンホールマップのページ(URL)単位で SNS にシェアしたり、ブログなどで再利用することについては第三者が無許可で自由に使うことができることを謳っています。


基本的にはこれまで通りの機能を後追いする利用規約(とプライバシーポリシー)としているつもりですが、どうしてもこの内容での公開に不安を感じられる場合は相談いただくか、あるいはお手数ですが問題が解決するまでの間、いったん削除していただきたいです。




このページのトップヘ