Mantisの言語ファイルの翻訳手順

本体の翻訳ファイルも翻訳手順を作ってみました。

訳文の抜き出し

一般的には xgettext で抜き出しますが元に戻すことができないので、また po4a パッケージを利用させてもらいました。

ただ po4a は汎用的な読み込みってできないのでフォーマットごとに Perl のプログラムを書かないといけません。

po4a の構造

Ubuntuの場合 po4a は /usr/share/perl5/Locale/Po4a にセットアップされています。

root@ubuntu-vm:/usr/share/perl5/Locale/Po4a# ls
BibTeX.pm   Docbook.pm     LaTeX.pm  Pod.pm      Text.pm
Chooser.pm  Guide.pm       Man.pm    Sgml.pm     TransTractor.pm
Common.pm   Ini.pm         TeX.pm      Xhtml.pm  Dia.pm
KernelHelp.pm  Po.pm     Texinfo.pm  Xml.pm

こんな感じで入っています。本体と読み込みの pm が同じ場所にありますね。

po4a の読み込みフィルターの構造

http://po4a.alioth.debian.org/man/man3pm/Locale::Po4a::TransTractor.3pm.php

この辺を参考に parse() を実装すればよいのがわかります。

ベースのフィルタ選択

Text を最初に使おうかと思いましたが Ini が一番近いのでこれを利用します。といってもほぼそのまま利用できます。。。実は””で囲まれた文字を抜き出す処理なので、’’も追加してあげれば終了(笑)

フィルタ作成

基本的にはパッケージ名を変えて、if文の場所を””をコピーして’’を作ってあげるだけです。

/usr/share/perl5/Locale/Po4a/Php.pm

# Locale::Po4a::Ini -- Convert ini files to PO file, for translation.
# $Id: Ini.pm,v 1.2 2006/08/23 19:30:30 nekral-guest Exp $
#
# This program is free software; you may redistribute it and/or modify it
# under the terms of GPL (see COPYING).
#

############################################################################
# Modules and declarations
############################################################################

use Locale::Po4a::TransTractor qw(process new);
use Locale::Po4a::Common;

package Locale::Po4a::Php;

use 5.006;
use strict;
use warnings;

require Exporter;

use vars qw(@ISA @EXPORT $AUTOLOAD);
@ISA = qw(Locale::Po4a::TransTractor);
@EXPORT = qw();

my $debug=0;

sub initialize {}


sub parse {
	my $self=shift;
	my ($line,$ref);
	my $par;

	LINE:
	($line,$ref)=$self->shiftline();

	while (defined($line)) {
		chomp($line);
		print STDERR  "begin\n" if $debug;

		if ($line =~ /\"/) {
			print STDERR  "Start of line containing \".\n" if $debug;
			# Text before the first quote
			$line =~ m/(^[^"\r\n]*")/;
			my $pre_text = $1;
			print STDERR  "  PreText=".$pre_text."\n" if $debug;
			# The text for translation
			$line =~ m/("[^\r\n]*")/;
			my $quoted_text = $1;
			print STDERR  "  QuotedText=".$quoted_text."\n" if $debug;
			# Text after last quote
			$line =~ m/("[^"\n]*$)/;
			my $post_text = $1;
			print STDERR  "  PostText=".$post_text."\n" if $debug;
			# Remove starting and ending quotes from the translation text, if any
			$quoted_text =~ s/^"//g;
			$quoted_text =~ s/"$//g;
			# Translate the string it
			$par = $self->translate($quoted_text, $ref);
			# Escape the \n characters
			$par =~ s/\n/\\n/g;
			# Now push the result
			$self->pushline($pre_text.$par.$post_text."\n");
			print STDERR  "End of line containing \".\n" if $debug;
		} elsif ($line =~ /\'/) {
			print STDERR  "Start of line containing '.\n" if $debug;
			# Text before the first quote
			$line =~ m/(^[^'\r\n]*')/;
			my $pre_text = $1;
			print STDERR  "  PreText=".$pre_text."\n" if $debug;
			# The text for translation
			$line =~ m/('[^\r\n]*')/;
			my $quoted_text = $1;
			print STDERR  "  QuotedText=".$quoted_text."\n" if $debug;
			# Text after last quote
			$line =~ m/('[^'\n]*$)/;
			my $post_text = $1;
			print STDERR  "  PostText=".$post_text."\n" if $debug;
			# Remove starting and ending quotes from the translation text, if any
			$quoted_text =~ s/^'//g;
			$quoted_text =~ s/'$//g;
			# Translate the string it
			$par = $self->translate($quoted_text, $ref);
			# Escape the \n characters
			$par =~ s/\n/\\n/g;
			# Now push the result
			$self->pushline($pre_text.$par.$post_text."\n");
			print STDERR  "End of line containing '.\n" if $debug;
		}
		else
		{
			print STDERR "Other stuff\n" if $debug;
			$self->pushline("$line\n");
		}
		# Reinit the loop
		($line,$ref)=$self->shiftline();
	}
}

##############################################################################
# Module return value and documentation
##############################################################################

1;
__END__

=head1 NAME

Locale::Po4a::Ini - Convert ini files from/to PO files

=head1 DESCRIPTION

Locale::Po4a::Ini is a module to help the translation of INI files into other
[human] languages.

The module searches for lines of the following format and extracts the quoted
text:

identificator="text than can be translated"

NOTE: If the text is not quoted, it will be ignored.

=head1 SEE ALSO

L<po4a(7)|po4a.7>, L<Locale::Po4a::TransTractor(3pm)>.

=head1 AUTHORS

 Razvan Rusu <rrusu@bitdefender.com>
 Costin Stroie <cstroie@bitdefender.com>

=head1 COPYRIGHT AND LICENSE

Copyright 2006 by BitDefender

This program is free software; you may redistribute it and/or modify it
under the terms of GPL (see the COPYING file).

=cut

po ファイルの作成

po4a-gettextize -f php -m strings_english.txt > strings_japanese.po

こんな感じで php のフォーマットが利用できるようになります。

po の翻訳

OmegaTだと。。。””が付いている状態での訳文になりますね。ちょっと気持ち悪いけれど仕方ないです。がりがりと翻訳します。

po から php への翻訳文反映

po4a-translate -f php -m strings_english.txt -p strings_japanese.po >strings_japanese.txt

結構簡単にいきますね。

問題点

OmegaT 側の問題ですが””が付いている訳文になる。po の状態だと関係ないのでこれはいいとして、あとはライセンスの部分をどうするかですね。ここは手作業で書き換えるかなって思っています。sjisとeucjp版の作成もある程度手作業かな?

訳の対象が増えた場合には po をマージするとかいろいろな手順が本当はありますが、そこは翻訳メモリの機能を使って、毎回新しい po を作成。同じ翻訳文は翻訳メモリから自動設定がいいかなって思っています。

全般的にはPHPの変数で翻訳ファイルを処理しているOSSとかは同じ手順で翻訳できるかな? この他に翻訳メモリ側のノウハウとして、基準となる翻訳対応表のグロッサリーや、翻訳結果の中間方式である tmx ファイルなどを現在の翻訳ファイルからPHPで生成してあげていたりします。

あとは。。。1.1.2系から1.2.x系で結構訳文が増えています。が、、、実質的な翻訳はしていないのでカバー率は変わりません(笑)

Mantisの翻訳を考えている人がいましたら、連絡いただければお手伝いしますのでコメントしてもらえればと思います。

あと消えている可能性があるかもしれませんが、翻訳状況とコンフィグの日本語訳の対応表を作ったのであげておきます。