diff options
| -rwxr-xr-x | markup/pod-samples/pod/live-manual/tools/bin/po-stats.pl | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/markup/pod-samples/pod/live-manual/tools/bin/po-stats.pl b/markup/pod-samples/pod/live-manual/tools/bin/po-stats.pl new file mode 100755 index 0000000..bfd763e --- /dev/null +++ b/markup/pod-samples/pod/live-manual/tools/bin/po-stats.pl @@ -0,0 +1,99 @@ +#!/usr/bin/env perl +# +# po-stats - what is translated, per language and per file +# +# The question before any translation work is where the effort should go, and +# a .po file does not answer it by looking at it. gettext counts three states +# and they are not the same thing: +# +# translated a msgstr with content and no fuzzy flag. This is what +# reaches the document. +# fuzzy a msgstr with content that po4a will not use, because the +# source changed under it. The work exists and is not being +# seen; a reviewer clearing the flag is cheaper than a +# translator starting over. +# untranslated an empty msgstr. sisu falls back to the source text, so +# the document is readable and in the wrong language. +# +# Fuzzy is the interesting column. A language showing many fuzzy entries has +# had work done that a source edit has taken out of use, and clearing them is +# the cheapest translation available. +# +# usage: po-stats.pl (all languages, summary) +# po-stats.pl --files de (per file, one language) +# +use strict; +use warnings; +use utf8; +binmode(STDOUT, ":encoding(UTF-8)"); + +my $per_file = 0; +my @args; +for (@ARGV) { $_ eq "--files" ? ($per_file = 1) : push @args, $_ } +my $root = "../po4a/po"; +unless (-d $root) { die "po-stats: no catalogues at $root\n" } + +my @langs = @args ? @args : map { s{.*/}{}r } grep { -d } glob("$root/*"); +@langs = sort @langs; + +printf "%-8s %8s %8s %8s %8s %s\n", + "lang", "total", "done", "fuzzy", "empty", "translated"; +printf "%s\n", "-" x 62; + +my %tot; +for my $lang (@langs) { + my (%n, %byfile); + for my $f (sort glob("$root/$lang/*.po")) { + my $c = count($f); + $n{$_} += $c->{$_} for qw(total done fuzzy empty); + $byfile{$f} = $c; + } + next unless $n{total}; + printf "%-8s %8d %8d %8d %8d %5.1f%%\n", + $lang, $n{total}, $n{done}, $n{fuzzy}, $n{empty}, + 100 * $n{done} / $n{total}; + $tot{$_} += $n{$_} for qw(total done fuzzy empty); + next unless $per_file; + for my $f (sort { $byfile{$a}{done} <=> $byfile{$b}{done} } keys %byfile) { + my $c = $byfile{$f}; + next unless $c->{total}; + printf " %-44s %5.1f%% %d fuzzy\n", + ($f =~ m{([^/]+)$})[0], 100 * $c->{done} / $c->{total}, $c->{fuzzy}; + } +} +printf "%s\n", "-" x 62; +printf "%-8s %8d %8d %8d %8d %5.1f%%\n", + "all", $tot{total}, $tot{done}, $tot{fuzzy}, $tot{empty}, + $tot{total} ? 100 * $tot{done} / $tot{total} : 0 + if $tot{total}; + +sub count { + my $file = shift; + open my $fh, "<:encoding(UTF-8)", $file or return { total => 0 }; + my (%c, @id, @str, $mode, $fuzzy); + my $flush = sub { + return unless $mode; + my $id = join "", @id; + my $str = join "", @str; + if ($id ne "") { # not the catalogue's own header + $c{total}++; + if ($str eq "") { $c{empty}++ } + elsif ($fuzzy) { $c{fuzzy}++ } + else { $c{done}++ } + } + @id = (); @str = (); $mode = ""; $fuzzy = 0; + }; + while (my $l = <$fh>) { + chomp $l; + if ($l =~ /^#,.*\bfuzzy\b/) { $fuzzy = 1 } + elsif ($l =~ /^#/) { } + elsif ($l =~ /^msgid\s+"(.*)"$/) { @id = ($1); @str = (); $mode = "id" } + elsif ($l =~ /^msgstr\s+"(.*)"$/) { @str = ($1); $mode = "str" } + elsif ($l =~ /^"(.*)"$/ && $mode) { $mode eq "id" ? push @id, $1 : push @str, $1 } + elsif ($l =~ /^\s*$/) { $flush->() } + } + $flush->(); + close $fh; + $c{$_} //= 0 for qw(total done fuzzy empty); + return \%c; +} |
