S9y 自体のインストールはスムーズに行ったけど、日付表示の日本語の部分が文字化けを起こしていた。
具体的にはエントリの日付やカレンダーの月の部分。
本来、2006年 3月 16(木曜日) と表示されるのだが、2006年 3?? 16(????) となっていた。
[原因]
Serendipity の locale の設定の仕方と、Serindipty が期待する、Serendipity を動かしているシステムのデフォルトの locale がかみ合ってない?って感じですた。
OS - Debian WOODY
default locale - EUC-JP
[対処法]
下記のいずれかを適用する。
1.Serendipity 動作時に渡す locale 設定値を決め打ちか、複数ある値の渡す順番を変更する。
(システムによっては UTF-8 が使用できないのでその場合は、2.や3.を適用する)
serendipity/lang/UTF-8/serendipity_lang_ja.inc.php 内の
@define('DATE_LOCALES', 'ja,jp,ja_JP.UTF-8');
の行をコメントアウトし、
@define('DATE_LOCALES', 'ja_JP.UTF-8,ja,jp');
のように ja_JP.UTF-8 を一番左に持ってくるか(何故左かは後述)、
@define('DATE_LOCALES', 'ja_JP.UTF-8');
もしくは 'ja_JP.UTF-8' のみにする。
2.日付を英語表記にする(日本語表記を使わない)
locale を C にする。
serendipity/lang/UTF-8/serendipity_lang_ja.inc.php 内の
@define('DATE_LOCALES', 'ja,jp,ja_JP.UTF-8');
の行をコメントアウトし、
@define('DATE_LOCALES', 'C');
とする。
3.locale に依存しないフォーマットに変更する。
serendipity/lang/UTF-8/serendipity_lang_ja.inc.php 内の
@define('DATE_FORMAT_ENTRY', '%Y年 %B %e(%A)');
をコメントアウトし、
@define('DATE_FORMAT_ENTRY', '%Y %m %e');
のようにする。詳しくは、
strftime フォーマットを参照。
[詳細]
Serendipity での日本語文字コードは UTF-8 のみ対応で、その日付表示は strftime 関数を使用している(date を使ってる部分もある)。
そして日本語日付フォーマットを定義しているのが、
serendipity/lang/UTF-8/serendipity_lang_ja.inc.php 内の
@define('DATE_FORMAT_ENTRY', '%Y年 %B %e(%A)');
という行。
初め、年だけ表示されていて月・曜日が化けてたので何かと思ったらこれで、
化けていた個所は、%B %A の出力。
試しに、ブラウザの文字コードを UTF-8 から EUC-JP にしたら、日付の文字化けが直り、逆に正常だった部分が文字化けに。
自分の中では、プログラム(Serendipity)側で出力する文字を全てエンコードしているのかと思ったら、どうやらそうでないらしい。
Serendipity で扱われる日本語コードは UTF-8 としているが、少なくともシステムから受け取った文字列はそのまま出力している。また、php.ini で PHP そのものの日本語設定が他の文字コードに設定されている場合は、エントリ等日本語そのものが文字化ける。
使用する言語及び locale は、
serendipity/lang/UTF-8/serendipity_lang_ja.inc.php 内で
@define('LANG_CHARSET', 'UTF-8');
@define('DATE_LOCALES', 'ja,jp,ja_JP.UTF-8');
と宣言している。
LANG_CHARSET に関しては、UTF-8 の使用を”前提とする”という風に解釈しておいた方がよさげ。
内部で文字列を扱う際に、 UTF-8 に変換されるって訳じゃないみたい。
問題の strftime 関数は setlocale 関数で設定された locale に従い、そしてその結果はシステムの localse 設定に依存され出力表示が変化する。
@define('DATE_FORMAT_ENTRY', '%Y年 %B %e(%A)'); で設定されたフォーマットに従い、
locale が C (English) の場合は、文字コード ASCII で 2006年 March 16(Thursday) となるし、
ja_JP.UTF-8 の場合は、文字コード UTF8 で 2006年 3月 16(木曜日) となり、
ja_JP.eucJP の場合は、文字コード EUC-JP で 2006年 3月 16(木曜日) となる。
ややこしいのが ja_JP.UTF-8 の時と ja_JP.eucJP の場合。
文字コードを意識しない表面的な表示は 2006年 3月 16(木曜日) とまったく一所だが、内部データとしては別物になる。
Serendipity 内の locale の設定は、
serendipity/serendipity_config.inc.php の 306行目辺り、
/
Set current locale, if any has been defined
*/
if (defined('DATE_LOCALES')) {
$locales = explode(',', DATE_LOCALES);
foreach ($locales as $locale) {
$locale = trim($locale);
if (setlocale(LC_TIME, $locale) == $locale) {
break;
}
}
}
のこれだけ。
@define('DATE_LOCALES', 'ja,jp,ja_JP.UTF-8'); で設定されている値を左から順に
ja→jp→ja_JP.UTF-8 と評価し、最初にマッチした値をそのまま適用され、適用したものが UTF-8 かどうかの確認までしていない。
この blog を動かしている環境(Debian) では、
/etc/locale.alias で
japanese ja_JP.eucJP
japanese.euc ja_JP.eucJP
ja ja_JP.eucJP
ja_JP ja_JP.eucJP
ja_JP.EUC ja_JP.eucJP
ja_JP.ujis ja_JP.eucJP
japanese.sjis ja_JP.SJIS
と定義されているため最初の ja がセットされるとその実態は ja_JP.eucJP となる。
この為、strftime の出力結果(システムのデフォルト locale)が EUC-JP、
Serendipity デフォルトの UTF-8 が混在する形となりとなり日付表示の文字化けを引き起こしていた。
[考察]
初めから locale の実装(?)関してとあたりを付けられていれば早かったのだろうが、知識に乏しく解決まで時間が掛かってしまった。
実際検索すると他のアプリケーションでも同様の症状・同じ対処で解決しているのが見受けられた。
いわゆる多言語化は物凄い難度な事なのだろうけど、
locale の設定に関して現コードの実装でなら
@define('DATE_LOCALES', 'ja_JP.UTF-8,ja,jp');
のように先に実体というか細かい locale 名を渡すようにして、マッチしないようなら ja 等のエイリアス名を渡すようにした方がいいと思う。
そういう単純な話じゃないのかな?(笑
[参考文献]
Linux における日本語ロケールに関する指針
日付の文字化けについ て(解決)
ロケールを設定する
Re: Sylpheed が起動しなくなった
1. locale の設定
続・最後の「/」が省略される検索サイト対策
こーひーをぶんなぐれ! - localeの設定