全く気付かないうちにあの曲になるwebアプリ

全く気付かないうちにあの曲になるwebアプリができた。
https://sanemat.github.io/lunch-box/?pv=k4xGqY5IDBE&st=11

クリスマスの宿題として、作っていたのだけど思ったより時間かかってしまった。
どうにか2016年中に完成したので年が越せる。

https://sanemat.github.io/lunch-box/?pv=mjyeBXDWiHg&st=10
https://sanemat.github.io/lunch-box/?pv=CTl1BDngldc&st=5

iosは複数動画流すと、1個目の動画が止まってしまうのはwebkitの仕様?バグ? らしいので、androidかパソコンで見てね。

ユッキのは元ネタあり
「気持ちいいよね 一等賞!」が全く気付かないうちにあの曲になる – ニコニコ動画 http://www.nicovideo.jp/watch/sm25234632

ECMAScript 2016 I18n API

ECMAScript® 2016 Internationalization API Specification がECMAScript 2016と同時にリリースされた。
I18n APIってなんだよってことで、MDN読んでた。Intl – JavaScript | MDN
specは読んでもわからんので…

I18n系のライブラリはいくつもあるし、なんでそんなのあるのって言うの読んでた。
The ECMAScript Internationalization API

ES5にもES2015あたりにも、ちょっとだけ仕組みが入ってるのをおしすすめた。
各ライブラリが個別に再実装するはめになってる。でかい変換テーブルがいる。インターフェースを決める。

そのへんか。なるほど。
まあ例によってユーザーがそのままこのAPI使うわけではなく、ライブラリ作者が楽に高速になるよね、系のアレ。fetchとかみたいな。

ブラウザ実装状況見ると、
chrome 24, firefox 29, ie 11, opera 15, safari 未実装。
chrome for android 26。モバイルはあと未実装。
なので、あーというかんじ。
ただ、safari 10に実装されることが発表されているので、mac os x sierra, ios 10で入る。
将来的にはいい感じになりそう。

ここから下は、仕様の話じゃなくて、もうあるchromeとfirefoxの実装の話。注意。

あとはだいたいMDNからのコピペ。コードを動かしてみるのは主にchrome 51。

Intl

Intlという名前空間があって、その下にオブジェクトがあるのと、あとString, Number, Dateにメソッドが生えてる。

コンストラクタ
Intl.Collator
Intl.DateTimeFormat
Intl.NumberFormat
メソッド
String.prototype.localeCompare()
Number.prototype.toLocaleString()
Date.prototype.toLocaleString()
Date.prototype.toLocaleDateString()
Date.prototype.toLocaleTimeString()

String.prototype.localeCompare()

ウムラウト区別できても関係ないよなーと思ってた。
けど、ふとひらがなカタカナ半角カナで試してみたら、なるほどーとなった。
まあブラウザ実装依存なんだろうけど、おおーってならない? そうでもないか。

'a'.localeCompare('c');
-1
'check'.localeCompare('against');
1
'a'.localeCompare('a');
0
'ä'.localeCompare('z', 'de')
-1
'ä'.localeCompare('z', 'sv')
1

# ドイツとスウェーデンでソート順が違う。ここまでMDNコピペ

'あ'.localeCompare('ア')
-1
'あ'.localeCompare('ア', 'ja')
0
# !?
'あらすか'.localeCompare('アラスカ', 'ja')
0
'あらすか'.localeCompare('アらスカ', 'ja')
0
'あらすか'.localeCompare('アラスカ', 'ja')
0

Number.prototype.toLocaleString()

プリセットでいろいろある。通貨は結構うれしい。デフォルトプリセット気に入らなかったら、設定上書きできる。
数字部分だけ色変えたいとかあるのはまあ自分で文字列切り刻んだり文字列追加したりでやれってことかな。

var number = 123456.789;
undefined
number.toLocaleString()
"123,456.789"
number.toLocaleString('de-DE')
"123.456,789"
number.toLocaleString('ar-EG')
"١٢٣٬٤٥٦٫٧٨٩"
number.toLocaleString('en-IN')
"1,23,456.789"
number.toLocaleString('zh-Hans-CN-u-nu-hanidec')
"一二三,四五六.七八九"
number.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })
"123.456,79 €"
number.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' })
"¥123,457"
number.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY', minimumFractionDigits: 2 })
"¥123,456.79"

Date.prototype.toLocaleString()

chromeやるな。 平成って文字列出てきた。でもMDNと違うぞ。でfirefoxで動かしてみたらMDN通りになった。
やっぱりブラウザ間実装差が。

