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);
 
 143     while (my ($key, $blacklisted) = each %bw_list)
 
 145         # FIXME: Does syck actually support true/false booleans in yaml?
 
 146         delete $keys{$key} if $blacklisted eq 'true'
 
 154     my ($hash, @path) = @_;
 
 157     while (my ($k, $v) = each %$hash)
 
 159         if (ref $v eq 'HASH')
 
 161              push @ret => iterate($v, @path, $k);
 
 165             push @ret => join(".",@path, $k), $v;
 
 175     $name =~ s[\..*?$][];
 
 183     Pod::Usage::pod2usage(
 
 184         -verbose => $arg{ verbose },
 
 185         -exitval => $arg{ exitval } || 0,
 
 192   # Default/Per language blacklist/whitelist for the
 
 193   # --untranslated-values switch. "true" as a value indicates that the
 
 194   # key is to be blacklisted, and "false" that it's to be
 
 195   # whitelisted. "false" is only required to whitelist a key
 
 196   # blacklisted by default on a per-language basis.
 
 200     layouts.intro_3_bytemark: true
 
 201     layouts.intro_3_ucl: true
 
 202     layouts.project_name.h1: true
 
 203     layouts.project_name.title: true
 
 204     site.index.license.project_url: true
 
 206     activerecord.attributes.message.sender: true
 
 207     activerecord.attributes.trace.name: true
 
 208     activerecord.models.changeset: true
 
 209     activerecord.models.relation: true
 
 210     browse.changeset.changeset: true
 
 211     browse.changeset.changesetxml: true
 
 212     browse.changeset.osmchangexml: true
 
 213     browse.changeset.title: true
 
 214     browse.common_details.version: true
 
 215     browse.containing_relation.relation: true
 
 216     browse.relation.relation: true
 
 217     browse.relation.relation_title: true
 
 218     browse.start_rjs.details: true
 
 219     browse.start_rjs.object_list.details: true
 
 220     browse.tag_details.tags: true
 
 221     changeset.changesets.id: true
 
 222     export.start.export_button: true
 
 223     export.start.format: true
 
 224     export.start.output: true
 
 225     export.start.zoom: true
 
 226     export.start_rjs.export: true
 
 229     layouts.shop_url: true
 
 230     notifier.gpx_notification.failure.import_failures_url: true
 
 231     notifier.signup_confirm_plain.wiki_signup_url: true
 
 232     site.edit.anon_edits: true
 
 233     site.edit.anon_edits_link: true
 
 234     site.index.license.license_name: true
 
 235     site.index.permalink: true
 
 236     site.search.submit_text: true
 
 237     trace.edit.tags: true
 
 239     trace.trace_form.tags: true
 
 240     trace.trace_optionals.tags: true
 
 241     trace.view.tags: true
 
 242     user.account.public editing.enabled link: true