Index: applications/editors/josm/plugins/photoadjust/i18n/README
===================================================================
--- applications/editors/josm/plugins/photoadjust/i18n/README	(revision 31959)
+++ applications/editors/josm/plugins/photoadjust/i18n/README	(revision 31960)
@@ -50,2 +50,13 @@
 * It is not possible to add the translations of the plugin description
   to the manifest.
+
+See Language String Changes
+---------------------------
+To see what language strings changed in data/*.lang run this:
+svn diff --diff-cmd i18n/diff_lang.pl --force data
+
+To see just removed or modified strings:
+svn diff --diff-cmd i18n/diff_lang.pl --force data | grep ^- | grep -v '^--- data/'
+
+To display changes of a single file with tkdiff:
+svn diff --diff-cmd i18n/diff_lang.pl --extensions --tkdiff --force data/<lang>.lang
Index: applications/editors/josm/plugins/photoadjust/i18n/diff_lang.pl
===================================================================
--- applications/editors/josm/plugins/photoadjust/i18n/diff_lang.pl	(revision 31960)
+++ applications/editors/josm/plugins/photoadjust/i18n/diff_lang.pl	(revision 31960)
@@ -0,0 +1,75 @@
+#! /usr/bin/perl -w
+###
+### diff_lang.pl - Show differences of a JOSM language file.
+###
+### Syntax examples:
+###   diff_lang.pl -u -L "data/en.lang (revision 12345)"
+###	-L "data/en.lang (working copy)"
+###	.svn/pristine/42/423b7dfb6a014d6c0d3ec3ce96a10e2df665266a.svn-base
+###	data/en.lang
+###   diff_lang.pl --tkdiff -L "data/en.lang (revision 12345)"
+###	-L "data/en.lang (working copy)"
+###	.svn/pristine/42/423b7dfb6a014d6c0d3ec3ce96a10e2df665266a.svn-base
+###	data/en.lang
+
+use strict;
+use utf8;
+use File::Basename;
+use File::Temp qw/ tempfile /;
+push(@INC, dirname($0));
+require i18nlib;
+
+my @diffArgs;
+my @files;
+my $tkdiff = 0;
+#print "Arguments: ", join(" ", @ARGV), "\n";
+for (my $idx = 0; $idx <= $#ARGV; $idx++) {
+  my $arg = $ARGV[$idx];
+  if ($arg eq "-u") {
+    push(@diffArgs, $arg);
+  }
+  elsif ($arg eq "-L") {
+    push(@diffArgs, $arg, $ARGV[++$idx]);
+  }
+  elsif ($arg eq "--tkdiff") {
+    $tkdiff = 1;
+  }
+  elsif ($arg =~ m/^-/) {
+    #die "Unknown option '$arg'.\n";
+    ### Assume that diff knows this option and that it has no argument.
+    push(@diffArgs, $arg);
+  }
+  else {
+    push(@files, $arg);
+  }
+  #print "$idx: $ARGV[$idx]\n";
+}
+
+if ($#files != 1) {
+  print "Files:\n", join("\n", @files), "\n";
+  die sprintf("Expected two file arguments, got %d arguments.\n", $#files + 1);
+}
+
+my $separator = "\n\n";
+my @strings = loadLangFile($files[0]);
+my ($fh1, $tmpfile1) = tempfile();
+#binmode($fh1, ":utf8");
+print $fh1 join($separator, @strings), "\n";
+close($fh1);
+@strings = loadLangFile($files[1]);
+my ($fh2, $tmpfile2) = tempfile();
+#binmode($fh2, ":utf8");
+print $fh2 join($separator, @strings), "\n";
+close($fh2);
+
+push(@diffArgs, $tmpfile1, $tmpfile2);
+my @diffCmd;
+if ($tkdiff) {
+  push(@diffCmd, "tkdiff");
+}
+else {
+  push(@diffCmd, "diff");
+}
+push(@diffCmd, @diffArgs);
+#print "Command: ", join(" ", @diffCmd), "\n";
+system(@diffCmd);
Index: applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm
===================================================================
--- applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm	(revision 31959)
+++ applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm	(revision 31960)
@@ -182,3 +182,43 @@
 }
 
+### Load a JOSM language file.  The format is two byte string length, then the
+### string.  Length 0x0000 means the string was not in the PO file, i.e. there
+### is no translation (there are no empty strings).  Length 0xfffe (65534)
+### means the string is the same as the original string.  Length 0xffff ends
+### the string list.
+###
+### Args:
+###     filename (str): Path to language file.
+###
+### Returns:
+###     array: List of decoded strings.
+sub loadLangFile {
+  my ($filename) = @_;
+  my @strings;
+  open(my $langFd, $filename) or die "Cannot open file $filename: $!";
+  binmode($langFd);
+  my $buffer;
+  my $length;
+  while (1) {
+    read($langFd, $buffer, 2);
+    $length = unpack("n", $buffer);
+    die "Unable to read string length" unless ($buffer);
+    if ($length == 0) {
+      push(@strings, "");
+    }
+    elsif ($length == 0xfffe) {
+      push(@strings, "(see original string)");
+    }
+    elsif ($length == 0xffff) {
+      last;
+    }
+    else {
+      read($langFd, $buffer, $length);
+      push(@strings, $buffer);
+    }
+  }
+  close($langFd);
+  return @strings;
+}
+
 1;
Index: applications/editors/josm/plugins/photoadjust/i18n/read_lang.pl
===================================================================
--- applications/editors/josm/plugins/photoadjust/i18n/read_lang.pl	(revision 31960)
+++ applications/editors/josm/plugins/photoadjust/i18n/read_lang.pl	(revision 31960)
@@ -0,0 +1,103 @@
+#! /usr/bin/perl -w
+
+#####################################################################
+### http://www.perl.com/doc/manual/html/utils/pod2man.html
+### http://search.cpan.org/dist/perl/pod/perlpod.pod
+
+=head1 NAME
+
+read_lang.pl - Read a binary JOSM language file.
+
+=head1 SYNOPSIS
+
+B<read_lang.pl> [B<--help>] [B<--man>] [B<--output> I<outfile>] I<lang.lang>
+
+=head1 DESCRIPTION
+
+Read a binary JOSM language file and print the strings.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Prints a brief help message and exits.
+
+=item B<--man>
+
+Prints the manual page and exits.
+
+=item B<--output>, B<-o>
+
+Write the strings into the specified file.  Default is to print the string to
+standard output.
+
+=item B<--statistics>, B<-s>
+
+Print statistics about the language file instead of the strings.
+
+=back
+
+=cut
+#####################################################################
+
+use strict;
+use File::Basename;
+use Getopt::Long;
+use Pod::Usage;
+push(@INC, dirname($0));
+require i18nlib;
+
+my $showhelp = 0;               ### Show help screen.
+my $showman = 0;                ### Show manual page of this script.
+my $outfile;			### Name of output file.
+my $langfile;			### Name of language file.
+my $statistics = 0;		### Print statistics.
+my $separator = "\n\n";		### String separator.
+
+GetOptions('help|?|h'   => \$showhelp,
+           'man'        => \$showman,
+           'output|o=s' => \$outfile,
+           'statistics|s' => \$statistics,
+          ) or pod2usage(2);
+
+pod2usage(1) if $showhelp;
+pod2usage(-exitstatus => 0, -verbose => 2) if $showman;
+
+### Check for arguments.  The only supported argument is the language file.
+if ($#ARGV == 0) {
+  $langfile = $ARGV[0];
+}
+elsif ($#ARGV > 0) {
+  die "This script accepts only one argument.\n";
+}
+
+die "Please specify a language file.\n" unless ($langfile);
+
+my @strings = loadLangFile($langfile);
+if ($statistics) {
+  my $empty = 0;
+  my $sametrans = 0;
+  foreach my $string (@strings) {
+    if ($string eq "") {
+      $empty++;
+    }
+    elsif ($string eq "(see original string)") {
+      $sametrans++;
+    }
+  }
+  printf("Total strings: %d\n", $#strings + 1);
+  print "Strings without translation: $empty\n";
+  print "Strings with equal translation: $sametrans\n";
+}
+else {
+  if ($outfile) {
+    open(my $outFd, ">", $outfile) or die "Cannot open output file $outfile: $!";
+    print $outFd join($separator, @strings), "\n";
+    close($outFd);
+  }
+  else {
+    print join($separator, @strings), "\n";
+  }
+}