var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
undefined
date.toLocaleString('en-US')
"12/20/2012, 12:00:00 PM"
date.toLocaleString('en-GB')
"20/12/2012, 12:00:00"
date.toLocaleString('ja')
"2012/12/20 12:00:00"
date.toLocaleString('ar-EG')
"٢٠‏/١٢‏/٢٠١٢ ١٢:٠٠:٠٠ م"
date.toLocaleString('ko-KR')
"2012. 12. 20. 오후 12:00:00"
date.toLocaleString('ja-JP-u-ca-japanese')
"平成24/12/20 12:00:00"

firefox 47

var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
undefined
date.toLocaleString('en-US')
"12/20/2012, 12:00:00 PM"
date.toLocaleString('ja-JP-u-ca-japanese')
"24/12/20 12:00:00"

エレクトロンならワンちゃんあるかな。

bookmarklet使えば、どのブラウザでも動くし、最高じゃない?と思ったがCSPにブロックされて全然ダメだった

便利なchrome extensionを使うたびに、chromeにロックインされていく。コレと同じ機能を持つfirefoxのaddonは〜とかダルい。
便利にchromeを使っているが、iosやandroidのchromeではchrome extensionが使えない。コレはきびしい。
ios safariでは、ios appに付属させる形でios safari用のextentionが配布できるようだ。要お布施。

各ブラウザのextention探すのもダルいのに各ブラウザのextention作るわけ無いだろ…。firefoxでchrome extentionとほぼ同じ形式で作れるようになるらしいけど調べてない。

greasemonkey系のでもいいけど、自動で適用しなくていいのなら、bookmarkletで良いのでは?
context menuに追加系のは多少だけど普段使うwebが遅くなりそうで避けたい。
ゴニョゴニョごニョーーっと処理をやって、最後にwindow.promptで出力すれば、クリップボードにアクセスしなくていいし、ユーザーに自分でコピーしてもらえばいいし、最高じゃない?と思った。

そんなに甘くなかった。

$ curl --head https://github.com/rackt/react-router
(snip)
Content-Security-Policy: default-src *; script-src assets-cdn.github.com; object-src assets-cdn.github.com; style-src 'self' 'unsafe-inline' 'unsafe-eval' assets-cdn.github.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com checkout.paypal.com collector.githubapp.com *.githubusercontent.com *.gravatar.com *.wp.com; media-src 'none'; frame-src 'self' render.githubusercontent.com gist.github.com www.youtube.com player.vimeo.com checkout.paypal.com; font-src assets-cdn.github.com; connect-src 'self' live.github.com wss://live.github.com uploads.github.com status.github.com api.github.com www.google-analytics.com api.braintreegateway.com client-analytics.braintreegateway.com github-cloud.s3.amazonaws.com; base-uri 'self'; form-action 'self' github.com gist.github.com

なるほど。

サーバー側がこう設定してある時に

外部ファイル読み込まないbookmarklet

javascript:()(function(){window.alert('foo');})

chrome46 foo のalert出る
firefox42 bookmarklet動かない
ios8 safari fooのalert出る
android5.1 chrome fooのalert出る
android5.1 firefox bookmarklet動かない

外部ファイル読み込むbookmarklet

例は省略

chrome46 csp違反で外部ファイル読み込めない
firefox42 bookmarklet動かない
あとは確認してない。

もちろんcsp設定していなければいろいろ動くが、使ってみるまでわからないのはきび
しいし、どのページでも動かしたい。

Which Browsers Can You Run Userscripts In, and How? | mturkgrind

外部ファイル使わないbookmarkletは更新が面倒。
あとnpm moduleを使って、browserifyで固めて、とか普通にやりたい。

  • desktop/laptop
    • firefox
      • greasemonkey
      • addon
    • chrome
      • tampermonkey
      • chrome extension
    • safari
      • tampermonkey for safari
      • extension
    • ie
      • greasemonkIE
      • addon
  • ios
    • safari
      • extension
  • android
    • firefox
      • greasemonkey(?) android41に入らない…
      • addon

上記サイトから引用するとこれぐらいなのかなあ。選択肢は。悲しい結末だった。
craete link 系のと はてブ数表示->はてブページにジャンプとevernoteにclipぐらいをお手軽にやりたいだけなんだけど。

nan v2対応part2

nan対応出来ると人気者になれそう | 實松アウトプットの続き。

wsが出たらengine.ioが出せて、engine.ioが出たらsocket.ioが出せて、socket.ioが出たらwebpack-dev-serverが出せて、なっが!

wsは無事出たんだけど、engine.ioを出すためには、engine.io-client, engine.io-parserが出ないとダメぽい。

bufferとかstreamとかはよくわからんので、狭めるために他の可能性を潰しに行ってみた。dependenciesと戦う。

https://github.com/socketio/engine.io-parser/pull/47
https://github.com/Raynos/after/pull/8
https://github.com/niklasvh/base64-arraybuffer/pull/5
https://github.com/jshttp/accepts/pull/11

