gettext の .po をバージョン管理しやすく加工する方法

# 前提
まずは `gettext` の基本的な手順の説明です。

`main.cpp` に `_()` マクロで gettext が使用されている前提です。

```
xgettext --keyword='_' -o foo.pot main.cpp
```

このコマンドで `foo.pot` が出力されます。`*.pot` はバージョン管理しないようにしてください。

```
msginit --locale=ja --input=foo.pot
```

このコマンドで `foo.pot` から日本語用の `ja.po` が生成されます。
これが通常の `gettext` を利用した初期化手順です。

次に `main.cpp` 翻訳対象のテキストが増えた場合の手順ですが、先程出てきた `xgettext` を再度使います。

```
xgettext --keyword='_' -o foo.pot main.cpp
```

しかし、次に `ja.po` を `msginit` で生成してしまうと翻訳済みのテキストが全て上書きされて失われてしまいます。そのため `gettext` には `msgmerge` というコマンドが用意されています。

```
msgmerge ja.po foo.pot -o ja.po
```

このようにすると、元の `ja.po` に新たに生まれた `foo.pot` の翻訳されていないテキストが追加された新しい `ja.po` が生まれます。

# 問題
例えば `make` と打てばビルドから `*.pot`, `*.po`, `*.mo` も生成したいようなプロジェクトだった場合、例えばこのような Makefile となるでしょう。

```
.PHONY: all
all:
  gcc main.cpp -o main
  xgettext --keyword='_' -o foo.pot main.cpp
  msgmerge ja.po foo.pot -o ja.po

.PHONY: init-i18n
init-i18n:
  xgettext --keyword='_' -o foo.pot main.cpp
  msginit --locale=ja --input=foo.pot
```

この `Makefile` であれば、最初だけ `make init-i18n` と入力して、それ以降は `make` でコンパイルと `ja.po` の生成ができます。(`.mo` の生成は割愛してます)

`main.cpp` にテキストが追加されていないときに `make` をもう一度実行することも当然あるのですが、このときに、バージョン管理上の問題が発生します。その例として以下の diff が作られます。

```
diff --git a/ja.po b/ja.po
index 529e532..10a871e 100644
--- a/ja.po
+++ b/ja.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-09-20 20:07+0900\n"
+"POT-Creation-Date: 2018-09-20 20:08+0900\n"
 "PO-Revision-Date: 2018-09-20 20:07+0900\n"
 "Last-Translator: Toshiyuki Hirooka <mail@address>\n"
 "Language-Team: Japanese\n"
```

これは `make` を実行した時間が `foo.pot` を生成した時間であり、それが `ja.po` に `msgmerge` で結合されたことによる問題です。生成時刻はバージョン管理を行う必要性がないと考えてよいのですが、この手順ではどうしてもこの diff が発生してしまいます。

また、`main.cpp` に変更や新たなテキストが生成されたときの問題もあります。

```
index 016f223..5a60241 100644
--- a/ja.po
+++ b/ja.po
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"

-#: main.cpp:2
+#: main.cpp:3
+msgid "Yahoo!"
+msgstr ""
+
+#: main.cpp:4
 msgid "Hello, World!"
 msgstr "こんにちは、世界！"
```

この diff は "Hello, World!" というテキストの登場位置が変わったり、新たな "Yahoo!" というテキストが追加されていることを示しています。
例えばこれをバージョン管理でコミットすると、`+#: main.cpp:4` の行がコンフリクトする可能性があります。なぜなら、"Hello, World!" の位置が変わる修正は他者が行う可能性があり git などのバージョン管理ソフトではそれを許容しているのに、その場合に `ja.po` で同じ行に対して他者と競合してしまうからです。

# 解決方法
長くなりましたが、解決方法は簡単です。

```
.PHONY: all
all:
	gcc main.cpp -o main
	xgettext --keyword='_' -o foo.pot main.cpp
	msgmerge ja.po foo.pot -o ja.po && msgcat ja.po --no-location --no-wrap --sort-output --output ja.po && cat ja.po | grep -v POT-Creation-Date > tmp.po && mv tmp.po ja.po

.PHONY: init-i18n
init-i18n:
	xgettext --keyword='_' -o foo.pot main.cpp
	msginit --locale=ja --input=foo.pot
```

先程の `Makefile` をこのように変更しました。この変更では次のことをやっています。

- `ja.po` を `msgcat` を使って登場位置の削除やテキストの順番のソートなどを行っている
- `POT-Creation-Date` の行を削除している

これで新たにテキストが追加された時、削除された時、変更された時だけ次のように diff が発生します。

```
diff --git a/ja.po b/ja.po
index c6c235a..1d69722 100644
--- a/ja.po
+++ b/ja.po
@@ -18,3 +18,6 @@ msgstr ""

 msgid "Hello, World!"
 msgstr "こんにちは、世界！"
+
+msgid "Yahoo!"
+msgstr ""
```

# 余談
取り急ぎだったので甘い作りですが、`POT-Creation-Date` の regex をもう少しキレイにしたり、`tmp.po` を一旦作らなくても良いような修正をしたほうが安全です。

以上です。