4 use YAML::Syck qw(Load LoadFile);
 
  11 locale-diff - Compare two YAML files and print how their datastructures differ
 
  15     # --keys is the default
 
  17     diff --keys en.yml is.yml
 
  19     # --untranslated-values compares prints keys whose values don't differ
 
  20     diff --untranslated-values-all en.yml is.yml
 
  22     # --untranslated-values-all compares prints keys whose values
 
  23     # don't differ. Ignoring the blacklist which prunes things
 
  24     # unlikley to be translated
 
  25     diff --untranslated-values-all en.yml is.yml
 
  29 This utility prints the differences between two YAML files using
 
  30 L<Test::Differences>. The purpose of it is to diff the files is
 
  31 F<config/locales> to find out what keys need to be added to the
 
  32 translated files when F<en.yml> changes.
 
  40 Print this help message.
 
  44 Show the hash keys that differ between the two files, useful merging
 
  45 new entries from F<en.yml> to a local file.
 
  47 =item --untranslated-values
 
  49 Show keys whose values are either exactly the same between the two
 
  50 files, or don't exist in the target file (the latter file
 
  51 specified). The values are pruned according to global and language
 
  52 specific blacklists found in the C<__DATA__> section of this script.
 
  54 This helps to find untranslated values.
 
  56 =item --untranslated-values-all
 
  58 Like C<--untranslated-values> but ignores blacklists.
 
  64 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@f-prot.com>
 
  68 # Get the command-line options
 
  69 Getopt::Long::Parser->new(
 
  70     config => [ qw< bundling no_ignore_case no_require_order pass_through > ],
 
  72     'h|help' => \my $help,
 
  74     'untranslated-values' => \my $untranslated_values,
 
  75     'untranslated-values-all' => \my $untranslated_values_all,
 
  78 # --keys is the default
 
  79 $keys = 1 if not $untranslated_values_all and not $untranslated_values;
 
  84 # If we're not given two .yml files
 
  85 help() if @ARGV != 2 or (!-f $ARGV[0] or !-f $ARGV[1]);
 
  87 my ($from, $to) = @ARGV;
 
  89 my $from_data = LoadFile($from);
 
  90 my $to_data   = LoadFile($to);
 
  92 my $from_parsed = { iterate($from_data->{basename($from)}) };
 
  93 my $to_parsed = { iterate($to_data->{basename($to)}) };
 
  95 # Since this used to be the default, support that...
 
  98     print_key_differences();
 
 100 elsif ($untranslated_values or $untranslated_values_all)
 
 102     my @untranslated = untranslated_keys($from_parsed, $to_parsed);
 
 104     # Prune according to blacklist
 
 105     if ($untranslated_values) {
 
 106         @untranslated = prune_untranslated_with_blacklist(basename($to), @untranslated);
 
 109     print $_, "\n" for @untranslated;
 
 114 sub print_key_differences
 
 116     # Hack around Test::Differences wanting a Test::* module loaded
 
 118     sub Test::ok { print shift }
 
 121     eq_or_diff([ sort keys %$from_parsed ], [ sort keys %$to_parsed ]);
 
 124 sub untranslated_keys
 
 126     my ($from_parsed, $to_parsed) = @_;
 
 127     sort grep { not exists $to_parsed->{$_} or $from_parsed->{$_} eq $to_parsed->{$_} } keys %$from_parsed;
 
 130 sub prune_untranslated_with_blacklist
 
 132     my ($language, @keys) = @_;
 
 136     my $end_yaml = Load(join '', <DATA>);
 
 137     my $untranslated_values = $end_yaml->{untranslated_values};
 
 138     my $default = $untranslated_values->{default};
 
 139     my $this_language = $untranslated_values->{$language} || {};
 
 141     my %bw_list = (%$default, %$this_language);
 
 144     use Data::Dump 'dump';
 
 145     say STDERR dump \%bw_list;
 
 147     while (my ($key, $blacklisted) = each %bw_list)
 
 149         # FIXME: Does syck actually support true/false booleans in yaml?
 
 150         delete $keys{$key} if $blacklisted eq 'true'
 
 158     my ($hash, @path) = @_;
 
 161     while (my ($k, $v) = each %$hash)
 
 163         if (ref $v eq 'HASH')
 
 165              push @ret => iterate($v, @path, $k);
 
 169             push @ret => join(".",@path, $k), $v;
 
 179     $name =~ s[\..*?$][];
 
 187     Pod::Usage::pod2usage(
 
 188         -verbose => $arg{ verbose },
 
 189         -exitval => $arg{ exitval } || 0,
 
 196   # Default/Per language blacklist/whitelist for the
 
 197   # --untranslated-values switch. "true" as a value indicates that the
 
 198   # key is to be blacklisted, and "false" that it's to be
 
 199   # whitelisted. "false" is only required to whitelist a key
 
 200   # blacklisted by default on a per-language basis.
 
 204     layouts.intro_3_bytemark: true
 
 205     layouts.intro_3_ucl: true