diff options
-rw-r--r-- | dist.ini | 2 | ||||
-rw-r--r-- | lib/Locale/POFileManager.pm | 20 | ||||
-rw-r--r-- | lib/Locale/POFileManager/File.pm | 112 | ||||
-rw-r--r-- | t/001-basic.t | 19 | ||||
-rw-r--r-- | t/002-create.t | 49 | ||||
-rw-r--r-- | t/data/001/de.po | 1 | ||||
-rw-r--r-- | t/data/001/ru.po | 1 |
7 files changed, 121 insertions, 83 deletions
@@ -10,7 +10,7 @@ abstract = Helpers for keeping a set of related .po files in sync [Prereq] File::Temp = 0.19 List::MoreUtils = 0 -Locale::PO = 0 +Locale::Maketext::Lexicon = 0 Moose = 0.90 MooseX::Types::Path::Class = 0 Scalar::Util = 0 diff --git a/lib/Locale/POFileManager.pm b/lib/Locale/POFileManager.pm index b32b076..54317ca 100644 --- a/lib/Locale/POFileManager.pm +++ b/lib/Locale/POFileManager.pm @@ -154,9 +154,8 @@ sub stub_msgstr { my %args = @_; my $canonical_msgstr; $canonical_msgstr = - $weakself->canonical_language_file->entry_for($args{msgid})->msgstr + $weakself->canonical_language_file->msgstr($args{msgid}) if $weakself; - $canonical_msgstr =~ s/^"|"$//g if defined($canonical_msgstr); return $msgstr->( %args, defined($canonical_msgstr) ? (canonical_msgstr => $canonical_msgstr) : (), @@ -200,13 +199,26 @@ sub add_language { confess("Can't overwrite existing language file for $lang") if -e $file->stringify; + my $canon_pofile = $self->canonical_language_file; + + my $fh = $file->openw; + $fh->binmode(':utf8'); + $fh->print(qq{msgid ""\n}); + $fh->print(qq{msgstr ""\n}); + for my $header_key ($canon_pofile->headers) { + $fh->print(qq{"$header_key: } + . $canon_pofile->header($header_key) + . qq{\\n"\n}); + } + $fh->print(qq{\n}); + $fh->close; + my $msgstr = $self->stub_msgstr; my $pofile = Locale::POFileManager::File->new( file => $file, defined($msgstr) ? (stub_msgstr => $msgstr) : (), ); - $pofile->add_entry($self->canonical_language_file->entry_for('')); - $pofile->save; + $self->_add_file($pofile); } diff --git a/lib/Locale/POFileManager/File.pm b/lib/Locale/POFileManager/File.pm index 196ab41..b024c8c 100644 --- a/lib/Locale/POFileManager/File.pm +++ b/lib/Locale/POFileManager/File.pm @@ -4,9 +4,13 @@ use Moose; use MooseX::Types::Path::Class qw(File); use List::MoreUtils qw(any); use List::Util qw(first); -use Locale::PO; +use Locale::Maketext::Lexicon::Gettext; use Scalar::Util qw(reftype); +require Locale::Maketext::Lexicon; +Locale::Maketext::Lexicon::set_option(decode => 1); +Locale::Maketext::Lexicon::set_option(allow_empty => 1); + =head1 NAME Locale::POFileManager::File - A single .po file @@ -83,82 +87,74 @@ has stub_msgstr => ( isa => 'Str|CodeRef', ); -=head2 entries - -Returns a list of L<Locale::PO> objects corresponding to translation entries in -the file. - -=cut - -=head2 add_entry - -Adds a new translation entry to the file. This can be provided either as a -L<Locale::PO> object directly, or as a hash of options to pass to the -L<Locale::PO> constructor (except without the leading dashes). - -=cut - =head2 msgids Returns a list of msgids found in the file. =cut -has entries => ( - traits => [qw(Array)], - isa => 'ArrayRef[Locale::PO]', - lazy => 1, - builder => '_build_entries', - init_arg => undef, - handles => { - entries => 'elements', - _add_entry => 'push', - msgids => - [ map => sub { my $m = $_->msgid; $m =~ s/^"|"$//g; $m } ], +has lexicon => ( + traits => [qw(Hash)], + isa => 'HashRef', + lazy => 1, + default => sub { + my $self = shift; + return Locale::Maketext::Lexicon::Gettext->parse($self->file->slurp); + }, + handles => { + msgids => 'keys', + has_msgid => 'exists', + _remove_msgid => 'delete', + msgstr => 'get', + _add_lexicon_entry => 'set', }, ); -sub _build_entries { +has headers => ( + traits => [qw(Hash)], + isa => 'HashRef', + lazy => 1, + default => sub { + my $self = shift; + my $ret = {}; + $ret->{$_} = $self->_remove_msgid("__$_") + for map { s/^__//; $_ } grep { /^__/ } $self->msgids; + return $ret; + }, + handles => { + headers => 'keys', + header => 'get', + }, +); + +sub BUILD { my $self = shift; + my $filename = $self->file->stringify; + confess "Can't read file " . $filename + unless -r $filename; - return (-r $filename) ? Locale::PO->load_file_asarray($filename) : []; + # strip the headers out of the lexicon hash + $self->headers; } sub add_entry { my $self = shift; - if (@_ == 1) { - $self->_add_entry($_[0]); - } - else { - my %args = @_; - $args{"-$_"} = delete $args{$_} for keys %args; - $self->_add_entry(Locale::PO->new(%args)); - } -} - -=head2 entry_for - -Returns the L<Locale::PO> object corresponding to the given msgid. - -=cut + my %args = @_; + my ($msgid, $msgstr) = @args{qw(msgid msgstr)}; -sub entry_for { - my $self = shift; - my ($msgid) = @_; - return first { $_->msgid eq '"' . $msgid . '"' } $self->entries; -} + return if $self->has_msgid($msgid); -=head2 save + my $needs_newline = ($self->file->slurp !~ /\n\n$/); + my $fh = $self->file->open('>>'); + $fh->binmode(':utf8'); + $fh->print(qq{\n}) if $needs_newline; -Writes the current contents of the file back out to disk. - -=cut + $fh->print(qq{msgid "$msgid"\n}); + $fh->print(qq{msgstr "$msgstr"\n}) if defined $msgstr; + $fh->print(qq{\n}); -sub save { - my $self = shift; - - Locale::PO->save_file_fromarray($self->file->stringify, [$self->entries]); + $self->_add_lexicon_entry($msgid => $msgstr); } =head2 language @@ -218,8 +214,6 @@ sub add_stubs_from { defined($msgstr) ? (msgstr => $msgstr) : (), ); } - - $self->save; } __PACKAGE__->meta->make_immutable; diff --git a/t/001-basic.t b/t/001-basic.t index 05e9299..6bda558 100644 --- a/t/001-basic.t +++ b/t/001-basic.t @@ -8,6 +8,16 @@ use Path::Class; use Locale::POFileManager; +sub header_is { + my ($got, $expected) = @_; + local $Test::Builder::Level = $Test::Builder::Level + 1; + my @got = split /\n/, $got, -1; + my @expected = split /\n/, $expected, -1; + is_deeply([@got[0..1], sort @got[2..$#got]], + [@expected[0..1], sort @expected[2..$#expected]], + "got the right header"); +} + { my $manager = Locale::POFileManager->new( base_dir => 't/data/001', @@ -34,7 +44,7 @@ use Locale::POFileManager; {ru => [], hi => [], en => [], de => []}, "got the correct missing messages"); - my $header = <<'HEADER'; + my $expected_header = <<'HEADER'; msgid "" msgstr "" "MIME-Version: 1.0\n" @@ -46,7 +56,7 @@ HEADER my %langs = ( en => qq{msgid "foo"\nmsgstr "foo"\n\n} . qq{msgid "bar"\nmsgstr "bar"\n\n} - . qq{msgid "baz"\nmsgstr "baz"\n\n}, + . qq{msgid "baz"\nmsgstr "baz"\n}, ru => qq{msgid "foo"\nmsgstr "foo"\n\n} . qq{msgid "bar"\n\n} . qq{msgid "baz"\n\n}, @@ -59,7 +69,10 @@ HEADER ); for my $file ($manager->files) { - is($file->file->slurp, $header . $langs{$file->language}, + my $contents = $file->file->slurp; + my ($header, $data) = ($contents =~ /^(.*?\n\n)(.*)$/s); + header_is($header, $expected_header); + is($data, $langs{$file->language}, "got the right stubs"); } } diff --git a/t/002-create.t b/t/002-create.t index 13a6611..92ec881 100644 --- a/t/002-create.t +++ b/t/002-create.t @@ -8,6 +8,16 @@ use Path::Class; use Locale::POFileManager; +sub header_is { + my ($got, $expected) = @_; + local $Test::Builder::Level = $Test::Builder::Level + 1; + my @got = split /\n/, $got, -1; + my @expected = split /\n/, $expected, -1; + is_deeply([@got[0..1], sort @got[2..$#got]], + [@expected[0..1], sort @expected[2..$#expected]], + "got the right header"); +} + { my $dir = File::Temp->newdir; my $from_dir = dir('t/data/002'); @@ -15,8 +25,8 @@ use Locale::POFileManager; for my $file ($from_dir->children) { copy($file->stringify, $dir->dirname); } - my $header = $tmpdir->file('en.po')->slurp; - $header =~ s/\n\n.*/\n\n/s; + my $expected_header = $tmpdir->file('en.po')->slurp; + $expected_header =~ s/\n\n.*/\n\n/s; my $manager = Locale::POFileManager->new( base_dir => $dir->dirname, @@ -34,8 +44,7 @@ use Locale::POFileManager; "correct directory contents after creation"); for my $lang (qw(ru hi)) { - is($tmpdir->file("$lang.po")->slurp, $header, - "got the right header in $lang.po"); + header_is(scalar($tmpdir->file("$lang.po")->slurp), $expected_header); } $manager->language_file('ru')->add_entry( @@ -45,7 +54,7 @@ use Locale::POFileManager; is_deeply([sort $manager->language_file('ru')->msgids], ['', qw(baz)], "created new entry successfully"); - is($manager->language_file('ru')->entry_for('baz')->msgstr, '"Zab"', + is($manager->language_file('ru')->msgstr('baz'), 'Zab', "correct entry created"); is_deeply([sort $manager->language_file('hi')->msgids], @@ -61,20 +70,28 @@ use Locale::POFileManager; } my %langs = ( - en => qq{msgid "foo"\nmsgstr "foo"\n\n} - . qq{msgid "bar"\nmsgstr "bar"\n\n} - . qq{msgid "baz"\nmsgstr "baz"\n\n}, - hi => qq{msgid "foo"\n\n} - . qq{msgid "bar"\n\n} - . qq{msgid "baz"\n\n}, - ru => qq{msgid "baz"\nmsgstr "Zab"\n\n} - . qq{msgid "foo"\n\n} - . qq{msgid "bar"\n\n}, + en => [qq{msgid "foo"\nmsgstr "foo"\n\n} + . qq{msgid "bar"\nmsgstr "bar"\n\n} + . qq{msgid "baz"\nmsgstr "baz"\n}, + qq{}], + hi => [qq{}, + qq{msgid "foo"\n\n} + . qq{msgid "bar"\n\n} + . qq{msgid "baz"\n\n}], + ru => [qq{msgid "baz"\nmsgstr "Zab"\n\n}, + qq{msgid "foo"\n\n} + . qq{msgid "bar"\n\n}], ); for my $lang (keys %langs) { - is($manager->language_file($lang)->file->slurp, $header . $langs{$lang}, - "files created properly"); + my $contents = $manager->language_file($lang)->file->slurp; + my ($header, $data) = ($contents =~ /^(.*?\n\n)(.*)$/s); + header_is($header, $expected_header); + my $fixed = substr($data, 0, length($langs{$lang}->[0]), ''); + is($fixed, $langs{$lang}->[0], "existing data untouched"); + is_deeply([sort split /\n\n/, $data], + [sort split /\n\n/, $langs{$lang}->[1]], + "correct new msgids added"); } } diff --git a/t/data/001/de.po b/t/data/001/de.po index b8aa9a8..da72c60 100644 --- a/t/data/001/de.po +++ b/t/data/001/de.po @@ -12,3 +12,4 @@ msgstr "bar" msgid "baz" msgstr "baz" + diff --git a/t/data/001/ru.po b/t/data/001/ru.po index 97a8e7f..3cf4e46 100644 --- a/t/data/001/ru.po +++ b/t/data/001/ru.po @@ -6,3 +6,4 @@ msgstr "" msgid "foo" msgstr "foo" + |