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
206 layouts.project_name.h1: true
207 layouts.project_name.title: true
208 site.index.license.license_url: true
209 site.index.license.project_url: true