Index: /applications/editors/josm/plugins/photoadjust/README
===================================================================
--- /applications/editors/josm/plugins/photoadjust/README	(revision 30179)
+++ /applications/editors/josm/plugins/photoadjust/README	(revision 30180)
@@ -11,4 +11,7 @@
 to place photos that don't have GPS coordinates associated with them
 on the map, thus to geotag them.
+
+
+See i18n/README for plugin translation.
 
 
@@ -45,2 +48,10 @@
                licence applicable to JOSM (GPL v2 or any later version),
         see https://help.launchpad.net/TermsofUse#Translations_copyright
+  i18n:
+    i18nlib.pm:
+      extract of
+        http://svn.openstreetmap.org/applications/editors/josm/i18n/i18n.pl
+      License: nothing specified, assuming JOSM license: GPL v2 or later
+    other files:
+      self written code
+      License: CC0
Index: /applications/editors/josm/plugins/photoadjust/i18n/README
===================================================================
--- /applications/editors/josm/plugins/photoadjust/i18n/README	(revision 30180)
+++ /applications/editors/josm/plugins/photoadjust/i18n/README	(revision 30180)
@@ -0,0 +1,51 @@
+Plugin Translations
+===================
+
+Run from plugin main directory:
+ant pot
+ant poimport
+ant pomerge
+ant lang
+
+Detailed Version
+----------------
+* To kick off the translation of the plugin it is SVN committed.
+  After a day the translatable strings are visible at Launchpad
+  (https://translations.launchpad.net/josm/trunk/+pots/josm).
+* After the Java code or the plugin description in build.xml was
+  changed, you need to run "ant pot".  That creates/updates the
+  template file po/plugin.pot.
+* Download the latest translations from Launchpad and copy them into
+  the directory po with "ant poimport".  This uses the version that is
+  updated once a day.  For a more recent version you need to request a
+  download from
+  https://translations.launchpad.net/josm/trunk/+pots/josm/+export.
+  Then run "ant -Dpoimport.tarball=URL poimport", replace URL with the
+  translation download URL.
+* Remove all untranslated strings and other translations with
+  "ant pomerge".
+* Create the language files in the data directory with "ant lang".
+* SVN commit plugin changes, SVN update plugin directory, run
+  "ant dist" to create a new plugin release, SVN commit new plugin
+  release (../../dist/plugin.jar).  "ant dist" will add the
+  translations of the plugin description to the manifest.
+
+Additions to plugin build.xml:
+    <!-- ** internationalization ** -->
+    <import file="i18n/build-i18n.xml"/>
+    <target name="additional-manifest">
+        <antcall target="mftrans"/>
+    </target>
+
+Global Run
+----------
+From the global i18n directory the steps are:
+./launchpad bzronly
+ant -Dplugin=plugin singleplugintrans
+
+* The command "launchpad bzronly" exports the latest revision of the
+  Launchpas translations.
+* "ant singleplugintrans" generates the language files in the plugin
+  data directory.  Then it deletes to PO files.
+* It is not possible to add the translations of the plugin description
+  to the manifest.
Index: /applications/editors/josm/plugins/photoadjust/i18n/build-i18n.xml
===================================================================
--- /applications/editors/josm/plugins/photoadjust/i18n/build-i18n.xml	(revision 30179)
+++ /applications/editors/josm/plugins/photoadjust/i18n/build-i18n.xml	(revision 30180)
@@ -7,4 +7,5 @@
     <property name="gettexttasks.jar" value="../../i18n/lib/gettext-ant-tasks-0.9.7.jar"/>
     <property name="plugin.po.dir" location="po"/>
+    <property name="poimport.tarball" value="latest"/>
     <property name="plugin.manifest" location="MANIFEST"/>
 
@@ -33,9 +34,10 @@
         </exec>
     </target>
-    <target name="poimport" description="Import the PO files from the tarball launchpad-export.tar.gz exported from Launchpad.">
+    <target name="poimport" description="Import the PO files from Launchpad tarball.">
         <exec executable="perl">
             <arg value="i18n/poimport.pl"/>
             <arg value="--podir"/>
             <arg value="${plugin.po.dir}"/>
+            <arg value="${poimport.tarball}"/>
         </exec>
     </target>
@@ -45,5 +47,6 @@
         </exec>
     </target>
-    <target name="mftrans" description="Add translations of plugin description to manifest.">
+
+    <target name="mftrans" description="Add translations of plugin description to manifest.  Not to be called directly.">
         <echo message="Adding translations to ${plugin.manifest} ..."/>
         <exec executable="perl">
Index: /applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm
===================================================================
--- /applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm	(revision 30180)
+++ /applications/editors/josm/plugins/photoadjust/i18n/i18nlib.pm	(revision 30180)
@@ -0,0 +1,184 @@
+### i18nlib.pm - Perl library based on i18n/i18n.pl.
+
+use utf8;
+binmode STDERR, ":encoding(utf8)";
+use Term::ReadKey;
+use Encode;
+
+my $waswarn = 0;
+my $maxcount = 0;
+
+sub loadfiles($@)
+{
+  my $desc;
+  my $all;
+  my ($lang,@files) = @_;
+  foreach my $file (@files)
+  {
+    die "Could not open file $file." if(!open FILE,"<:utf8",$file);
+    my $linenum = 0;
+
+    my $cnt = -1; # don't count translators info
+    if($file =~ /\/(.._..(@.+)?)\.po$/ || $file =~ /\/(...?(@.+)?)\.po$/)
+    {
+      my $l = $1;
+      ++$lang->{$l};
+      my %postate = (last => "", type => "");
+      my $linenum = 0;
+      print "Reading file $file\n";
+      while(<FILE>)
+      {
+        ++$linenum;
+        my $fn = "$file:$linenum";
+        chomp;
+        if($_ =~ /^#/ || !$_)
+        {
+          checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, 1);
+          $postate{fuzzy} = 1 if ($_ =~ /fuzzy/);
+        }
+        elsif($_ =~ /^"(.*)"$/) {$postate{last} .= $1;}
+        elsif($_ =~ /^(msg.+) "(.*)"$/)
+        {
+          my ($n, $d) = ($1, $2);
+          ++$cnt if $n eq "msgid";
+          my $new = !${postate}{fuzzy} && (($n eq "msgid" && $postate{type} ne "msgctxt") || ($n eq "msgctxt"));
+          checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, $new);
+          $postate{last} = $d;
+          $postate{type} = $n;
+          $postate{src} = $fn if $new;
+        }
+        else
+        {
+          die "Strange line $linenum in $file: $_.";
+        }
+      }
+      checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, 1);
+    }
+    else
+    {
+      die "File format not supported for file $file.";
+    }
+    $maxcount = $cnt if $cnt > $maxcount;
+    close(FILE);
+  }
+  return %all;
+}
+
+my $alwayspo = 0;
+my $alwaysup = 0;
+my $noask = 0;
+my $conflicts;
+sub copystring($$$$$$$)
+{
+  my ($data, $en, $l, $str, $txt, $context, $ispo) = @_;
+
+  $en = "___${context}___$en" if $context;
+
+  if(exists($data->{$en}{$l}) && $data->{$en}{$l} ne $str)
+  {
+    return if !$str;
+    if($l =~ /^_/)
+    {
+      $data->{$en}{$l} .= ";$str" if !($data->{$en}{$l} =~ /$str/);
+    }
+    elsif(!$data->{$en}{$l})
+    {
+      $data->{$en}{$l} = $str;
+    }
+    else
+    {
+
+      my $f = $data->{$en}{_file} || "";
+      $f = ($f ? "$f;".$data->{$en}{"_src.$l"} : $data->{$en}{"_src.$l"}) if $data->{$en}{"_src.$l"};
+      my $isotherpo = ($f =~ /\.po\:/);
+      my $pomode = ($ispo && !$isotherpo) || (!$ispo && $isotherpo);
+
+      my $mis = "String mismatch for '$en' **$str** ($txt) != **$data->{$en}{$l}** ($f)\n";
+      my $replace = 0;
+
+      if(($conflicts{$l}{$str} || "") eq $data->{$en}{$l}) {}
+      elsif($pomode && $alwaysup) { $replace=$isotherpo; }
+      elsif($pomode && $alwayspo) { $replace=$ispo; }
+      elsif($noask) { print $mis; ++$waswarn; }
+      else
+      {
+        ReadMode 4; # Turn off controls keys
+        my $arg = "(l)eft, (r)ight";
+        $arg .= ", (p)o, (u)pstream[ts/mat], all p(o), all up(s)tream" if $pomode;
+        $arg .= ", e(x)it: ";
+        print "$mis$arg";
+        while((my $c = getc()))
+        {
+          if($c eq "l") { $replace=1; }
+          elsif($c eq "r") {}
+          elsif($c eq "p" && $pomode) { $replace=$ispo; }
+          elsif($c eq "u" && $pomode) { $replace=$isotherpo; }
+          elsif($c eq "o" && $pomode) { $alwayspo = 1; $replace=$ispo; }
+          elsif($c eq "s" && $pomode) { $alwaysup = 1; $replace=$isotherpo; }
+          elsif($c eq "x") { $noask = 1; ++$waswarn; }
+          else { print "\n$arg"; next; }
+          last;
+        }
+        print("\n");
+        ReadMode 0; # Turn on controls keys
+      }
+      if(!$noask)
+      {
+        if($replace)
+        {
+          $data->{$en}{$l} = $str;
+          $conflicts{$l}{$data->{$en}{$l}} = $str;
+        }
+        else
+        {
+          $conflicts{$l}{$str} = $data->{$en}{$l};
+        }
+      }
+    }
+  }
+  else
+  {
+    $data->{$en}{$l} = $str;
+  }
+}
+
+sub checkpo($$$$$$)
+{
+  my ($postate, $data, $l, $txt, $keys, $new) = @_;
+
+  if($postate->{type} eq "msgid") {$postate->{msgid} = $postate->{last};}
+  elsif($postate->{type} eq "msgid_plural") {$postate->{msgid_1} = $postate->{last};}
+  elsif($postate->{type} =~ /^msgstr(\[0\])?$/) {$postate->{msgstr} = $postate->{last};}
+  elsif($postate->{type} =~ /^msgstr\[(.+)\]$/) {$postate->{"msgstr_$1"} = $postate->{last};}
+  elsif($postate->{type} eq "msgctxt") {$postate->{context} = $postate->{last};}
+  elsif($postate->{type}) { die "Strange type $postate->{type} found\n" }
+
+  if($new)
+  {
+    if((!$postate->{fuzzy}) && $postate->{msgstr} && $postate->{msgid})
+    {
+      copystring($data, $postate->{msgid}, $l, $postate->{msgstr},$txt,$postate->{context}, 1);
+      for($i = 1; exists($postate->{"msgstr_$i"}); ++$i)
+      { copystring($data, $postate->{msgid}, "$l.$i", $postate->{"msgstr_$i"},$txt,$postate->{context}, 1); }
+      if($postate->{msgid_1})
+      { copystring($data, $postate->{msgid}, "en.1", $postate->{msgid_1},$txt,$postate->{context}, 1); }
+      copystring($data, $postate->{msgid}, "_src.$l", $postate->{src},$txt,$postate->{context}, 1);
+    }
+    elsif($postate->{msgstr} && !$postate->{msgid})
+    {
+      my %k = ($postate->{msgstr} =~ /(.+?): +(.+?)\\n/g);
+      # take the first one!
+      for $a (sort keys %k)
+      {
+        $keys->{$l}{$a} = $k{$a} if !$keys->{$l}{$a};
+      }
+    }
+    foreach my $k (keys %{$postate})
+    {
+      delete $postate->{$k};
+    }
+    $postate->{type} = $postate->{last} = "";
+  }
+}
+
+1;
Index: /applications/editors/josm/plugins/photoadjust/i18n/mftrans.pl
===================================================================
--- /applications/editors/josm/plugins/photoadjust/i18n/mftrans.pl	(revision 30179)
+++ /applications/editors/josm/plugins/photoadjust/i18n/mftrans.pl	(revision 30180)
@@ -47,193 +47,14 @@
 #####################################################################
 
