LoginSignup
1
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-09-20

前提

まずは 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.pomsginit で生成してしまうと翻訳済みのテキストが全て上書きされて失われてしまいます。そのため 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.pomsgmerge で結合されたことによる問題です。生成時刻はバージョン管理を行う必要性がないと考えてよいのですが、この手順ではどうしてもこの 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.pomsgcat を使って登場位置の削除やテキストの順番のソートなどを行っている
  • 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 を一旦作らなくても良いような修正をしたほうが安全です。

以上です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1