testがないやつとか、travis-ciないやつとかは手が出せない。testないやつはどうしようもないが、travis-ciないやつは手元のiojs v3.0で動かしてみて通った。v3.2では確認してないけどまあいいんじゃないかな。外堀は大丈夫そうだとわかった。

engine.io-clientはpackagingもグズグズっぽい。
package: remove ‘xmlhttprequest’ dep to restore fix from #396

先は長い & socketio のorganization全体で反応が鈍い。

http://github.com/socketio の活動一ヶ月以上止まってるけどみんなでバカンスかな

method visibility

オブジェクト指向厨からテスト原理主義厨になったので、methodのvisibility? 全publicだ! ってやってる。
ただ、nodejsのmoduleみたいに、module.exportsに一個だけメソッド公開してやるのがいいなーってなってて、公開したくない(してもどっちでもいいけど見かけ上のシンプルさが減る)って時にどうしようか考えてる。

index.js一枚にそれやろうとするから、そうなるんであって、lib/foo.js とか内部で区切って、公開するほどではないけどテストしたいものは区切ったものに対してテストすればいいか。

libとかtestとかディレクトリ切らないで、index.js, test.js とかflatにするのがカッコイイ厨と合わさって変になってた。

書いてたら整理出来てきた。

小分けの.potと.poと.json? 巨大な.potと.poと.json?

.potファイルn個, .poファイルn個, –lang–/translation.json にしたい?

TL;DR

translation.pot 1個, translation.–lang–.po, –lang–/translation.json のパターンに収めるのがひとまず良さそう。

続き

これらの続きだけど続くとは思わず…

日本語と英語のドキュメントの同期 | 實松アウトプット
GNU gettextのフォーマット・i18nextの流れで日本語と英語を同期 | 實松アウトプット

分量

Dependency Update as a Service – Tachikoma.io トップページ、設定、FAQ、イントロダクションぐらいなので、そんなでもないはず。FAQ、イントロダクションは分量増えるのかもだけど。まだ数kBだし増えても数百kBだろう。

sphinxの場合

Sphinx では rst ファイルごと、もしくはサブディレクトリごとに 1つの pot ファイルが作成されます。

(3日目) Sphinx の文書を翻訳してみよう (gettext機能) – Hack like a rolling stone

i18next, i18next-convの場合

eg.: i18next-conv -l en -s ./locales/en.po -t ./locales/en/translation.json