-### This file is based on i18n/i18n.pl.  The functions loadfiles(),
-### copystring(), checkpo() and variables used by those functions are
-### a one-to-one copy.
-
+use strict;
 use utf8;
-#use encoding "utf8";
-binmode STDERR, ":encoding(utf8)";
-use Term::ReadKey;
 use Encode;
 use Getopt::Long;
 use Pod::Usage;
-
-my $waswarn = 0;
-my $maxcount = 0;
+use File::Basename;
+push(@INC, dirname($0));
+require i18nlib;
 
 main();
-
-sub loadfiles($@)
-{
-  my $desc;
-  my $all;
-  my ($lang,@files) = @_;
-  foreach my $file (@files)
-  {
-    die "Could not open file $file." if(!open FILE,"<:utf8",$file);
-    my $linenum = 0;
-
-    my $cnt = -1; # don't count translators info
-    if($file =~ /\/(.._..(@.+)?)\.po$/ || $file =~ /\/(...?(@.+)?)\.po$/)
-    {
-      my $l = $1;
-      ++$lang->{$l};
-      my %postate = (last => "", type => "");
-      my $linenum = 0;
-      print "Reading file $file\n";
-      while(<FILE>)
-      {
-        ++$linenum;
-        my $fn = "$file:$linenum";
-        chomp;
-        if($_ =~ /^#/ || !$_)
-        {
-          checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, 1);
-          $postate{fuzzy} = 1 if ($_ =~ /fuzzy/);
-        }
-        elsif($_ =~ /^"(.*)"$/) {$postate{last} .= $1;}
-        elsif($_ =~ /^(msg.+) "(.*)"$/)
-        {
-          my ($n, $d) = ($1, $2);
-          ++$cnt if $n eq "msgid";
-          my $new = !${postate}{fuzzy} && (($n eq "msgid" && $postate{type} ne "msgctxt") || ($n eq "msgctxt"));
-          checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, $new);
-          $postate{last} = $d;
-          $postate{type} = $n;
-          $postate{src} = $fn if $new;
-        }
-        else
-        {
-          die "Strange line $linenum in $file: $_.";
-        }
-      }
-      checkpo(\%postate, \%all, $l, "line $linenum in $file", $keys, 1);
-    }
-    else
-    {
-      die "File format not supported for file $file.";
-    }
-    $maxcount = $cnt if $cnt > $maxcount;
-    close(FILE);
-  }
-  return %all;
-}
-
-my $alwayspo = 0;
-my $alwaysup = 0;
-my $noask = 0;
-my $conflicts;
-sub copystring($$$$$$$)
-{
-  my ($data, $en, $l, $str, $txt, $context, $ispo) = @_;
-
-  $en = "___${context}___$en" if $context;
-
-  if(exists($data->{$en}{$l}) && $data->{$en}{$l} ne $str)
-  {
-    return if !$str;
-    if($l =~ /^_/)
-    {
-      $data->{$en}{$l} .= ";$str" if !($data->{$en}{$l} =~ /$str/);
-    }
-    elsif(!$data->{$en}{$l})
-    {
-      $data->{$en}{$l} = $str;
-    }
-    else
-    {
-
-      my $f = $data->{$en}{_file} || "";
-      $f = ($f ? "$f;".$data->{$en}{"_src.$l"} : $data->{$en}{"_src.$l"}) if $data->{$en}{"_src.$l"};
-      my $isotherpo = ($f =~ /\.po\:/);
-      my $pomode = ($ispo && !$isotherpo) || (!$ispo && $isotherpo);
-
-      my $mis = "String mismatch for '$en' **$str** ($txt) != **$data->{$en}{$l}** ($f)\n";
-      my $replace = 0;
-
-      if(($conflicts{$l}{$str} || "") eq $data->{$en}{$l}) {}
-      elsif($pomode && $alwaysup) { $replace=$isotherpo; }
-      elsif($pomode && $alwayspo) { $replace=$ispo; }
-      elsif($noask) { print $mis; ++$waswarn; }
-      else
-      {
-        ReadMode 4; # Turn off controls keys
-        my $arg = "(l)eft, (r)ight";
-        $arg .= ", (p)o, (u)pstream[ts/mat], all p(o), all up(s)tream" if $pomode;
-        $arg .= ", e(x)it: ";
-        print "$mis$arg";
-        while((my $c = getc()))
-        {
-          if($c eq "l") { $replace=1; }
-          elsif($c eq "r") {}
-          elsif($c eq "p" && $pomode) { $replace=$ispo; }
-          elsif($c eq "u" && $pomode) { $replace=$isotherpo; }
-          elsif($c eq "o" && $pomode) { $alwayspo = 1; $replace=$ispo; }
-          elsif($c eq "s" && $pomode) { $alwaysup = 1; $replace=$isotherpo; }
-          elsif($c eq "x") { $noask = 1; ++$waswarn; }
-          else { print "\n$arg"; next; }
-          last;
-        }
-        print("\n");
-        ReadMode 0; # Turn on controls keys
-      }
-      if(!$noask)
-      {
-        if($replace)
-        {
-          $data->{$en}{$l} = $str;
-          $conflicts{$l}{$data->{$en}{$l}} = $str;
-        }
-        else
-        {
-          $conflicts{$l}{$str} = $data->{$en}{$l};
-        }
-      }
-    }
-  }
-  else
-  {
-    $data->{$en}{$l} = $str;
-  }
-}
-
-sub checkpo($$$$$$)
-{
-  my ($postate, $data, $l, $txt, $keys, $new) = @_;
-
-  if($postate->{type} eq "msgid") {$postate->{msgid} = $postate->{last};}
-  elsif($postate->{type} eq "msgid_plural") {$postate->{msgid_1} = $postate->{last};}
-  elsif($postate->{type} =~ /^msgstr(\[0\])?$/) {$postate->{msgstr} = $postate->{last};}
-  elsif($postate->{type} =~ /^msgstr\[(.+)\]$/) {$postate->{"msgstr_$1"} = $postate->{last};}
-  elsif($postate->{type} eq "msgctxt") {$postate->{context} = $postate->{last};}
-  elsif($postate->{type}) { die "Strange type $postate->{type} found\n" }
-
-  if($new)
-  {
-    if((!$postate->{fuzzy}) && $postate->{msgstr} && $postate->{msgid})
-    {
-      copystring($data, $postate->{msgid}, $l, $postate->{msgstr},$txt,$postate->{context}, 1);
-      for($i = 1; exists($postate->{"msgstr_$i"}); ++$i)
-      { copystring($data, $postate->{msgid}, "$l.$i", $postate->{"msgstr_$i"},$txt,$postate->{context}, 1); }
-      if($postate->{msgid_1})
-      { copystring($data, $postate->{msgid}, "en.1", $postate->{msgid_1},$txt,$postate->{context}, 1); }
-      copystring($data, $postate->{msgid}, "_src.$l", $postate->{src},$txt,$postate->{context}, 1);
-    }
-    elsif($postate->{msgstr} && !$postate->{msgid})
-    {
-      my %k = ($postate->{msgstr} =~ /(.+?): +(.+?)\\n/g);
-      # take the first one!
-      for $a (sort keys %k)
-      {
-        $keys->{$l}{$a} = $k{$a} if !$keys->{$l}{$a};
-      }
-    }
-    foreach my $k (keys %{$postate})
-    {
-      delete $postate->{$k};
-    }
-    $postate->{type} = $postate->{last} = "";
-  }
-}
 
 ### Add translations of plugin description to manifest.  We write an
@@ -296,4 +117,5 @@
     }
   }
+  exit if ($#po < 0);
   my %data = loadfiles(\%lang,@po);
   my $descs = $data{$description};