1つの.poから1つの.jsonにconvertする。 ディレクトリ指定とか、複数指定とか、./localose/*.en.po とかの指定はできなかった。

別ファイル名を振って、それをnamespaceとして使うことは出来る。

accessing resources

これはこれで…。どれ読み込むのかいちいち指定するのだるいし、commonとか作りたくなってくるんだろうか。テンプレートにkey書くときも、namespace意識したくはない。

やりたいこと

開発中は各foo.json, bar.json作って、deploy時にconcat。productionには1個の–lang–/translation.jsonだけがある。テンプレートはテンプレートで、いい感じに吸収してくれる。assets pipelineだコレ。ここまでぼんやり考えたがひとまずオーバースペックすぎる。

結論

1つの巨大な translation.pot をつくって、考えるのは後回しにする。

GNU gettextのフォーマット・i18nextの流れで日本語と英語を同期

GNU gettextのフォーマット・i18nextの流れで日本語と英語を同期

TL;DR

ペライチのページの日本語/英語対応を入れた。多言語対応標準のGNU gettextの流れに乗せたつもりだけど、あんまり楽になってないし、ページ二枚作るでよかったのでは。いちおう、デザインの統一は一枚なのでやりやすい。

続き

日本語と英語のドキュメントの同期 | 實松アウトプット
このエントリーの続き。

実際の挙動

http://tachikoma.io/

基本は英語。staticなgithub page。

http://tachikoma.io/?setLng=en-US
http://tachikoma.io/?setLng=ja-JP

setLangパラメータをつけると言語を変えられる。i18n対応部分は i18next使った。ある程度ホントのi18n対応 単数/複数・男性/女性(contextを指定する、ちょっと簡略)してるライブラリ。なお、時刻、日時周りはまた別のライブラリを使う必要がありそう。ある程度動的に使う用なライブラリなので、staticにhtmlの中身ごとに出し分けたい、程度にはオーバースペックかもしれない。

一度setLngパラメーターをつけると、それをcookieに保存してくれる。便利。オールインワン。

Alternative

ググった限りでは、jedi18next がGNU gettextベースでは良さそうに見えた。どちらも、dom組み立て終わってから、キー見て差し替えるので、特にdefaultがen-US以外のユーザーの場合は、普通に使うには厳しく感じるかも。まあとりあえずよい。

手順

GNU gettextな手順

素材 -> .pot -> .po -> .mo

に載せるうまい方法がググれなくて、なんかもうちょっとあるだろ、という感じの手順で変換した。

.html -(pandoc)-> .rst -(sphinx)-> .pot -(GNU gettext)-> .po -(翻訳)-> -(i18next-conv)-> .json

xgettextが.rst読めるかと思ったところで手間取った。xgettext rst読めると思うじゃん…
Resource String TablereStructuredText(reST)だと。

あとsphinxってハンズオン一回やったきりだったので全く覚えてなかった。

初回はコレで、2回目以降はこれ。

.html -(手作業)-> .pot -(GNU gettext)-> .po -(翻訳)-> -(i18next-conv)-> .json

感想

自分以外触るのは無理だろ、ッて感じなので、ページ二枚あるのとあんまり変わらない。gulpかnpmのコマンドで出来るようにしておけば、まだましなのか?? いちおう英語に全部fallbackする(はず)なので(設定足りてないかも dev localeに積む必要がある?)、翻訳漏れは合っても文言漏れがなくなるメリットがイイ。

translation.jsonを順番に探索していく(ja-JP -> ja -> dev)から必ず404出まくるのが心理的にもやっと来る。

一回やってみて納得したのでよかった。

他の事例(Edited 2014-11-08 12:02)

jsxgettext Pootle そういうのもあるのか。

手探りだったけど、大筋では方向性間違ってなさそう。よかった。

手順

# TL;DR

Use gettext format and i18next flow.

# Iteration

$ brew install gettext # convert .pot to .po
$ npm install -g i18next-conv # convert .po to .json

Edit index.html
Add data-i18n attribute
This is msgid
(Caution: Remove period from msgid!)

Add msgid + msgstr to _build/index.pot

$ msgmerge -U _build/index.en.po _build/index.pot
$ msgmerge -U _build/index.ja.po _build/index.pot

Translate *.po

$ i18next-conv -l ja -s ./_build/index.ja.po -t ./locales/ja/translation.json
$ i18next-conv -l en -s ./_build/index.en.po -t ./locales/en/translation.json

Done!

# Initial

$ brew install gettext
$ npm install -g i18next-conv
$ cabal install pandoc
$ pip install sphinx

# https://github.com/tachikomaio/maguro.tachikoma.io/pull/32
index.html to index.rst (pandoc)
$ ~/.cabal/bin/pandoc -f html -t rst -o index.rst index.html
index.rst to index.pot (sphinx)
$ make gettext

$ msginit --locale=ja --input=_build/locale/index.pot --output=locale/ja/LC_MESSAGES/index.po

# See: (3日目) Sphinx の文書を翻訳してみよう (gettext機能) Hack like a rolling stone
# http://tk0miya.hatenablog.com/entry/20111203/p1

i18n-step.txt

Ship boolify-string v0.1.0 いい感じに文字列をboolにする

いい感じに文字列をboolにする boolify-string v0.1.0をリリースした。

ユースケース

環境変数に書いた設定(true/false/TRUE)などをいい感じに使える。

if (boolifyString(process.env.CI)){ something_do(); }

examples

var boolifyString = require('boolify-string');

boolifyString('true');// #=> true
boolifyString('TRUE');// #=> true
boolifyString('True');// #=> true
boolifyString('false');// #=> false

boolifyString('{}');// #=> true
boolifyString('foo');// #=> true
boolifyString('');// #=> false
boolifyString('1');// #=> true
boolifyString('-1');// #=> true
boolifyString('0');// #=> false
boolifyString('[]');// #=> true
boolifyString('undefined');// #=> false
boolifyString('null');// #=> false

node-boolify-string
boolify-string

強力ツールチェーンで書くhubot-script: Ship generator-hubot-script-gulp v0.1.0

強力ツールチェーンでhubot-scriptを書くための generator-hubot-script-gulp v0.1.0をリリースした。

This generator provides:
– hubot-script based on standard example
– coffeescript
– gulp
– coffeelint
– code coverage (istanbul)
– travis-ci ready
– coveralls ready
– mocha
– sinon
– power-assert

How to use

npm i generator-hubot-script-gulp -g
mkdir hubot-you-want-to-generate && cd $_
yo hubot-script-gulp

こんなかんじに生成されて最強に見える。

$ tree -I 'node_modules|.idea' -a
.
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── coffeelint.json
├── gulpfile.coffee
├── index.coffee
├── package.json
├── src
│   └── you-want-to-generate.coffee
└── test
    └── you-want-to-generate-test.coffee

中身

https://github.com/desmondmorris/generator-hubot-script をforkして https://github.com/youngmountain/generator-node-gulp をまぶした。