{"thread":{"id":"43967","subject":"[PATCH v2 00/11] Mark strings in perl script for translation","startedAt":"2016-08-31T12:32:48Z","lastAt":"2016-10-03T13:22:01Z","messageCount":45,"participants":["Vasco Almeida","Junio C Hamano","Duy Nguyen","Jakub Narębski"],"isPatch":true,"patchVersion":2,"patchTotal":11},"messages":[{"id":"300676","messageId":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":null,"subject":"[PATCH v2 00/11] Mark strings in perl script for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:19Z","receivedAt":"2016-08-31T12:32:48Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark messages in some perl scripts for translation.\n\nSince v1, adds brackets so parameter grouping of sprintf parameters is easier\nto see.\n\nInterdiff included below.\n\nVasco Almeida (11):\n  i18n: add--interactive: mark strings for translation\n  i18n: add--interactive: mark simple here documents for translation\n  i18n: add--interactive: mark strings with interpolation for\n    translation\n  i18n: add--interactive: mark plural strings\n  i18n: add--interactive: mark message for translation\n  i18n: add--interactive: i18n of help_patch_cmd\n  i18n: add--interactive: mark edit_hunk_manually message for\n    translation\n  i18n: send-email: mark strings for translation\n  i18n: send-email: mark warnings and errors for translation\n  i18n: send-email: mark string with interpolation for translation\n  i18n: difftool: mark warnings for translation\n\n Makefile                  |   3 +-\n git-add--interactive.perl | 358 ++++++++++++++++++++++++++++++++++------------\n git-difftool.perl         |  18 +--\n git-send-email.perl       | 160 +++++++++++----------\n perl/Git/I18N.pm          |   4 +-\n t/t0202/test.pl           |  11 +-\n 6 files changed, 376 insertions(+), 178 deletions(-)\n\n---- >8 ----\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 1652a57..235142c 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -614,12 +614,12 @@ sub list_and_choose {\n \t\t\telse {\n \t\t\t\t$bottom = $top = find_unique($choice, @stuff);\n \t\t\t\tif (!defined $bottom) {\n-\t\t\t\t\terror_msg sprintf __(\"Huh (%s)?\\n\"), $choice;\n+\t\t\t\t\terror_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n \t\t\t\t\tnext TOPLOOP;\n \t\t\t\t}\n \t\t\t}\n \t\t\tif ($opts->{SINGLETON} && $bottom != $top) {\n-\t\t\t\terror_msg sprintf __(\"Huh (%s)?\\n\"), $choice;\n+\t\t\t\terror_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n \t\t\t\tnext TOPLOOP;\n \t\t\t}\n \t\t\tfor ($i = $bottom-1; $i <= $top-1; $i++) {\n@@ -669,17 +669,17 @@ sub say_n_paths {\n \tmy $did = shift @_;\n \tmy $cnt = scalar @_;\n \tif ($did eq 'added') {\n-\t\tprintf Q__(\"added one path\\n\", \"added %d paths\\n\",\n-\t\t\t   $cnt), $cnt;\n+\t\tprintf(Q__(\"added one path\\n\", \"added %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n \t} elsif ($did eq 'updated') {\n-\t\tprintf Q__(\"updated one path\\n\", \"updated %d paths\\n\",\n-\t\t\t   $cnt), $cnt;\n+\t\tprintf(Q__(\"updated one path\\n\", \"updated %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n \t} elsif ($did eq 'reversed') {\n-\t\tprintf Q__(\"reversed one path\\n\", \"reversed %d paths\\n\",\n-\t\t\t   $cnt), $cnt;\n+\t\tprintf(Q__(\"reversed one path\\n\", \"reversed %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n \t} else {\n-\t\tprintf Q__(\"touched one path\\n\", \"touched %d paths\\n\",\n-\t\t\t   $cnt), $cnt;\n+\t\tprintf(Q__(\"touched one path\\n\", \"touched %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n \t}\n }\n \n@@ -1056,12 +1056,12 @@ sub edit_hunk_manually {\n \tmy $hunkfile = $repo->repo_path . \"/addp-hunk-edit.diff\";\n \tmy $fh;\n \topen $fh, '>', $hunkfile\n-\t\tor die sprintf __(\"failed to open hunk edit file for writing: %s\"), $!;\n+\t\tor die sprintf(__(\"failed to open hunk edit file for writing: %s\"), $!);\n \tprint $fh __(\"# Manual hunk edit mode -- see bottom for a quick guide\\n\");\n \tprint $fh @$oldtext;\n \tmy $is_reverse = $patch_mode_flavour{IS_REVERSE};\n \tmy ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');\n-\tprint $fh (sprintf __(\n+\tprint $fh sprintf(__(\n \"# ---\n # To remove '%s' lines, make them ' ' lines (context).\n # To remove '%s' lines, delete them.\n@@ -1121,7 +1121,7 @@ sub edit_hunk_manually {\n \t}\n \n \topen $fh, '<', $hunkfile\n-\t\tor die sprintf __(\"failed to open hunk edit file for reading: %s\"), $!;\n+\t\tor die sprintf(__(\"failed to open hunk edit file for reading: %s\"), $!);\n \tmy @newtext = grep { !/^#/ } <$fh>;\n \tclose $fh;\n \tunlink $hunkfile;\n@@ -1314,7 +1314,7 @@ sub apply_patch_for_checkout_commit {\n \n sub patch_update_cmd {\n \tmy @all_mods = list_modified($patch_mode_flavour{FILTER});\n-\terror_msg sprintf __(\"ignoring unmerged: %s\\n\"), $_->{VALUE}\n+\terror_msg sprintf(__(\"ignoring unmerged: %s\\n\"), $_->{VALUE})\n \t\tfor grep { $_->{UNMERGED} } @all_mods;\n \t@all_mods = grep { !$_->{UNMERGED} } @all_mods;\n \n@@ -1458,100 +1458,79 @@ sub patch_update_file {\n \t\tif ($patch_mode eq 'stage') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stage mode change [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stage deletion [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stage this hunk [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'stash') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stash mode change [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stash mode change [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stash deletion [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stash deletion [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Stash this hunk [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Stash this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'reset_head') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Unstage mode change [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Unstage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Unstage deletion [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Unstage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Unstage this hunk [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Unstage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'reset_nothead') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply mode change to index [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply mode change to index [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply deletion to index [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply deletion to index [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply this hunk to index [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply this hunk to index [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'checkout_index') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard mode change from worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard mode change from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard deletion from worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard deletion from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard this hunk from worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard this hunk from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'checkout_head') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard mode change from index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard mode change from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard deletion from index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard deletion from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Discard this hunk from index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Discard this hunk from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t} elsif ($patch_mode eq 'checkout_nothead') {\n \t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply mode change to index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply mode change to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply deletion to index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply deletion to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t} else {\n \t\t\t  print colored $prompt_color,\n-\t\t\t    sprintf __(\"Apply this hunk to index and worktree [y,n,q,a,d,/%s,?]? \"),\n-\t\t\t\t       $other;\n+\t\t\t    sprintf(__(\"Apply this hunk to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n \t\t\t}\n \t\t}\n \t\tmy $line = prompt_single_character;\n@@ -1589,13 +1568,13 @@ sub patch_update_file {\n \t\t\t\t\tchomp $response;\n \t\t\t\t}\n \t\t\t\tif ($response !~ /^\\s*\\d+\\s*$/) {\n-\t\t\t\t\terror_msg sprintf __(\"Invalid number: '%s'\\n\"),\n-\t\t\t\t\t\t      $response;\n+\t\t\t\t\terror_msg sprintf(__(\"Invalid number: '%s'\\n\"),\n+\t\t\t\t\t\t\t     $response);\n \t\t\t\t} elsif (0 < $response && $response <= $num) {\n \t\t\t\t\t$ix = $response - 1;\n \t\t\t\t} else {\n-\t\t\t\t\terror_msg sprintf __(\"Sorry, only %s hunks available.\\n\"),\n-\t\t\t\t\t\t      $num;\n+\t\t\t\t\terror_msg sprintf(__(\"Sorry, only %s hunks available.\\n\"),\n+\t\t\t\t\t\t\t     $num);\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n@@ -1633,7 +1612,7 @@ sub patch_update_file {\n \t\t\t\tif ($@) {\n \t\t\t\t\tmy ($err,$exp) = ($@, $1);\n \t\t\t\t\t$err =~ s/ at .*git-add--interactive line \\d+, <STDIN> line \\d+.*$//;\n-\t\t\t\t\terror_msg sprintf __(\"Malformed search regexp %s: %s\\n\"), $exp, $err;\n+\t\t\t\t\terror_msg sprintf(__(\"Malformed search regexp %s: %s\\n\"), $exp, $err);\n \t\t\t\t\tnext;\n \t\t\t\t}\n \t\t\t\tmy $iy = $ix;\n@@ -1690,10 +1669,10 @@ sub patch_update_file {\n \t\t\telsif ($other =~ /s/ && $line =~ /^s/) {\n \t\t\t\tmy @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});\n \t\t\t\tif (1 < @split) {\n-\t\t\t\t\tprint colored $header_color, sprintf\n+\t\t\t\t\tprint colored $header_color, sprintf(\n \t\t\t\t\t\tQ__(\"Split into %d hunk.\\n\",\n \t\t\t\t\t\t    \"Split into %d hunks.\\n\",\n-\t\t\t\t\t\t    scalar(@split)), scalar(@split);\n+\t\t\t\t\t\t    scalar(@split)), scalar(@split));\n \t\t\t\t}\n \t\t\t\tsplice (@hunk, $ix, 1, @split);\n \t\t\t\t$num = scalar @hunk;\n@@ -1798,19 +1777,19 @@ sub process_args {\n \t\t\t\t$patch_mode = $1;\n \t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t} else {\n-\t\t\t\tdie sprintf __(\"unknown --patch mode: %s\"), $1;\n+\t\t\t\tdie sprintf(__(\"unknown --patch mode: %s\"), $1);\n \t\t\t}\n \t\t} else {\n \t\t\t$patch_mode = 'stage';\n \t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t}\n-\t\tdie sprintf __(\"invalid argument %s, expecting --\"),\n-\t\t\t       $arg unless $arg eq \"--\";\n+\t\tdie sprintf(__(\"invalid argument %s, expecting --\"),\n+\t\t\t       $arg) unless $arg eq \"--\";\n \t\t%patch_mode_flavour = %{$patch_modes{$patch_mode}};\n \t\t$cmd = 1;\n \t}\n \telsif ($arg ne \"--\") {\n-\t\tdie sprintf __(\"invalid argument %s, expecting --\"), $arg;\n+\t\tdie sprintf(__(\"invalid argument %s, expecting --\"), $arg);\n \t}\n }\n \ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex fe7f003..de8d783 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -452,11 +452,11 @@ sub dir_diff\n \t\t}\n \n \t\tif (exists $wt_modified{$file} and exists $tmp_modified{$file}) {\n-\t\t\twarn sprintf __(\n-\"warning: Both files modified:\n-'%s/%s' and '%s/%s'.\n-warning: Working tree file has been left.\n-warning:\\n\"), $workdir, $file, $b, $file;\n+\t\t\twarn sprintf(__(\n+\t\t\t\t\"warning: Both files modified:\\n\" .\n+\t\t\t\t\"'%s/%s' and '%s/%s'.\\n\" .\n+\t\t\t\t\"warning: Working tree file has been left.\\n\" .\n+\t\t\t\t\"warning:\\n\"), $workdir, $file, $b, $file);\n \t\t\t$error = 1;\n \t\t} elsif (exists $tmp_modified{$file}) {\n \t\t\tmy $mode = stat(\"$b/$file\")->mode;\n@@ -468,9 +468,9 @@ warning:\\n\"), $workdir, $file, $b, $file;\n \t\t}\n \t}\n \tif ($error) {\n-\t\twarn sprintf __(\n-\"warning: Temporary files exist in '%s'.\n-warning: You may want to cleanup or recover these.\\n\"), $tmpdir;\n+\t\twarn sprintf(__(\n+\t\t\t\"warning: Temporary files exist in '%s'.\\n\" .\n+\t\t\t\"warning: You may want to cleanup or recover these.\\n\"), $tmpdir);\n \t\texit(1);\n \t} else {\n \t\texit_cleanup($tmpdir, $rc);\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex f445a5e..c29381b 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -434,7 +434,7 @@ $smtp_encryption = '' unless (defined $smtp_encryption);\n my(%suppress_cc);\n if (@suppress_cc) {\n \tforeach my $entry (@suppress_cc) {\n-\t\tdie sprintf __(\"Unknown --suppress-cc field: '%s'\\n\"), $entry\n+\t\tdie sprintf(__(\"Unknown --suppress-cc field: '%s'\\n\"), $entry)\n \t\t\tunless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc)$/;\n \t\t$suppress_cc{$entry} = 1;\n \t}\n@@ -585,12 +585,12 @@ sub is_format_patch_arg {\n \t\tif (defined($format_patch)) {\n \t\t\treturn $format_patch;\n \t\t}\n-\t\tdie sprintf __(\n+\t\tdie sprintf(__(\n \"File '%s' exists but it could also be the range of commits\n to produce patches for.  Please disambiguate by...\n \n     * Saying \\\"./%s\\\" if you mean a file; or\n-    * Giving --format-patch option if you mean a range.\"), $f, $f;\n+    * Giving --format-patch option if you mean a range.\"), $f, $f);\n \t} catch Git::Error::Command with {\n \t\t# Not a valid revision.  Treat it as a filename.\n \t\treturn 0;\n@@ -606,7 +606,7 @@ while (defined(my $f = shift @ARGV)) {\n \t\t@ARGV = ();\n \t} elsif (-d $f and !is_format_patch_arg($f)) {\n \t\topendir my $dh, $f\n-\t\t\tor die sprintf __(\"Failed to opendir %s: %s\"), $f, $!;\n+\t\t\tor die sprintf(__(\"Failed to opendir %s: %s\"), $f, $!);\n \n \t\tpush @files, grep { -f $_ } map { catfile($f, $_) }\n \t\t\t\tsort readdir $dh;\n@@ -628,8 +628,8 @@ if ($validate) {\n \tforeach my $f (@files) {\n \t\tunless (-p $f) {\n \t\t\tmy $error = validate_patch($f);\n-\t\t\t$error and die sprintf __(\"fatal: %s: %s\\nwarning: no patches were sent\\n\"),\n-\t\t\t\t\t\t  $f, $error;\n+\t\t\t$error and die sprintf(__(\"fatal: %s: %s\\nwarning: no patches were sent\\n\"),\n+\t\t\t\t\t\t  $f, $error);\n \t\t}\n \t}\n }\n@@ -652,7 +652,7 @@ sub get_patch_subject {\n \t\treturn \"GIT: $1\\n\";\n \t}\n \tclose $fh;\n-\tdie sprintf __(\"No subject line in %s ?\"), $fn;\n+\tdie sprintf(__(\"No subject line in %s ?\"), $fn);\n }\n \n if ($compose) {\n@@ -662,7 +662,7 @@ if ($compose) {\n \t\ttempfile(\".gitsendemail.msg.XXXXXX\", DIR => $repo->repo_path()) :\n \t\ttempfile(\".gitsendemail.msg.XXXXXX\", DIR => \".\"))[1];\n \topen my $c, \">\", $compose_filename\n-\t\tor die sprintf __(\"Failed to open for writing %s: %s\"), $compose_filename, $!;\n+\t\tor die sprintf(__(\"Failed to open for writing %s: %s\"), $compose_filename, $!);\n \n \n \tmy $tpl_sender = $sender || $repoauthor || $repocommitter || '';\n@@ -693,10 +693,10 @@ EOT\n \t}\n \n \topen my $c2, \">\", $compose_filename . \".final\"\n-\t\tor die sprintf __(\"Failed to open %s.final : %s\"), $compose_filename, $!;\n+\t\tor die sprintf(__(\"Failed to open %s.final : %s\"), $compose_filename, $!);\n \n \topen $c, \"<\", $compose_filename\n-\t\tor die sprintf __(\"Failed to open %s : %s\"), $compose_filename, $!;\n+\t\tor die sprintf(__(\"Failed to open %s : %s\"), $compose_filename, $!);\n \n \tmy $need_8bit_cte = file_has_nonascii($compose_filename);\n \tmy $in_body = 0;\n@@ -772,7 +772,7 @@ sub ask {\n \t\tif ($confirm_only) {\n \t\t\t# TRANSLATORS: Keep [y/N] as is.\n \t\t\tmy $yesno = $term->readline(\n-\t\t\t\tsprintf __(\"Are you sure you want to use <%s> [y/N]? \"), $resp);\n+\t\t\t\tsprintf(__(\"Are you sure you want to use <%s> [y/N]? \"), $resp));\n \t\t\tif (defined $yesno && $yesno =~ /y/i) {\n \t\t\t\treturn $resp;\n \t\t\t}\n@@ -851,7 +851,7 @@ my %EXPANDED_ALIASES;\n sub expand_one_alias {\n \tmy $alias = shift;\n \tif ($EXPANDED_ALIASES{$alias}) {\n-\t\tdie sprintf __(\"fatal: alias '%s' expands to itself\\n\"), $alias;\n+\t\tdie sprintf(__(\"fatal: alias '%s' expands to itself\\n\"), $alias);\n \t}\n \tlocal $EXPANDED_ALIASES{$alias} = 1;\n \treturn $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;\n@@ -1226,7 +1226,7 @@ sub ssl_verify_params {\n \t\treturn (SSL_verify_mode => SSL_VERIFY_PEER(),\n \t\t\tSSL_ca_file => $smtp_ssl_cert_path);\n \t} else {\n-\t\tdie sprintf __(\"CA path \\\"%s\\\" does not exist\"), $smtp_ssl_cert_path;\n+\t\tdie sprintf(__(\"CA path \\\"%s\\\" does not exist\"), $smtp_ssl_cert_path);\n \t}\n }\n \n@@ -1388,7 +1388,7 @@ Message-Id: $message_id\n \t\t\t\t\t# supported commands\n \t\t\t\t\t$smtp->hello($smtp_domain);\n \t\t\t\t} else {\n-\t\t\t\t\tdie sprintf __(\"Server does not support STARTTLS! %s\"), $smtp->message;\n+\t\t\t\t\tdie sprintf(__(\"Server does not support STARTTLS! %s\"), $smtp->message);\n \t\t\t\t}\n \t\t\t}\n \t\t}\n@@ -1445,7 +1445,7 @@ $subject = $initial_subject;\n $message_num = 0;\n \n foreach my $t (@files) {\n-\topen my $fh, \"<\", $t or die sprintf __(\"can't open file %s\"), $t;\n+\topen my $fh, \"<\", $t or die sprintf(__(\"can't open file %s\"), $t);\n \n \tmy $author = undef;\n \tmy $sauthor = undef;\n@@ -1678,7 +1678,7 @@ sub recipients_cmd {\n \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n \tclose $fh\n-\t    or die sprintf __(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd;\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n@@ -1732,10 +1732,10 @@ sub unique_email_list {\n sub validate_patch {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die sprintf __(\"unable to open %s: %s\\n\"), $fn, $!;\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\tif (length($line) > 998) {\n-\t\t\treturn sprintf __(\"%s: patch contains a line longer than 998 characters\"), $.;\n+\t\t\treturn sprintf(__(\"%s: patch contains a line longer than 998 characters\"), $.);\n \t\t}\n \t}\n \treturn;\n@@ -1744,7 +1744,7 @@ sub validate_patch {\n sub file_has_nonascii {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die sprintf __(\"unable to open %s: %s\\n\"), $fn, $!;\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\treturn 1 if $line =~ /[^[:ascii:]]/;\n \t}\n@@ -1754,7 +1754,7 @@ sub file_has_nonascii {\n sub body_or_subject_has_nonascii {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die sprintf __(\"unable to open %s: %s\\n\"), $fn, $!;\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\tlast if $line =~ /^$/;\n \t\treturn 1 if $line =~ /^Subject.*[^[:ascii:]]/;\n---- >8 ----\n\n-- \n2.7.4\n\n"},{"id":"300677","messageId":"1472646690-9699-2-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:20Z","receivedAt":"2016-08-31T12:32:52Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark simple strings (without interpolation) for translation.\n\nBrackets around first parameter of ternary operator is necessary because\notherwise xgettext fails to extract strings marked for translation from\nthe rest of the file.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 68 +++++++++++++++++++++++++----------------------\n 1 file changed, 36 insertions(+), 32 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 822f857..fb8e5de 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -4,6 +4,7 @@ use 5.008;\n use strict;\n use warnings;\n use Git;\n+use Git::I18N;\n \n binmode(STDOUT, \":raw\");\n \n@@ -252,7 +253,7 @@ sub list_untracked {\n }\n \n my $status_fmt = '%12s %12s %s';\n-my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n+my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));\n \n {\n \tmy $initial;\n@@ -678,7 +679,7 @@ sub update_cmd {\n \tmy @mods = list_modified('file-only');\n \treturn if (!@mods);\n \n-\tmy @update = list_and_choose({ PROMPT => 'Update',\n+\tmy @update = list_and_choose({ PROMPT => __('Update'),\n \t\t\t\t       HEADER => $status_head, },\n \t\t\t\t     @mods);\n \tif (@update) {\n@@ -690,7 +691,7 @@ sub update_cmd {\n }\n \n sub revert_cmd {\n-\tmy @update = list_and_choose({ PROMPT => 'Revert',\n+\tmy @update = list_and_choose({ PROMPT => __('Revert'),\n \t\t\t\t       HEADER => $status_head, },\n \t\t\t\t     list_modified());\n \tif (@update) {\n@@ -724,13 +725,13 @@ sub revert_cmd {\n }\n \n sub add_untracked_cmd {\n-\tmy @add = list_and_choose({ PROMPT => 'Add untracked' },\n+\tmy @add = list_and_choose({ PROMPT => __('Add untracked') },\n \t\t\t\t  list_untracked());\n \tif (@add) {\n \t\tsystem(qw(git update-index --add --), @add);\n \t\tsay_n_paths('added', @add);\n \t} else {\n-\t\tprint \"No untracked files.\\n\";\n+\t\tprint __(\"No untracked files.\\n\");\n \t}\n \tprint \"\\n\";\n }\n@@ -1159,8 +1160,11 @@ sub edit_hunk_loop {\n \t\t}\n \t\telse {\n \t\t\tprompt_yesno(\n-\t\t\t\t'Your edited hunk does not apply. Edit again '\n-\t\t\t\t. '(saying \"no\" discards!) [y/n]? '\n+\t\t\t\t# TRANSLATORS: do not translate [y/n]\n+\t\t\t\t# The program will only accept that input\n+\t\t\t\t# at this point.\n+\t\t\t\t__('Your edited hunk does not apply. Edit again '\n+\t\t\t\t   . '(saying \"no\" discards!) [y/n]? ')\n \t\t\t\t) or return undef;\n \t\t}\n \t}\n@@ -1206,11 +1210,11 @@ sub apply_patch_for_checkout_commit {\n \t\trun_git_apply 'apply '.$reverse, @_;\n \t\treturn 1;\n \t} elsif (!$applies_index) {\n-\t\tprint colored $error_color, \"The selected hunks do not apply to the index!\\n\";\n-\t\tif (prompt_yesno \"Apply them to the worktree anyway? \") {\n+\t\tprint colored $error_color, __(\"The selected hunks do not apply to the index!\\n\");\n+\t\tif (prompt_yesno __(\"Apply them to the worktree anyway? \")) {\n \t\t\treturn run_git_apply 'apply '.$reverse, @_;\n \t\t} else {\n-\t\t\tprint colored $error_color, \"Nothing was applied.\\n\";\n+\t\t\tprint colored $error_color, __(\"Nothing was applied.\\n\");\n \t\t\treturn 0;\n \t\t}\n \t} else {\n@@ -1230,9 +1234,9 @@ sub patch_update_cmd {\n \n \tif (!@mods) {\n \t\tif (@all_mods) {\n-\t\t\tprint STDERR \"Only binary files changed.\\n\";\n+\t\t\tprint STDERR __(\"Only binary files changed.\\n\");\n \t\t} else {\n-\t\t\tprint STDERR \"No changes.\\n\";\n+\t\t\tprint STDERR __(\"No changes.\\n\");\n \t\t}\n \t\treturn 0;\n \t}\n@@ -1390,12 +1394,12 @@ sub patch_update_file {\n \t\t\t\tmy $response = $1;\n \t\t\t\tmy $no = $ix > 10 ? $ix - 10 : 0;\n \t\t\t\twhile ($response eq '') {\n-\t\t\t\t\tmy $extra = \"\";\n \t\t\t\t\t$no = display_hunks(\\@hunk, $no);\n \t\t\t\t\tif ($no < $num) {\n-\t\t\t\t\t\t$extra = \" (<ret> to see more)\";\n+\t\t\t\t\t\tprint __(\"go to which hunk (<ret> to see more)? \");\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tprint __(\"go to which hunk? \");\n \t\t\t\t\t}\n-\t\t\t\t\tprint \"go to which hunk$extra? \";\n \t\t\t\t\t$response = <STDIN>;\n \t\t\t\t\tif (!defined $response) {\n \t\t\t\t\t\t$response = '';\n@@ -1432,7 +1436,7 @@ sub patch_update_file {\n \t\t\telsif ($line =~ m|^/(.*)|) {\n \t\t\t\tmy $regex = $1;\n \t\t\t\tif ($1 eq \"\") {\n-\t\t\t\t\tprint colored $prompt_color, \"search for regex? \";\n+\t\t\t\t\tprint colored $prompt_color, __(\"search for regex? \");\n \t\t\t\t\t$regex = <STDIN>;\n \t\t\t\t\tif (defined $regex) {\n \t\t\t\t\t\tchomp $regex;\n@@ -1455,7 +1459,7 @@ sub patch_update_file {\n \t\t\t\t\t$iy++;\n \t\t\t\t\t$iy = 0 if ($iy >= $num);\n \t\t\t\t\tif ($ix == $iy) {\n-\t\t\t\t\t\terror_msg \"No hunk matches the given pattern\\n\";\n+\t\t\t\t\t\terror_msg __(\"No hunk matches the given pattern\\n\");\n \t\t\t\t\t\tlast;\n \t\t\t\t\t}\n \t\t\t\t}\n@@ -1467,7 +1471,7 @@ sub patch_update_file {\n \t\t\t\t\t$ix--;\n \t\t\t\t}\n \t\t\t\telse {\n-\t\t\t\t\terror_msg \"No previous hunk\\n\";\n+\t\t\t\t\terror_msg __(\"No previous hunk\\n\");\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n@@ -1476,7 +1480,7 @@ sub patch_update_file {\n \t\t\t\t\t$ix++;\n \t\t\t\t}\n \t\t\t\telse {\n-\t\t\t\t\terror_msg \"No next hunk\\n\";\n+\t\t\t\t\terror_msg __(\"No next hunk\\n\");\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n@@ -1489,13 +1493,13 @@ sub patch_update_file {\n \t\t\t\t\t}\n \t\t\t\t}\n \t\t\t\telse {\n-\t\t\t\t\terror_msg \"No previous hunk\\n\";\n+\t\t\t\t\terror_msg __(\"No previous hunk\\n\");\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n \t\t\telsif ($line =~ /^j/) {\n \t\t\t\tif ($other !~ /j/) {\n-\t\t\t\t\terror_msg \"No next hunk\\n\";\n+\t\t\t\t\terror_msg __(\"No next hunk\\n\");\n \t\t\t\t\tnext;\n \t\t\t\t}\n \t\t\t}\n@@ -1553,18 +1557,18 @@ sub diff_cmd {\n \tmy @mods = list_modified('index-only');\n \t@mods = grep { !($_->{BINARY}) } @mods;\n \treturn if (!@mods);\n-\tmy (@them) = list_and_choose({ PROMPT => 'Review diff',\n+\tmy (@them) = list_and_choose({ PROMPT => __('Review diff'),\n \t\t\t\t     IMMEDIATE => 1,\n \t\t\t\t     HEADER => $status_head, },\n \t\t\t\t   @mods);\n \treturn if (!@them);\n-\tmy $reference = is_initial_commit() ? get_empty_tree() : 'HEAD';\n+\tmy $reference = (is_initial_commit()) ? get_empty_tree() : 'HEAD';\n \tsystem(qw(git diff -p --cached), $reference, '--',\n \t\tmap { $_->{VALUE} } @them);\n }\n \n sub quit_cmd {\n-\tprint \"Bye.\\n\";\n+\tprint __(\"Bye.\\n\");\n \texit(0);\n }\n \n@@ -1587,32 +1591,32 @@ sub process_args {\n \t\t\tif ($1 eq 'reset') {\n \t\t\t\t$patch_mode = 'reset_head';\n \t\t\t\t$patch_mode_revision = 'HEAD';\n-\t\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t\tif ($arg ne '--') {\n \t\t\t\t\t$patch_mode_revision = $arg;\n \t\t\t\t\t$patch_mode = ($arg eq 'HEAD' ?\n \t\t\t\t\t\t       'reset_head' : 'reset_nothead');\n-\t\t\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t\t}\n \t\t\t} elsif ($1 eq 'checkout') {\n-\t\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t\tif ($arg eq '--') {\n \t\t\t\t\t$patch_mode = 'checkout_index';\n \t\t\t\t} else {\n \t\t\t\t\t$patch_mode_revision = $arg;\n \t\t\t\t\t$patch_mode = ($arg eq 'HEAD' ?\n \t\t\t\t\t\t       'checkout_head' : 'checkout_nothead');\n-\t\t\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t\t}\n \t\t\t} elsif ($1 eq 'stage' or $1 eq 'stash') {\n \t\t\t\t$patch_mode = $1;\n-\t\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t} else {\n \t\t\t\tdie \"unknown --patch mode: $1\";\n \t\t\t}\n \t\t} else {\n \t\t\t$patch_mode = 'stage';\n-\t\t\t$arg = shift @ARGV or die \"missing --\";\n+\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t}\n \t\tdie \"invalid argument $arg, expecting --\"\n \t\t    unless $arg eq \"--\";\n@@ -1634,10 +1638,10 @@ sub main_loop {\n \t\t   [ 'help', \\&help_cmd, ],\n \t);\n \twhile (1) {\n-\t\tmy ($it) = list_and_choose({ PROMPT => 'What now',\n+\t\tmy ($it) = list_and_choose({ PROMPT => __('What now'),\n \t\t\t\t\t     SINGLETON => 1,\n \t\t\t\t\t     LIST_FLAT => 4,\n-\t\t\t\t\t     HEADER => '*** Commands ***',\n+\t\t\t\t\t     HEADER => __('*** Commands ***'),\n \t\t\t\t\t     ON_EOF => \\&quit_cmd,\n \t\t\t\t\t     IMMEDIATE => 1 }, @cmd);\n \t\tif ($it) {\n-- \n2.7.4\n\n"},{"id":"300678","messageId":"1472646690-9699-3-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:21Z","receivedAt":"2016-08-31T12:32:57Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark messages in here document without interpolation for translation.\n\nMarking for translation by removing here documents this way, rather than\ntake advantage of \"print __ << EOF\" way, makes other instances of help\nmessages in clean.c match the first two in this file.  Otherwise,\nreusing here document would add a trailer newline to the message, making\nthem not match 100%, hence creating two entries in pot template for\ntranslation rather than a single entry.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex fb8e5de..e11a33d 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -636,25 +636,25 @@ sub list_and_choose {\n }\n \n sub singleton_prompt_help_cmd {\n-\tprint colored $help_color, <<\\EOF ;\n-Prompt help:\n+\tprint colored $help_color, __(\n+\"Prompt help:\n 1          - select a numbered item\n foo        - select item based on unique prefix\n-           - (empty) select nothing\n-EOF\n+           - (empty) select nothing\"),\n+\"\\n\";\n }\n \n sub prompt_help_cmd {\n-\tprint colored $help_color, <<\\EOF ;\n-Prompt help:\n+\tprint colored $help_color, __(\n+\"Prompt help:\n 1          - select a single item\n 3-5        - select a range of items\n 2-3,6-9    - select multiple ranges\n foo        - select item based on unique prefix\n -...       - unselect specified items\n *          - choose all items\n-           - (empty) finish selecting\n-EOF\n+           - (empty) finish selecting\"),\n+\"\\n\";\n }\n \n sub status_cmd {\n@@ -1573,14 +1573,14 @@ sub quit_cmd {\n }\n \n sub help_cmd {\n-\tprint colored $help_color, <<\\EOF ;\n-status        - show paths with changes\n+\tprint colored $help_color, __(\n+\"status        - show paths with changes\n update        - add working tree state to the staged set of changes\n revert        - revert staged set of changes back to the HEAD version\n patch         - pick hunks and update selectively\n diff\t      - view diff between HEAD and index\n-add untracked - add contents of untracked files to the staged set of changes\n-EOF\n+add untracked - add contents of untracked files to the staged set of changes\"),\n+\"\\n\";\n }\n \n sub process_args {\n-- \n2.7.4\n\n"},{"id":"300679","messageId":"1472646690-9699-4-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 03/11] i18n: add--interactive: mark strings with interpolation for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:22Z","receivedAt":"2016-08-31T12:33:00Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Use of sprintf following die or error_msg is necessary for placeholder\nsubstitution take place.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 26 ++++++++++++++------------\n 1 file changed, 14 insertions(+), 12 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex e11a33d..4e1e857 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -612,12 +612,12 @@ sub list_and_choose {\n \t\t\telse {\n \t\t\t\t$bottom = $top = find_unique($choice, @stuff);\n \t\t\t\tif (!defined $bottom) {\n-\t\t\t\t\terror_msg \"Huh ($choice)?\\n\";\n+\t\t\t\t\terror_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n \t\t\t\t\tnext TOPLOOP;\n \t\t\t\t}\n \t\t\t}\n \t\t\tif ($opts->{SINGLETON} && $bottom != $top) {\n-\t\t\t\terror_msg \"Huh ($choice)?\\n\";\n+\t\t\t\terror_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n \t\t\t\tnext TOPLOOP;\n \t\t\t}\n \t\t\tfor ($i = $bottom-1; $i <= $top-1; $i++) {\n@@ -1048,7 +1048,7 @@ sub edit_hunk_manually {\n \tmy $hunkfile = $repo->repo_path . \"/addp-hunk-edit.diff\";\n \tmy $fh;\n \topen $fh, '>', $hunkfile\n-\t\tor die \"failed to open hunk edit file for writing: \" . $!;\n+\t\tor die sprintf(__(\"failed to open hunk edit file for writing: %s\"), $!);\n \tprint $fh \"# Manual hunk edit mode -- see bottom for a quick guide\\n\";\n \tprint $fh @$oldtext;\n \tmy $participle = $patch_mode_flavour{PARTICIPLE};\n@@ -1075,7 +1075,7 @@ EOF\n \t}\n \n \topen $fh, '<', $hunkfile\n-\t\tor die \"failed to open hunk edit file for reading: \" . $!;\n+\t\tor die sprintf(__(\"failed to open hunk edit file for reading: %s\"), $!);\n \tmy @newtext = grep { !/^#/ } <$fh>;\n \tclose $fh;\n \tunlink $hunkfile;\n@@ -1225,7 +1225,7 @@ sub apply_patch_for_checkout_commit {\n \n sub patch_update_cmd {\n \tmy @all_mods = list_modified($patch_mode_flavour{FILTER});\n-\terror_msg \"ignoring unmerged: $_->{VALUE}\\n\"\n+\terror_msg sprintf(__(\"ignoring unmerged: %s\\n\"), $_->{VALUE})\n \t\tfor grep { $_->{UNMERGED} } @all_mods;\n \t@all_mods = grep { !$_->{UNMERGED} } @all_mods;\n \n@@ -1407,11 +1407,13 @@ sub patch_update_file {\n \t\t\t\t\tchomp $response;\n \t\t\t\t}\n \t\t\t\tif ($response !~ /^\\s*\\d+\\s*$/) {\n-\t\t\t\t\terror_msg \"Invalid number: '$response'\\n\";\n+\t\t\t\t\terror_msg sprintf(__(\"Invalid number: '%s'\\n\"),\n+\t\t\t\t\t\t\t     $response);\n \t\t\t\t} elsif (0 < $response && $response <= $num) {\n \t\t\t\t\t$ix = $response - 1;\n \t\t\t\t} else {\n-\t\t\t\t\terror_msg \"Sorry, only $num hunks available.\\n\";\n+\t\t\t\t\terror_msg sprintf(__(\"Sorry, only %s hunks available.\\n\"),\n+\t\t\t\t\t\t\t     $num);\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n@@ -1449,7 +1451,7 @@ sub patch_update_file {\n \t\t\t\tif ($@) {\n \t\t\t\t\tmy ($err,$exp) = ($@, $1);\n \t\t\t\t\t$err =~ s/ at .*git-add--interactive line \\d+, <STDIN> line \\d+.*$//;\n-\t\t\t\t\terror_msg \"Malformed search regexp $exp: $err\\n\";\n+\t\t\t\t\terror_msg sprintf(__(\"Malformed search regexp %s: %s\\n\"), $exp, $err);\n \t\t\t\t\tnext;\n \t\t\t\t}\n \t\t\t\tmy $iy = $ix;\n@@ -1612,18 +1614,18 @@ sub process_args {\n \t\t\t\t$patch_mode = $1;\n \t\t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t\t} else {\n-\t\t\t\tdie \"unknown --patch mode: $1\";\n+\t\t\t\tdie sprintf(__(\"unknown --patch mode: %s\"), $1);\n \t\t\t}\n \t\t} else {\n \t\t\t$patch_mode = 'stage';\n \t\t\t$arg = shift @ARGV or die __(\"missing --\");\n \t\t}\n-\t\tdie \"invalid argument $arg, expecting --\"\n-\t\t    unless $arg eq \"--\";\n+\t\tdie sprintf(__(\"invalid argument %s, expecting --\"),\n+\t\t\t       $arg) unless $arg eq \"--\";\n \t\t%patch_mode_flavour = %{$patch_modes{$patch_mode}};\n \t}\n \telsif ($arg ne \"--\") {\n-\t\tdie \"invalid argument $arg, expecting --\";\n+\t\tdie sprintf(__(\"invalid argument %s, expecting --\"), $arg);\n \t}\n }\n \n-- \n2.7.4\n\n"},{"id":"300680","messageId":"1472646690-9699-5-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 04/11] i18n: add--interactive: mark plural strings","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:23Z","receivedAt":"2016-08-31T12:33:04Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark plural strings for translation.  Unfold each action case in one\nentire sentence.\n\nPass new keyword for xgettext to extract.\n\nUpdate test to include new subrotine Q__() for plural strings handling.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n Makefile                  |  3 ++-\n git-add--interactive.perl | 24 ++++++++++++++++--------\n perl/Git/I18N.pm          |  4 +++-\n t/t0202/test.pl           | 11 ++++++++++-\n 4 files changed, 31 insertions(+), 11 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex de5a030..eedf1fa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2061,7 +2061,8 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n \t--keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \\\n \t--keyword=gettextln --keyword=eval_gettextln\n-XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl\n+XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n+\t--keyword=__ --keyword=\"Q__:1,2\"\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 4e1e857..08badfa 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -666,12 +666,18 @@ sub status_cmd {\n sub say_n_paths {\n \tmy $did = shift @_;\n \tmy $cnt = scalar @_;\n-\tprint \"$did \";\n-\tif (1 < $cnt) {\n-\t\tprint \"$cnt paths\\n\";\n-\t}\n-\telse {\n-\t\tprint \"one path\\n\";\n+\tif ($did eq 'added') {\n+\t\tprintf(Q__(\"added one path\\n\", \"added %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n+\t} elsif ($did eq 'updated') {\n+\t\tprintf(Q__(\"updated one path\\n\", \"updated %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n+\t} elsif ($did eq 'reversed') {\n+\t\tprintf(Q__(\"reversed one path\\n\", \"reversed %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n+\t} else {\n+\t\tprintf(Q__(\"touched one path\\n\", \"touched %d paths\\n\",\n+\t\t\t   $cnt), $cnt);\n \t}\n }\n \n@@ -1508,8 +1514,10 @@ sub patch_update_file {\n \t\t\telsif ($other =~ /s/ && $line =~ /^s/) {\n \t\t\t\tmy @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});\n \t\t\t\tif (1 < @split) {\n-\t\t\t\t\tprint colored $header_color, \"Split into \",\n-\t\t\t\t\tscalar(@split), \" hunks.\\n\";\n+\t\t\t\t\tprint colored $header_color, sprintf(\n+\t\t\t\t\t\tQ__(\"Split into %d hunk.\\n\",\n+\t\t\t\t\t\t    \"Split into %d hunks.\\n\",\n+\t\t\t\t\t\t    scalar(@split)), scalar(@split));\n \t\t\t\t}\n \t\t\t\tsplice (@hunk, $ix, 1, @split);\n \t\t\t\t$num = scalar @hunk;\ndiff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm\nindex f889fd6..5a75dd5 100644\n--- a/perl/Git/I18N.pm\n+++ b/perl/Git/I18N.pm\n@@ -13,7 +13,7 @@ BEGIN {\n \t}\n }\n \n-our @EXPORT = qw(__);\n+our @EXPORT = qw(__ Q__);\n our @EXPORT_OK = @EXPORT;\n \n sub __bootstrap_locale_messages {\n@@ -44,6 +44,7 @@ BEGIN\n \teval {\n \t\t__bootstrap_locale_messages();\n \t\t*__ = \\&Locale::Messages::gettext;\n+\t\t*Q__ = \\&Locale::Messages::ngettext;\n \t\t1;\n \t} or do {\n \t\t# Tell test.pl that we couldn't load the gettext library.\n@@ -51,6 +52,7 @@ BEGIN\n \n \t\t# Just a fall-through no-op\n \t\t*__ = sub ($) { $_[0] };\n+\t\t*Q__ = sub ($$$) { $_[2] == 1 ? $_[0] : $_[1] };\n \t};\n }\n \ndiff --git a/t/t0202/test.pl b/t/t0202/test.pl\nindex 2c10cb4..98aa9a3 100755\n--- a/t/t0202/test.pl\n+++ b/t/t0202/test.pl\n@@ -4,7 +4,7 @@ use lib (split(/:/, $ENV{GITPERLLIB}));\n use strict;\n use warnings;\n use POSIX qw(:locale_h);\n-use Test::More tests => 8;\n+use Test::More tests => 11;\n use Git::I18N;\n \n my $has_gettext_library = $Git::I18N::__HAS_LIBRARY;\n@@ -31,6 +31,7 @@ is_deeply(\\@Git::I18N::EXPORT, \\@Git::I18N::EXPORT_OK, \"sanity: Git::I18N export\n \t# more gettext wrapper functions.\n \tmy %prototypes = (qw(\n \t\t__\t$\n+\t\tQ__\t$$$\n \t));\n \twhile (my ($sub, $proto) = each %prototypes) {\n \t\tis(prototype(\\&{\"Git::I18N::$sub\"}), $proto, \"sanity: $sub has a $proto prototype\");\n@@ -46,6 +47,14 @@ is_deeply(\\@Git::I18N::EXPORT, \\@Git::I18N::EXPORT_OK, \"sanity: Git::I18N export\n \tmy ($got, $expect) = (('TEST: A Perl test string') x 2);\n \n \tis(__($got), $expect, \"Passing a string through __() in the C locale works\");\n+\n+\tmy ($got_singular, $got_plural, $expect_singular, $expect_plural) =\n+\t\t(('TEST: 1 file', 'TEST: n files') x 2);\n+\n+\tis(Q__($got_singular, $got_plural, 1), $expect_singular,\n+\t\t\"Get singular string through Q__() in C locale\");\n+\tis(Q__($got_singular, $got_plural, 2), $expect_plural,\n+\t\t\"Get plural string through Q__() in C locale\");\n }\n \n # Test a basic message on different locales\n-- \n2.7.4\n\n"},{"id":"300681","messageId":"1472646690-9699-6-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 05/11] i18n: add--interactive: mark message for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:24Z","receivedAt":"2016-08-31T12:33:09Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark message assembled in place for translation, unfolding each use case\nfor each entry in the %patch_modes hash table.\n\nPreviously, this script relied on whether $patch_mode was set to run the\ncommand patch_update_cmd() or show status and loop the main loop. Now,\nit uses $cmd to indicate we must run patch_update_cmd() and $patch_mode\nis used to tell which flavor of the %patch_modes are we on.  This is\nintroduced in order to be able to mark and unfold the message prompt\nknowing in which context we are.\n\nThe tracking of context was done previously by point %patch_mode_flavour\nhash table to the correct entry of %patch_modes, focusing only on value\nof %patch_modes. Now, we are also interested in the key ('staged',\n'stash', 'checkout_head', ...).\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 91 ++++++++++++++++++++++++++++++++++++++++++-----\n 1 file changed, 83 insertions(+), 8 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 08badfa..5b89b97 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -91,6 +91,7 @@ sub colored {\n }\n \n # command line options\n+my $cmd;\n my $patch_mode;\n my $patch_mode_revision;\n \n@@ -171,7 +172,8 @@ my %patch_modes = (\n \t},\n );\n \n-my %patch_mode_flavour = %{$patch_modes{stage}};\n+$patch_mode = 'stage';\n+my %patch_mode_flavour = %{$patch_modes{$patch_mode}};\n \n sub run_cmd_pipe {\n \tif ($^O eq 'MSWin32') {\n@@ -1372,12 +1374,84 @@ sub patch_update_file {\n \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n \t\t\tprint;\n \t\t}\n-\t\tprint colored $prompt_color, $patch_mode_flavour{VERB},\n-\t\t  ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' :\n-\t\t   $hunk[$ix]{TYPE} eq 'deletion' ? ' deletion' :\n-\t\t   ' this hunk'),\n-\t\t  $patch_mode_flavour{TARGET},\n-\t\t  \" [y,n,q,a,d,/$other,?]? \";\n+\t\tif ($patch_mode eq 'stage') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'stash') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stash mode change [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stash deletion [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Stash this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'reset_head') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Unstage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Unstage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Unstage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'reset_nothead') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply mode change to index [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply deletion to index [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply this hunk to index [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'checkout_index') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard mode change from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard deletion from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard this hunk from worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'checkout_head') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard mode change from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard deletion from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Discard this hunk from index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t} elsif ($patch_mode eq 'checkout_nothead') {\n+\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply mode change to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply deletion to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t} else {\n+\t\t\t  print colored $prompt_color,\n+\t\t\t    sprintf(__(\"Apply this hunk to index and worktree [y,n,q,a,d,/%s,?]? \"), $other);\n+\t\t\t}\n+\t\t}\n \t\tmy $line = prompt_single_character;\n \t\tlast unless defined $line;\n \t\tif ($line) {\n@@ -1631,6 +1705,7 @@ sub process_args {\n \t\tdie sprintf(__(\"invalid argument %s, expecting --\"),\n \t\t\t       $arg) unless $arg eq \"--\";\n \t\t%patch_mode_flavour = %{$patch_modes{$patch_mode}};\n+\t\t$cmd = 1;\n \t}\n \telsif ($arg ne \"--\") {\n \t\tdie sprintf(__(\"invalid argument %s, expecting --\"), $arg);\n@@ -1667,7 +1742,7 @@ sub main_loop {\n \n process_args();\n refresh();\n-if ($patch_mode) {\n+if ($cmd) {\n \tpatch_update_cmd();\n }\n else {\n-- \n2.7.4\n\n"},{"id":"300682","messageId":"1472646690-9699-7-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 06/11] i18n: add--interactive: i18n of help_patch_cmd","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:25Z","receivedAt":"2016-08-31T12:33:14Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark help message of help_patch_cmd for translation.  The message must\nbe unfolded to be free of variables so we can have high quality\ntranslations.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 65 +++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 54 insertions(+), 11 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 5b89b97..acbfa4e 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -1179,15 +1179,58 @@ sub edit_hunk_loop {\n }\n \n sub help_patch_cmd {\n-\tmy $verb = lc $patch_mode_flavour{VERB};\n-\tmy $target = $patch_mode_flavour{TARGET};\n-\tprint colored $help_color, <<EOF ;\n-y - $verb this hunk$target\n-n - do not $verb this hunk$target\n-q - quit; do not $verb this hunk or any of the remaining ones\n-a - $verb this hunk and all later hunks in the file\n-d - do not $verb this hunk or any of the later hunks in the file\n-g - select a hunk to go to\n+\tif ($patch_mode eq 'stage') {\n+\t\tprint colored $help_color, __(\n+\"y - stage this hunk\n+n - do not stage this hunk\n+q - quit; do not stage this hunk or any of the remaining ones\n+a - stage this hunk and all later hunks in the file\n+d - do not stage this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'stash') {\n+\t\tprint colored $help_color, __(\n+\"y - stash this hunk\n+n - do not stash this hunk\n+q - quit; do not stash this hunk or any of the remaining ones\n+a - stash this hunk and all later hunks in the file\n+d - do not stash this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'reset_head') {\n+\t\tprint colored $help_color, __(\n+\"y - unstage this hunk\n+n - do not unstage this hunk\n+q - quit; do not unstage this hunk or any of the remaining ones\n+a - unstage this hunk and all later hunks in the file\n+d - do not unstage this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'reset_nothead') {\n+\t\tprint colored $help_color, __(\n+\"y - apply this hunk to index\n+n - do not apply this hunk to index\n+q - quit; do not apply this hunk or any of the remaining ones\n+a - apply this hunk and all later hunks in the file\n+d - do not apply this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'checkout_index') {\n+\t\tprint colored $help_color, __(\n+\"y - discard this hunk from worktree\n+n - do not discard this hunk from worktree\n+q - quit; do not discard this hunk or any of the remaining ones\n+a - discard this hunk and all later hunks in the file\n+d - do not discard this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'checkout_head') {\n+\t\tprint colored $help_color, __(\n+\"y - discard this hunk from index and worktree\n+n - do not discard this hunk from index and worktree\n+q - quit; do not discard this hunk or any of the remaining ones\n+a - discard this hunk and all later hunks in the file\n+d - do not discard this hunk or any of the later hunks in the file\");\n+\t} elsif ($patch_mode eq 'checkout_nothead') {\n+\t\tprint colored $help_color, __(\n+\"y - apply this hunk to index and worktree\n+n - do not apply this hunk to index and worktree\n+q - quit; do not apply this hunk or any of the remaining ones\n+a - apply this hunk and all later hunks in the file\n+d - do not apply this hunk or any of the later hunks in the file\");\n+\t}\n+\tprint colored $help_color, \"\\n\", __(\n+\"g - select a hunk to go to\n / - search for a hunk matching the given regex\n j - leave this hunk undecided, see next undecided hunk\n J - leave this hunk undecided, see next hunk\n@@ -1195,8 +1238,8 @@ k - leave this hunk undecided, see previous undecided hunk\n K - leave this hunk undecided, see previous hunk\n s - split the current hunk into smaller hunks\n e - manually edit the current hunk\n-? - print help\n-EOF\n+? - print help\"),\n+\"\\n\";\n }\n \n sub apply_patch {\n-- \n2.7.4\n\n"},{"id":"300683","messageId":"1472646690-9699-8-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 07/11] i18n: add--interactive: mark edit_hunk_manually message for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:26Z","receivedAt":"2016-08-31T12:33:18Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark message of edit_hunk_manually displayed in the editing file when\nuser chooses 'e' option.  The message had to be unfolded to allow\ntranslation of the $participle verb.\n\nSome messages end up being exactly the same for some uses cases, but\nleft it for easier change in the future, e.g., wanting to change wording\nof one particular use case.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-add--interactive.perl | 60 ++++++++++++++++++++++++++++++++++++++---------\n 1 file changed, 49 insertions(+), 11 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex acbfa4e..235142c 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -1057,22 +1057,60 @@ sub edit_hunk_manually {\n \tmy $fh;\n \topen $fh, '>', $hunkfile\n \t\tor die sprintf(__(\"failed to open hunk edit file for writing: %s\"), $!);\n-\tprint $fh \"# Manual hunk edit mode -- see bottom for a quick guide\\n\";\n+\tprint $fh __(\"# Manual hunk edit mode -- see bottom for a quick guide\\n\");\n \tprint $fh @$oldtext;\n-\tmy $participle = $patch_mode_flavour{PARTICIPLE};\n \tmy $is_reverse = $patch_mode_flavour{IS_REVERSE};\n \tmy ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');\n-\tprint $fh <<EOF;\n-# ---\n-# To remove '$remove_minus' lines, make them ' ' lines (context).\n-# To remove '$remove_plus' lines, delete them.\n+\tprint $fh sprintf(__(\n+\"# ---\n+# To remove '%s' lines, make them ' ' lines (context).\n+# To remove '%s' lines, delete them.\n # Lines starting with # will be removed.\n-#\n-# If the patch applies cleanly, the edited hunk will immediately be\n-# marked for $participle. If it does not apply cleanly, you will be given\n+#\"), $remove_minus, $remove_plus),\n+\"\\n\";\n+\tif ($patch_mode eq 'stage') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for staging. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'stash') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for stashing. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'reset_head') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for unstaging. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'reset_nothead') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for applying. If it does not apply cleanly, you will be given\n # an opportunity to edit again. If all lines of the hunk are removed,\n-# then the edit is aborted and the hunk is left unchanged.\n-EOF\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'checkout_index') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for discarding. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'checkout_head') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for discarding. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t} elsif ($patch_mode eq 'checkout_nothead') {\n+\t\tprint $fh __(\n+\"# If the patch applies cleanly, the edited hunk will immediately be\n+# marked for applying. If it does not apply cleanly, you will be given\n+# an opportunity to edit again. If all lines of the hunk are removed,\n+# then the edit is aborted and the hunk is left unchanged.\");\n+\t}\n \tclose $fh;\n \n \tchomp(my $editor = run_cmd_pipe(qw(git var GIT_EDITOR)));\n-- \n2.7.4\n\n"},{"id":"300684","messageId":"1472646690-9699-9-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 08/11] i18n: send-email: mark strings for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:27Z","receivedAt":"2016-08-31T12:33:38Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark strings often displayed to user for translation.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-send-email.perl | 53 +++++++++++++++++++++++++++++++----------------------\n 1 file changed, 31 insertions(+), 22 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 6958785..2521832 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -28,6 +28,7 @@ use File::Temp qw/ tempdir tempfile /;\n use File::Spec::Functions qw(catfile);\n use Error qw(:try);\n use Git;\n+use Git::I18N;\n \n Getopt::Long::Configure qw/ pass_through /;\n \n@@ -795,12 +796,12 @@ foreach my $f (@files) {\n }\n \n if (!defined $auto_8bit_encoding && scalar %broken_encoding) {\n-\tprint \"The following files are 8bit, but do not declare \" .\n-\t\t\"a Content-Transfer-Encoding.\\n\";\n+\tprint __(\"The following files are 8bit, but do not declare \" .\n+\t\t \"a Content-Transfer-Encoding.\\n\");\n \tforeach my $f (sort keys %broken_encoding) {\n \t\tprint \"    $f\\n\";\n \t}\n-\t$auto_8bit_encoding = ask(\"Which 8bit encoding should I declare [UTF-8]? \",\n+\t$auto_8bit_encoding = ask(__(\"Which 8bit encoding should I declare [UTF-8]? \"),\n \t\t\t\t  valid_re => qr/.{4}/, confirm_only => 1,\n \t\t\t\t  default => \"UTF-8\");\n }\n@@ -827,7 +828,7 @@ if (defined $sender) {\n # But it's a no-op to run sanitize_address on an already sanitized address.\n $sender = sanitize_address($sender);\n \n-my $to_whom = \"To whom should the emails be sent (if anyone)?\";\n+my $to_whom = __(\"To whom should the emails be sent (if anyone)?\");\n my $prompting = 0;\n if (!@initial_to && !defined $to_cmd) {\n \tmy $to = ask(\"$to_whom \",\n@@ -857,7 +858,7 @@ sub expand_one_alias {\n \n if ($thread && !defined $initial_reply_to && $prompting) {\n \t$initial_reply_to = ask(\n-\t\t\"Message-ID to be used as In-Reply-To for the first email (if any)? \",\n+\t\t__(\"Message-ID to be used as In-Reply-To for the first email (if any)? \"),\n \t\tdefault => \"\",\n \t\tvalid_re => qr/\\@.*\\./, confirm_only => 1);\n }\n@@ -916,7 +917,10 @@ sub validate_address {\n \tmy $address = shift;\n \twhile (!extract_valid_address($address)) {\n \t\tprint STDERR \"error: unable to extract a valid address from: $address\\n\";\n-\t\t$_ = ask(\"What to do with this address? ([q]uit|[d]rop|[e]dit): \",\n+\t\t# TRANSLATORS: Make sure to include [q] [d] [e] in your\n+\t\t# translation. The program will only accept English input\n+\t\t# at this point.\n+\t\t$_ = ask(__(\"What to do with this address? ([q]uit|[d]rop|[e]dit): \"),\n \t\t\tvalid_re => qr/^(?:quit|q|drop|d|edit|e)/i,\n \t\t\tdefault => 'q');\n \t\tif (/^d/i) {\n@@ -1291,17 +1295,22 @@ Message-Id: $message_id\n \t\tif ($needs_confirm eq \"inform\") {\n \t\t\t$confirm_unconfigured = 0; # squelch this message for the rest of this run\n \t\t\t$ask_default = \"y\"; # assume yes on EOF since user hasn't explicitly asked for confirmation\n-\t\t\tprint \"    The Cc list above has been expanded by additional\\n\";\n-\t\t\tprint \"    addresses found in the patch commit message. By default\\n\";\n-\t\t\tprint \"    send-email prompts before sending whenever this occurs.\\n\";\n-\t\t\tprint \"    This behavior is controlled by the sendemail.confirm\\n\";\n-\t\t\tprint \"    configuration setting.\\n\";\n-\t\t\tprint \"\\n\";\n-\t\t\tprint \"    For additional information, run 'git send-email --help'.\\n\";\n-\t\t\tprint \"    To retain the current behavior, but squelch this message,\\n\";\n-\t\t\tprint \"    run 'git config --global sendemail.confirm auto'.\\n\\n\";\n+\t\t\tprint __(\n+\"    The Cc list above has been expanded by additional\n+    addresses found in the patch commit message. By default\n+    send-email prompts before sending whenever this occurs.\n+    This behavior is controlled by the sendemail.confirm\n+    configuration setting.\n+\n+    For additional information, run 'git send-email --help'.\n+    To retain the current behavior, but squelch this message,\n+    run 'git config --global sendemail.confirm auto'.\"),\n+\"\\n\\n\";\n \t\t}\n-\t\t$_ = ask(\"Send this email? ([y]es|[n]o|[q]uit|[a]ll): \",\n+\t\t# TRANSLATORS: Make sure to include [y] [n] [q] [a] in your\n+\t\t# translation. The program will only accept English input\n+\t\t# at this point.\n+\t\t$_ = ask(__(\"Send this email? ([y]es|[n]o|[q]uit|[a]ll): \"),\n \t\t         valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i,\n \t\t         default => $ask_default);\n \t\tdie \"Send this email reply required\" unless defined $_;\n@@ -1403,7 +1412,7 @@ Message-Id: $message_id\n \tif ($quiet) {\n \t\tprintf (($dry_run ? \"Dry-\" : \"\").\"Sent %s\\n\", $subject);\n \t} else {\n-\t\tprint (($dry_run ? \"Dry-\" : \"\").\"OK. Log says:\\n\");\n+\t\tprint (($dry_run ? \"Dry-\" : \"\"). __(\"OK. Log says:\\n\"));\n \t\tif (!file_name_is_absolute($smtp_server)) {\n \t\t\tprint \"Server: $smtp_server\\n\";\n \t\t\tprint \"MAIL FROM:<$raw_from>\\n\";\n@@ -1478,13 +1487,13 @@ foreach my $t (@files) {\n \t\t\t\t$sauthor = sanitize_address($author);\n \t\t\t\tnext if $suppress_cc{'author'};\n \t\t\t\tnext if $suppress_cc{'self'} and $sauthor eq $sender;\n-\t\t\t\tprintf(\"(mbox) Adding cc: %s from line '%s'\\n\",\n+\t\t\t\tprintf(__(\"(mbox) Adding cc: %s from line '%s'\\n\"),\n \t\t\t\t\t$1, $_) unless $quiet;\n \t\t\t\tpush @cc, $1;\n \t\t\t}\n \t\t\telsif (/^To:\\s+(.*)$/i) {\n \t\t\t\tforeach my $addr (parse_address_line($1)) {\n-\t\t\t\t\tprintf(\"(mbox) Adding to: %s from line '%s'\\n\",\n+\t\t\t\t\tprintf(__(\"(mbox) Adding to: %s from line '%s'\\n\"),\n \t\t\t\t\t\t$addr, $_) unless $quiet;\n \t\t\t\t\tpush @to, $addr;\n \t\t\t\t}\n@@ -1498,7 +1507,7 @@ foreach my $t (@files) {\n \t\t\t\t\t} else {\n \t\t\t\t\t\tnext if ($suppress_cc{'cc'});\n \t\t\t\t\t}\n-\t\t\t\t\tprintf(\"(mbox) Adding cc: %s from line '%s'\\n\",\n+\t\t\t\t\tprintf(__(\"(mbox) Adding cc: %s from line '%s'\\n\"),\n \t\t\t\t\t\t$addr, $_) unless $quiet;\n \t\t\t\t\tpush @cc, $addr;\n \t\t\t\t}\n@@ -1532,7 +1541,7 @@ foreach my $t (@files) {\n \t\t\t# So let's support that, too.\n \t\t\t$input_format = 'lots';\n \t\t\tif (@cc == 0 && !$suppress_cc{'cc'}) {\n-\t\t\t\tprintf(\"(non-mbox) Adding cc: %s from line '%s'\\n\",\n+\t\t\t\tprintf(__(\"(non-mbox) Adding cc: %s from line '%s'\\n\"),\n \t\t\t\t\t$_, $_) unless $quiet;\n \t\t\t\tpush @cc, $_;\n \t\t\t} elsif (!defined $subject) {\n@@ -1555,7 +1564,7 @@ foreach my $t (@files) {\n \t\t\t\tnext if $suppress_cc{'bodycc'} and $what =~ /Cc/i;\n \t\t\t}\n \t\t\tpush @cc, $c;\n-\t\t\tprintf(\"(body) Adding cc: %s from line '%s'\\n\",\n+\t\t\tprintf(__(\"(body) Adding cc: %s from line '%s'\\n\"),\n \t\t\t\t$c, $_) unless $quiet;\n \t\t}\n \t}\n-- \n2.7.4\n\n"},{"id":"300685","messageId":"1472646690-9699-12-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 11/11] i18n: difftool: mark warnings for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:30Z","receivedAt":"2016-08-31T12:33:41Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-difftool.perl | 18 ++++++++++--------\n 1 file changed, 10 insertions(+), 8 deletions(-)\n\ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex ebd13ba..de8d783 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -22,6 +22,7 @@ use File::Path qw(mkpath rmtree);\n use File::Temp qw(tempdir);\n use Getopt::Long qw(:config pass_through);\n use Git;\n+use Git::I18N;\n \n sub usage\n {\n@@ -144,7 +145,7 @@ sub setup_dir_diff\n \tmy $i = 0;\n \twhile ($i < $#rawdiff) {\n \t\tif ($rawdiff[$i] =~ /^::/) {\n-\t\t\twarn << 'EOF';\n+\t\t\twarn __ <<'EOF';\n Combined diff formats ('-c' and '--cc') are not supported in\n directory diff mode ('-d' and '--dir-diff').\n EOF\n@@ -451,11 +452,11 @@ sub dir_diff\n \t\t}\n \n \t\tif (exists $wt_modified{$file} and exists $tmp_modified{$file}) {\n-\t\t\tmy $errmsg = \"warning: Both files modified: \";\n-\t\t\t$errmsg .= \"'$workdir/$file' and '$b/$file'.\\n\";\n-\t\t\t$errmsg .= \"warning: Working tree file has been left.\\n\";\n-\t\t\t$errmsg .= \"warning:\\n\";\n-\t\t\twarn $errmsg;\n+\t\t\twarn sprintf(__(\n+\t\t\t\t\"warning: Both files modified:\\n\" .\n+\t\t\t\t\"'%s/%s' and '%s/%s'.\\n\" .\n+\t\t\t\t\"warning: Working tree file has been left.\\n\" .\n+\t\t\t\t\"warning:\\n\"), $workdir, $file, $b, $file);\n \t\t\t$error = 1;\n \t\t} elsif (exists $tmp_modified{$file}) {\n \t\t\tmy $mode = stat(\"$b/$file\")->mode;\n@@ -467,8 +468,9 @@ sub dir_diff\n \t\t}\n \t}\n \tif ($error) {\n-\t\twarn \"warning: Temporary files exist in '$tmpdir'.\\n\";\n-\t\twarn \"warning: You may want to cleanup or recover these.\\n\";\n+\t\twarn sprintf(__(\n+\t\t\t\"warning: Temporary files exist in '%s'.\\n\" .\n+\t\t\t\"warning: You may want to cleanup or recover these.\\n\"), $tmpdir);\n \t\texit(1);\n \t} else {\n \t\texit_cleanup($tmpdir, $rc);\n-- \n2.7.4\n\n"},{"id":"300686","messageId":"1472646690-9699-10-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 09/11] i18n: send-email: mark warnings and errors for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:28Z","receivedAt":"2016-08-31T12:33:42Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark warnings, errors and other messages for translation.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-send-email.perl | 36 ++++++++++++++++++------------------\n 1 file changed, 18 insertions(+), 18 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 2521832..e7f712e 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -118,20 +118,20 @@ sub format_2822_time {\n \tmy $localmin = $localtm[1] + $localtm[2] * 60;\n \tmy $gmtmin = $gmttm[1] + $gmttm[2] * 60;\n \tif ($localtm[0] != $gmttm[0]) {\n-\t\tdie \"local zone differs from GMT by a non-minute interval\\n\";\n+\t\tdie __(\"local zone differs from GMT by a non-minute interval\\n\");\n \t}\n \tif ((($gmttm[6] + 1) % 7) == $localtm[6]) {\n \t\t$localmin += 1440;\n \t} elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {\n \t\t$localmin -= 1440;\n \t} elsif ($gmttm[6] != $localtm[6]) {\n-\t\tdie \"local time offset greater than or equal to 24 hours\\n\";\n+\t\tdie __(\"local time offset greater than or equal to 24 hours\\n\");\n \t}\n \tmy $offset = $localmin - $gmtmin;\n \tmy $offhour = $offset / 60;\n \tmy $offmin = abs($offset % 60);\n \tif (abs($offhour) >= 24) {\n-\t\tdie (\"local time offset greater than or equal to 24 hours\\n\");\n+\t\tdie __(\"local time offset greater than or equal to 24 hours\\n\");\n \t}\n \n \treturn sprintf(\"%s, %2d %s %d %02d:%02d:%02d %s%02d%02d\",\n@@ -199,13 +199,13 @@ sub do_edit {\n \t\tmap {\n \t\t\tsystem('sh', '-c', $editor.' \"$@\"', $editor, $_);\n \t\t\tif (($? & 127) || ($? >> 8)) {\n-\t\t\t\tdie(\"the editor exited uncleanly, aborting everything\");\n+\t\t\t\tdie(__(\"the editor exited uncleanly, aborting everything\"));\n \t\t\t}\n \t\t} @_;\n \t} else {\n \t\tsystem('sh', '-c', $editor.' \"$@\"', $editor, @_);\n \t\tif (($? & 127) || ($? >> 8)) {\n-\t\t\tdie(\"the editor exited uncleanly, aborting everything\");\n+\t\t\tdie(__(\"the editor exited uncleanly, aborting everything\"));\n \t\t}\n \t}\n }\n@@ -299,7 +299,7 @@ my $help;\n my $rc = GetOptions(\"h\" => \\$help,\n                     \"dump-aliases\" => \\$dump_aliases);\n usage() unless $rc;\n-die \"--dump-aliases incompatible with other options\\n\"\n+die __(\"--dump-aliases incompatible with other options\\n\")\n     if !$help and $dump_aliases and @ARGV;\n $rc = GetOptions(\n \t\t    \"sender|from=s\" => \\$sender,\n@@ -362,7 +362,7 @@ unless ($rc) {\n     usage();\n }\n \n-die \"Cannot run git format-patch from outside a repository\\n\"\n+die __(\"Cannot run git format-patch from outside a repository\\n\")\n \tif $format_patch and not $repo;\n \n # Now, let's fill any that aren't set in with defaults:\n@@ -617,7 +617,7 @@ while (defined(my $f = shift @ARGV)) {\n }\n \n if (@rev_list_opts) {\n-\tdie \"Cannot run git format-patch from outside a repository\\n\"\n+\tdie __(\"Cannot run git format-patch from outside a repository\\n\")\n \t\tunless $repo;\n \tpush @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);\n }\n@@ -636,7 +636,7 @@ if (@files) {\n \t\tprint $_,\"\\n\" for (@files);\n \t}\n } else {\n-\tprint STDERR \"\\nNo patch files specified!\\n\\n\";\n+\tprint STDERR __(\"\\nNo patch files specified!\\n\\n\");\n \tusage();\n }\n \n@@ -728,7 +728,7 @@ EOT\n \t\t\t$sender = $1;\n \t\t\tnext;\n \t\t} elsif (/^(?:To|Cc|Bcc):/i) {\n-\t\t\tprint \"To/Cc/Bcc fields are not interpreted yet, they have been ignored\\n\";\n+\t\t\tprint __(\"To/Cc/Bcc fields are not interpreted yet, they have been ignored\\n\");\n \t\t\tnext;\n \t\t}\n \t\tprint $c2 $_;\n@@ -737,7 +737,7 @@ EOT\n \tclose $c2;\n \n \tif ($summary_empty) {\n-\t\tprint \"Summary email is empty, skipping it\\n\";\n+\t\tprint __(\"Summary email is empty, skipping it\\n\");\n \t\t$compose = -1;\n \t}\n } elsif ($annotate) {\n@@ -1313,7 +1313,7 @@ Message-Id: $message_id\n \t\t$_ = ask(__(\"Send this email? ([y]es|[n]o|[q]uit|[a]ll): \"),\n \t\t         valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i,\n \t\t         default => $ask_default);\n-\t\tdie \"Send this email reply required\" unless defined $_;\n+\t\tdie __(\"Send this email reply required\") unless defined $_;\n \t\tif (/^n/i) {\n \t\t\treturn 0;\n \t\t} elsif (/^q/i) {\n@@ -1339,7 +1339,7 @@ Message-Id: $message_id\n \t} else {\n \n \t\tif (!defined $smtp_server) {\n-\t\t\tdie \"The required SMTP server is not properly defined.\"\n+\t\t\tdie __(\"The required SMTP server is not properly defined.\")\n \t\t}\n \n \t\tif ($smtp_encryption eq 'ssl') {\n@@ -1410,7 +1410,7 @@ Message-Id: $message_id\n \t\t$smtp->code =~ /250|200/ or die \"Failed to send $subject\\n\".$smtp->message;\n \t}\n \tif ($quiet) {\n-\t\tprintf (($dry_run ? \"Dry-\" : \"\").\"Sent %s\\n\", $subject);\n+\t\tprintf (($dry_run ? \"Dry-\" : \"\"). __(\"Sent %s\\n\"), $subject);\n \t} else {\n \t\tprint (($dry_run ? \"Dry-\" : \"\"). __(\"OK. Log says:\\n\"));\n \t\tif (!file_name_is_absolute($smtp_server)) {\n@@ -1424,10 +1424,10 @@ Message-Id: $message_id\n \t\t}\n \t\tprint $header, \"\\n\";\n \t\tif ($smtp) {\n-\t\t\tprint \"Result: \", $smtp->code, ' ',\n+\t\t\tprint __(\"Result: \"), $smtp->code, ' ',\n \t\t\t\t($smtp->message =~ /\\n([^\\n]+\\n)$/s), \"\\n\";\n \t\t} else {\n-\t\t\tprint \"Result: OK\\n\";\n+\t\t\tprint __(\"Result: OK\\n\");\n \t\t}\n \t}\n \n@@ -1700,7 +1700,7 @@ sub apply_transfer_encoding {\n \t$message = MIME::Base64::decode($message)\n \t\tif ($from eq 'base64');\n \n-\tdie \"cannot send message as 7bit\"\n+\tdie __(\"cannot send message as 7bit\")\n \t\tif ($to eq '7bit' and $message =~ /[^[:ascii:]]/);\n \treturn $message\n \t\tif ($to eq '7bit' or $to eq '8bit');\n@@ -1708,7 +1708,7 @@ sub apply_transfer_encoding {\n \t\tif ($to eq 'quoted-printable');\n \treturn MIME::Base64::encode($message, \"\\n\")\n \t\tif ($to eq 'base64');\n-\tdie \"invalid transfer encoding\";\n+\tdie __(\"invalid transfer encoding\");\n }\n \n sub unique_email_list {\n-- \n2.7.4\n\n"},{"id":"300687","messageId":"1472646690-9699-11-git-send-email-vascomalmeida@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2 10/11] i18n: send-email: mark string with interpolation for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-08-31T12:31:29Z","receivedAt":"2016-08-31T12:33:43Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Mark warnings, errors and other messages that are interpolated for\ntranslation.\n\nWe must call sprintf() before calling die() and in few other\ncircumstances in order to interpolation take place.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n git-send-email.perl | 71 ++++++++++++++++++++++++++++-------------------------\n 1 file changed, 38 insertions(+), 33 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex e7f712e..c29381b 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -279,10 +279,13 @@ sub signal_handler {\n \t# tmp files from --compose\n \tif (defined $compose_filename) {\n \t\tif (-e $compose_filename) {\n-\t\t\tprint \"'$compose_filename' contains an intermediate version of the email you were composing.\\n\";\n+\t\t\tprintf __(\"'%s' contains an intermediate version \".\n+\t\t\t\t  \"of the email you were composing.\\n\"),\n+\t\t\t\t  $compose_filename;\n \t\t}\n \t\tif (-e ($compose_filename . \".final\")) {\n-\t\t\tprint \"'$compose_filename.final' contains the composed email.\\n\"\n+\t\t\tprintf __(\"'%s.final' contains the composed email.\\n\"),\n+\t\t\t\t  $compose_filename;\n \t\t}\n \t}\n \n@@ -431,7 +434,7 @@ $smtp_encryption = '' unless (defined $smtp_encryption);\n my(%suppress_cc);\n if (@suppress_cc) {\n \tforeach my $entry (@suppress_cc) {\n-\t\tdie \"Unknown --suppress-cc field: '$entry'\\n\"\n+\t\tdie sprintf(__(\"Unknown --suppress-cc field: '%s'\\n\"), $entry)\n \t\t\tunless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc)$/;\n \t\t$suppress_cc{$entry} = 1;\n \t}\n@@ -460,7 +463,7 @@ my $confirm_unconfigured = !defined $confirm;\n if ($confirm_unconfigured) {\n \t$confirm = scalar %suppress_cc ? 'compose' : 'auto';\n };\n-die \"Unknown --confirm setting: '$confirm'\\n\"\n+die sprintf(__(\"Unknown --confirm setting: '%s'\\n\"), $confirm)\n \tunless $confirm =~ /^(?:auto|cc|compose|always|never)/;\n \n # Debugging, print out the suppressions.\n@@ -492,16 +495,16 @@ my %aliases;\n sub parse_sendmail_alias {\n \tlocal $_ = shift;\n \tif (/\"/) {\n-\t\tprint STDERR \"warning: sendmail alias with quotes is not supported: $_\\n\";\n+\t\tprintf STDERR __(\"warning: sendmail alias with quotes is not supported: %s\\n\"), $_;\n \t} elsif (/:include:/) {\n-\t\tprint STDERR \"warning: `:include:` not supported: $_\\n\";\n+\t\tprintf STDERR __(\"warning: `:include:` not supported: %s\\n\"), $_;\n \t} elsif (/[\\/|]/) {\n-\t\tprint STDERR \"warning: `/file` or `|pipe` redirection not supported: $_\\n\";\n+\t\tprintf STDERR __(\"warning: `/file` or `|pipe` redirection not supported: %s\\n\"), $_;\n \t} elsif (/^(\\S+?)\\s*:\\s*(.+)$/) {\n \t\tmy ($alias, $addr) = ($1, $2);\n \t\t$aliases{$alias} = [ split_addrs($addr) ];\n \t} else {\n-\t\tprint STDERR \"warning: sendmail line is not recognized: $_\\n\";\n+\t\tprintf STDERR __(\"warning: sendmail line is not recognized: %s\\n\"), $_;\n \t}\n }\n \n@@ -582,13 +585,12 @@ sub is_format_patch_arg {\n \t\tif (defined($format_patch)) {\n \t\t\treturn $format_patch;\n \t\t}\n-\t\tdie(<<EOF);\n-File '$f' exists but it could also be the range of commits\n+\t\tdie sprintf(__(\n+\"File '%s' exists but it could also be the range of commits\n to produce patches for.  Please disambiguate by...\n \n-    * Saying \"./$f\" if you mean a file; or\n-    * Giving --format-patch option if you mean a range.\n-EOF\n+    * Saying \\\"./%s\\\" if you mean a file; or\n+    * Giving --format-patch option if you mean a range.\"), $f, $f);\n \t} catch Git::Error::Command with {\n \t\t# Not a valid revision.  Treat it as a filename.\n \t\treturn 0;\n@@ -604,7 +606,7 @@ while (defined(my $f = shift @ARGV)) {\n \t\t@ARGV = ();\n \t} elsif (-d $f and !is_format_patch_arg($f)) {\n \t\topendir my $dh, $f\n-\t\t\tor die \"Failed to opendir $f: $!\";\n+\t\t\tor die sprintf(__(\"Failed to opendir %s: %s\"), $f, $!);\n \n \t\tpush @files, grep { -f $_ } map { catfile($f, $_) }\n \t\t\t\tsort readdir $dh;\n@@ -626,7 +628,8 @@ if ($validate) {\n \tforeach my $f (@files) {\n \t\tunless (-p $f) {\n \t\t\tmy $error = validate_patch($f);\n-\t\t\t$error and die \"fatal: $f: $error\\nwarning: no patches were sent\\n\";\n+\t\t\t$error and die sprintf(__(\"fatal: %s: %s\\nwarning: no patches were sent\\n\"),\n+\t\t\t\t\t\t  $f, $error);\n \t\t}\n \t}\n }\n@@ -649,7 +652,7 @@ sub get_patch_subject {\n \t\treturn \"GIT: $1\\n\";\n \t}\n \tclose $fh;\n-\tdie \"No subject line in $fn ?\";\n+\tdie sprintf(__(\"No subject line in %s ?\"), $fn);\n }\n \n if ($compose) {\n@@ -659,7 +662,7 @@ if ($compose) {\n \t\ttempfile(\".gitsendemail.msg.XXXXXX\", DIR => $repo->repo_path()) :\n \t\ttempfile(\".gitsendemail.msg.XXXXXX\", DIR => \".\"))[1];\n \topen my $c, \">\", $compose_filename\n-\t\tor die \"Failed to open for writing $compose_filename: $!\";\n+\t\tor die sprintf(__(\"Failed to open for writing %s: %s\"), $compose_filename, $!);\n \n \n \tmy $tpl_sender = $sender || $repoauthor || $repocommitter || '';\n@@ -690,10 +693,10 @@ EOT\n \t}\n \n \topen my $c2, \">\", $compose_filename . \".final\"\n-\t\tor die \"Failed to open $compose_filename.final : \" . $!;\n+\t\tor die sprintf(__(\"Failed to open %s.final : %s\"), $compose_filename, $!);\n \n \topen $c, \"<\", $compose_filename\n-\t\tor die \"Failed to open $compose_filename : \" . $!;\n+\t\tor die sprintf(__(\"Failed to open %s : %s\"), $compose_filename, $!);\n \n \tmy $need_8bit_cte = file_has_nonascii($compose_filename);\n \tmy $in_body = 0;\n@@ -767,7 +770,9 @@ sub ask {\n \t\t\treturn $resp;\n \t\t}\n \t\tif ($confirm_only) {\n-\t\t\tmy $yesno = $term->readline(\"Are you sure you want to use <$resp> [y/N]? \");\n+\t\t\t# TRANSLATORS: Keep [y/N] as is.\n+\t\t\tmy $yesno = $term->readline(\n+\t\t\t\tsprintf(__(\"Are you sure you want to use <%s> [y/N]? \"), $resp));\n \t\t\tif (defined $yesno && $yesno =~ /y/i) {\n \t\t\t\treturn $resp;\n \t\t\t}\n@@ -846,7 +851,7 @@ my %EXPANDED_ALIASES;\n sub expand_one_alias {\n \tmy $alias = shift;\n \tif ($EXPANDED_ALIASES{$alias}) {\n-\t\tdie \"fatal: alias '$alias' expands to itself\\n\";\n+\t\tdie sprintf(__(\"fatal: alias '%s' expands to itself\\n\"), $alias);\n \t}\n \tlocal $EXPANDED_ALIASES{$alias} = 1;\n \treturn $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;\n@@ -908,7 +913,7 @@ sub extract_valid_address {\n sub extract_valid_address_or_die {\n \tmy $address = shift;\n \t$address = extract_valid_address($address);\n-\tdie \"error: unable to extract a valid address from: $address\\n\"\n+\tdie sprintf(__(\"error: unable to extract a valid address from: %s\\n\"), $address)\n \t\tif !$address;\n \treturn $address;\n }\n@@ -916,7 +921,7 @@ sub extract_valid_address_or_die {\n sub validate_address {\n \tmy $address = shift;\n \twhile (!extract_valid_address($address)) {\n-\t\tprint STDERR \"error: unable to extract a valid address from: $address\\n\";\n+\t\tprintf STDERR __(\"error: unable to extract a valid address from: %s\\n\"), $address;\n \t\t# TRANSLATORS: Make sure to include [q] [d] [e] in your\n \t\t# translation. The program will only accept English input\n \t\t# at this point.\n@@ -1221,7 +1226,7 @@ sub ssl_verify_params {\n \t\treturn (SSL_verify_mode => SSL_VERIFY_PEER(),\n \t\t\tSSL_ca_file => $smtp_ssl_cert_path);\n \t} else {\n-\t\tdie \"CA path \\\"$smtp_ssl_cert_path\\\" does not exist\";\n+\t\tdie sprintf(__(\"CA path \\\"%s\\\" does not exist\"), $smtp_ssl_cert_path);\n \t}\n }\n \n@@ -1383,7 +1388,7 @@ Message-Id: $message_id\n \t\t\t\t\t# supported commands\n \t\t\t\t\t$smtp->hello($smtp_domain);\n \t\t\t\t} else {\n-\t\t\t\t\tdie \"Server does not support STARTTLS! \".$smtp->message;\n+\t\t\t\t\tdie sprintf(__(\"Server does not support STARTTLS! %s\"), $smtp->message);\n \t\t\t\t}\n \t\t\t}\n \t\t}\n@@ -1440,7 +1445,7 @@ $subject = $initial_subject;\n $message_num = 0;\n \n foreach my $t (@files) {\n-\topen my $fh, \"<\", $t or die \"can't open file $t\";\n+\topen my $fh, \"<\", $t or die sprintf(__(\"can't open file %s\"), $t);\n \n \tmy $author = undef;\n \tmy $sauthor = undef;\n@@ -1669,11 +1674,11 @@ sub recipients_cmd {\n \t\t$address = sanitize_address($address);\n \t\tnext if ($address eq $sender and $suppress_cc{'self'});\n \t\tpush @addresses, $address;\n-\t\tprintf(\"($prefix) Adding %s: %s from: '%s'\\n\",\n-\t\t       $what, $address, $cmd) unless $quiet;\n+\t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n+\t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n \tclose $fh\n-\t    or die \"($prefix) failed to close pipe to '$cmd'\";\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n@@ -1727,10 +1732,10 @@ sub unique_email_list {\n sub validate_patch {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die \"unable to open $fn: $!\\n\";\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\tif (length($line) > 998) {\n-\t\t\treturn \"$.: patch contains a line longer than 998 characters\";\n+\t\t\treturn sprintf(__(\"%s: patch contains a line longer than 998 characters\"), $.);\n \t\t}\n \t}\n \treturn;\n@@ -1739,7 +1744,7 @@ sub validate_patch {\n sub file_has_nonascii {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die \"unable to open $fn: $!\\n\";\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\treturn 1 if $line =~ /[^[:ascii:]]/;\n \t}\n@@ -1749,7 +1754,7 @@ sub file_has_nonascii {\n sub body_or_subject_has_nonascii {\n \tmy $fn = shift;\n \topen(my $fh, '<', $fn)\n-\t\tor die \"unable to open $fn: $!\\n\";\n+\t\tor die sprintf(__(\"unable to open %s: %s\\n\"), $fn, $!);\n \twhile (my $line = <$fh>) {\n \t\tlast if $line =~ /^$/;\n \t\treturn 1 if $line =~ /^Subject.*[^[:ascii:]]/;\n-- \n2.7.4\n\n"},{"id":"300700","messageId":"xmqqtwe026p9.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-1-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 00/11] Mark strings in perl script for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T17:23:30Z","receivedAt":"2016-08-31T17:23:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> Mark messages in some perl scripts for translation.\n>\n> Since v1, adds brackets so parameter grouping of sprintf parameters is easier\n> to see.\n>\n> Interdiff included below.\n\nThanks; it is way too late for this cycle for i18n so I won't be\npicking the series up right now.  Please ping me if you see me\nforget to pick it up in a week after 2.10 final gets tagged.\n"},{"id":"302537","messageId":"xmqqr387y4le.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-2-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T22:52:45Z","receivedAt":"2016-09-25T22:52:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> Mark simple strings (without interpolation) for translation.\n>\n> Brackets around first parameter of ternary operator is necessary because\n> otherwise xgettext fails to extract strings marked for translation from\n> the rest of the file.\n>\n> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  git-add--interactive.perl | 68 +++++++++++++++++++++++++----------------------\n>  1 file changed, 36 insertions(+), 32 deletions(-)\n>\n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index 822f857..fb8e5de 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -4,6 +4,7 @@ use 5.008;\n>  use strict;\n>  use warnings;\n>  use Git;\n> +use Git::I18N;\n>  \n>  binmode(STDOUT, \":raw\");\n>  \n> @@ -252,7 +253,7 @@ sub list_untracked {\n>  }\n>  \n>  my $status_fmt = '%12s %12s %s';\n> -my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n> +my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));\n\nWouldn't it make sense to allow translators to tweak $status_fmt if\nyou are allowing the earlier elements that are formatted with %12s,\nas their translation may not fit within that width, in which case\nthey may want to make these columns wider?\n\n>  \t\t\tprompt_yesno(\n> -\t\t\t\t'Your edited hunk does not apply. Edit again '\n> -\t\t\t\t. '(saying \"no\" discards!) [y/n]? '\n> +\t\t\t\t# TRANSLATORS: do not translate [y/n]\n> +\t\t\t\t# The program will only accept that input\n> +\t\t\t\t# at this point.\n> +\t\t\t\t__('Your edited hunk does not apply. Edit again '\n> +\t\t\t\t   . '(saying \"no\" discards!) [y/n]? ')\n\nNot just [y/n], but \"no\" in \"saying no discards!\" also needs to\nstay, no?  I wonder if it is a good idea to lose the TRANSLATORS\ncomment by ejecting \"[y/n]\" outside the \"__()\" construct here.\n"},{"id":"302538","messageId":"xmqqmvivy4i9.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-3-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T22:54:38Z","receivedAt":"2016-09-25T22:54:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> -Prompt help:\n> +\tprint colored $help_color, __(\n> +\"Prompt help:\n>  1          - select a numbered item\n>  foo        - select item based on unique prefix\n> -           - (empty) select nothing\n> -EOF\n> +           - (empty) select nothing\"),\n> +\"\\n\";\n>  }\n>  \n>  sub prompt_help_cmd {\n> -\tprint colored $help_color, <<\\EOF ;\n> -Prompt help:\n> +\tprint colored $help_color, __(\n> +\"Prompt help:\n>  1          - select a single item\n>  3-5        - select a range of items\n>  2-3,6-9    - select multiple ranges\n>  foo        - select item based on unique prefix\n>  -...       - unselect specified items\n>  *          - choose all items\n> -           - (empty) finish selecting\n> -EOF\n> +           - (empty) finish selecting\"),\n> +\"\\n\";\n>  }\n>  \n>  sub status_cmd {\n> @@ -1573,14 +1573,14 @@ sub quit_cmd {\n>  }\n>  \n>  sub help_cmd {\n> -\tprint colored $help_color, <<\\EOF ;\n> -status        - show paths with changes\n> +\tprint colored $help_color, __(\n> +\"status        - show paths with changes\n>  update        - add working tree state to the staged set of changes\n>  revert        - revert staged set of changes back to the HEAD version\n>  patch         - pick hunks and update selectively\n>  diff\t      - view diff between HEAD and index\n> -add untracked - add contents of untracked files to the staged set of changes\n> -EOF\n> +add untracked - add contents of untracked files to the staged set of changes\"),\n> +\"\\n\";\n>  }\n\nDo we need TRANSLATORS: comment to all of the above not to touch the\ncommand words that are explained and translate only the explanation?\n"},{"id":"302539","messageId":"xmqqintjy4ct.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-4-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 03/11] i18n: add--interactive: mark strings with interpolation for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T22:57:54Z","receivedAt":"2016-09-25T22:58:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> @@ -1048,7 +1048,7 @@ sub edit_hunk_manually {\n>  \tmy $hunkfile = $repo->repo_path . \"/addp-hunk-edit.diff\";\n>  \tmy $fh;\n>  \topen $fh, '>', $hunkfile\n> -\t\tor die \"failed to open hunk edit file for writing: \" . $!;\n> +\t\tor die sprintf(__(\"failed to open hunk edit file for writing: %s\"), $!);\n\nOK, $! presumably is given in the user's language, so we let\ntranslators prepare the error-specific text and interpolate $! into\nit.\n\nMakes sense.\n"},{"id":"302540","messageId":"xmqqbmzby3tc.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-6-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 05/11] i18n: add--interactive: mark message for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:09:35Z","receivedAt":"2016-09-25T23:09:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> -\t\tprint colored $prompt_color, $patch_mode_flavour{VERB},\n> -\t\t  ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' :\n> -\t\t   $hunk[$ix]{TYPE} eq 'deletion' ? ' deletion' :\n> -\t\t   ' this hunk'),\n> -\t\t  $patch_mode_flavour{TARGET},\n> -\t\t  \" [y,n,q,a,d,/$other,?]? \";\n\nI hate to say this but expanding this single-liner into if/elsif/\ncascade of uncountable number of arms is simply a disaster.\n\n> +\t\tif ($patch_mode eq 'stage') {\n> +\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n> +\t\t\t  print colored $prompt_color,\n> +\t\t\t    sprintf(__(\"Stage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n> +\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n> +\t\t\t  print colored $prompt_color,\n> +\t\t\t    sprintf(__(\"Stage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n> +\t\t\t} else {\n> +\t\t\t  print colored $prompt_color,\n> +\t\t\t    sprintf(__(\"Stage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n> +\t\t\t}\n> +\t\t} elsif ($patch_mode eq 'stash') {\n> + ...\n> +\t\t\t}\n> +\t\t}\n\nI wonder if you can make a simple helper function so that the caller\nhere can still be a single-liner:\n\n\tprint_colored $prompt_color,\n             sprintf(patch_update_prompt_string($patch_mode, $hunk[$ix]{TYPE}), $other);\n \nwhere the patch_update_prompt_string helper function would look up\nthese messages from a table that is looked up by patch-mode and TYPE\nand the run __() on it, or something?\n"},{"id":"302541","messageId":"xmqq7f9zy3ps.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-7-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 06/11] i18n: add--interactive: i18n of help_patch_cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:11:43Z","receivedAt":"2016-09-25T23:12:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n>  sub help_patch_cmd {\n> -\tmy $verb = lc $patch_mode_flavour{VERB};\n> -\tmy $target = $patch_mode_flavour{TARGET};\n> -\tprint colored $help_color, <<EOF ;\n> -y - $verb this hunk$target\n> -n - do not $verb this hunk$target\n> -q - quit; do not $verb this hunk or any of the remaining ones\n> -a - $verb this hunk and all later hunks in the file\n> -d - do not $verb this hunk or any of the later hunks in the file\n> -g - select a hunk to go to\n> +\tif ($patch_mode eq 'stage') {\n> +\t\tprint colored $help_color, __(\n> +\"y - stage this hunk\n> +n - do not stage this hunk\n> +q - quit; do not stage this hunk or any of the remaining ones\n> +a - stage this hunk and all later hunks in the file\n> +d - do not stage this hunk or any of the later hunks in the file\");\n> +\t} elsif ($patch_mode eq 'stash') {\n> + ...\n> +\"\\n\";\n>  }\n\nThe same \"shouldn't this be done with a table not code?\" comment\napplies to this as well, though this is not as bad as the previous\none.\n"},{"id":"302542","messageId":"xmqq37kny3kh.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-9-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 08/11] i18n: send-email: mark strings for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:14:54Z","receivedAt":"2016-09-25T23:15:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> -\t\t$_ = ask(\"What to do with this address? ([q]uit|[d]rop|[e]dit): \",\n> +\t\t# TRANSLATORS: Make sure to include [q] [d] [e] in your\n> +\t\t# translation. The program will only accept English input\n> +\t\t# at this point.\n> +\t\t$_ = ask(__(\"What to do with this address? ([q]uit|[d]rop|[e]dit): \"),\n>  \t\t\tvalid_re => qr/^(?:quit|q|drop|d|edit|e)/i,\n>  \t\t\tdefault => 'q');\n> ...\n> -\t\t$_ = ask(\"Send this email? ([y]es|[n]o|[q]uit|[a]ll): \",\n> +\t\t# TRANSLATORS: Make sure to include [y] [n] [q] [a] in your\n> +\t\t# translation. The program will only accept English input\n> +\t\t# at this point.\n> +\t\t$_ = ask(__(\"Send this email? ([y]es|[n]o|[q]uit|[a]ll): \"),\n>  \t\t         valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i,\n>  \t\t         default => $ask_default);\n\nThe same comment as the one for the prompt in \"add -i\" applies\nhere.  If something should not be translated, perhaps we are better\noff pushing it outside __(), no?\n"},{"id":"302543","messageId":"xmqqy42fwotm.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-9-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 08/11] i18n: send-email: mark strings for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:18:45Z","receivedAt":"2016-09-25T23:18:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> @@ -1403,7 +1412,7 @@ Message-Id: $message_id\n>  \tif ($quiet) {\n>  \t\tprintf (($dry_run ? \"Dry-\" : \"\").\"Sent %s\\n\", $subject);\n>  \t} else {\n> -\t\tprint (($dry_run ? \"Dry-\" : \"\").\"OK. Log says:\\n\");\n> +\t\tprint (($dry_run ? \"Dry-\" : \"\"). __(\"OK. Log says:\\n\"));\n\nI am not sure about this change.  We either say Dry-Sent/Dry-OK\n(under --dry-run) or \"Sent/OK\"; don't you want \"dry-\" part also\ntranslated?\n"},{"id":"302544","messageId":"xmqqtwd3wooa.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1472646690-9699-12-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 11/11] i18n: difftool: mark warnings for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:21:57Z","receivedAt":"2016-09-25T23:22:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> -\t\t\twarn << 'EOF';\n> +\t\t\twarn __ <<'EOF';\n>  Combined diff formats ('-c' and '--cc') are not supported in\n>  directory diff mode ('-d' and '--dir-diff').\n>  EOF\n\nWow, didn't imagine gettext would pick this up.  Nice.\n\n"},{"id":"302545","messageId":"xmqqponrwo94.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"xmqqtwe026p9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 00/11] Mark strings in perl script for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-25T23:31:03Z","receivedAt":"2016-09-25T23:31:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n>\n>> Mark messages in some perl scripts for translation.\n>>\n>> Since v1, adds brackets so parameter grouping of sprintf parameters is easier\n>> to see.\n>>\n>> Interdiff included below.\n>\n> Thanks; it is way too late for this cycle for i18n so I won't be\n> picking the series up right now.  Please ping me if you see me\n> forget to pick it up in a week after 2.10 final gets tagged.\n\nI'll queue this round on 'pu' (if there aren't too heavy conflicts,\nthat is) and let the interested parties continue reviewing and\ndiscussing.\n\nThanks.\n"},{"id":"302608","messageId":"1474913721.1035.9.camel@sapo.pt","threadId":"43967","inReplyTo":"1472646690-9699-5-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 04/11] i18n: add--interactive: mark plural strings","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-09-26T18:15:21Z","receivedAt":"2016-09-26T18:15:32Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Qua, 31-08-2016 às 12:31 +0000, Vasco Almeida escreveu:\n> Mark plural strings for translation.  Unfold each action case in one\n> entire sentence.\n> \n> Pass new keyword for xgettext to extract.\n> \n> Update test to include new subrotine Q__() for plural strings handling.\n> \n> > Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  Makefile                  |  3 ++-\n>  git-add--interactive.perl | 24 ++++++++++++++++--------\n>  perl/Git/I18N.pm          |  4 +++-\n>  t/t0202/test.pl           | 11 ++++++++++-\n>  4 files changed, 31 insertions(+), 11 deletions(-)\n> \n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index 4e1e857..08badfa 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -666,12 +666,18 @@ sub status_cmd {\n>  sub say_n_paths {\n> >  \tmy $did = shift @_;\n> >  \tmy $cnt = scalar @_;\n> > -\tprint \"$did \";\n> > -\tif (1 < $cnt) {\n> > -\t\tprint \"$cnt paths\\n\";\n> > -\t}\n> > -\telse {\n> > -\t\tprint \"one path\\n\";\n> > +\tif ($did eq 'added') {\n> > +\t\tprintf(Q__(\"added one path\\n\", \"added %d paths\\n\",\n> > +\t\t\t   $cnt), $cnt);\n> > +\t} elsif ($did eq 'updated') {\n> > +\t\tprintf(Q__(\"updated one path\\n\", \"updated %d paths\\n\",\n> > +\t\t\t   $cnt), $cnt);\n> > +\t} elsif ($did eq 'reversed') {\n> > +\t\tprintf(Q__(\"reversed one path\\n\", \"reversed %d paths\\n\",\n\nThis should be 'reverted' not 'reversed'.\n\n> > +\t\t\t   $cnt), $cnt);\n> > +\t} else {\n> > +\t\tprintf(Q__(\"touched one path\\n\", \"touched %d paths\\n\",\n> > +\t\t\t   $cnt), $cnt);\n> >  \t}\n>  }\n\nWhen $cnt is 1 I get the following warning:\nRedundant argument in printf at /home/vasco/dev/local/libexec/git-core/git-add--interactive line 680.\n\nThe singular form does not have a %d to consume $cnt argument to\nprintf(). Either we find a way to suppress that warning or we change\nthe singular form to contain %d.\n\n> @@ -1508,8 +1514,10 @@ sub patch_update_file {\n> ...\n> > -\t\t\t\t\tprint colored $header_color, \"Split into \",\n> > -\t\t\t\t\tscalar(@split), \" hunks.\\n\";\n> > +\t\t\t\t\tprint colored $header_color, sprintf(\n> > +\t\t\t\t\t\tQ__(\"Split into %d hunk.\\n\",\n> > +\t\t\t\t\t\t    \"Split into %d hunks.\\n\",\n> > +\t\t\t\t\t\t    scalar(@split)), scalar(@split));\nLike we do with this.\n> > \n> > \n"},{"id":"302610","messageId":"xmqqlgyesesm.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1474913721.1035.9.camel@sapo.pt","subject":"Re: [PATCH v2 04/11] i18n: add--interactive: mark plural strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-26T18:21:13Z","receivedAt":"2016-09-26T18:21:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n>> > +\t} elsif ($did eq 'reversed') {\n>> > +\t\tprintf(Q__(\"reversed one path\\n\", \"reversed %d paths\\n\",\n>\n> This should be 'reverted' not 'reversed'.\n\nI'll mark v2 of this topic \"not to be merged yet\"; please send in a\ncorrected version 3 after you collect feedbacks from others and\nadjusted the patches for them.\n\nThanks.\n"},{"id":"302807","messageId":"1475066620.3257.12.camel@sapo.pt","threadId":"43967","inReplyTo":"xmqqr387y4le.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-09-28T12:43:40Z","receivedAt":"2016-09-28T12:44:02Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Dom, 25-09-2016 às 15:52 -0700, Junio C Hamano escreveu:\n> > @@ -252,7 +253,7 @@ sub list_untracked {\n> >  }\n> >  \n> >  my $status_fmt = '%12s %12s %s';\n> > -my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n> > +my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));\n> \n> Wouldn't it make sense to allow translators to tweak $status_fmt if\n> you are allowing the earlier elements that are formatted with %12s,\n> as their translation may not fit within that width, in which case\n> they may want to make these columns wider?\n\nAs far as I understand, %12s means that the argument printed will have\na minimum length of 12 columns. So if the translation of 'stage' is\nlonger than 12 it will be printed fully no matter what. Though in that\ncase, the header will not be align correctly anymore:\n\nmy $status_fmt = '%12s %12s %s';\n\n     123456789abcdefghijkl     unstaged caminho\n  1:    unchanged        +1/-0 git-add--interactive.perl\n  2:    unchanged  +4226/-3152 po/git.pot\n  3:    unchanged +11542/-10426 po/pt_PT.po\n\n\nmy $status_fmt = '%12s %8s %s';\n\n     123456789abcdefghijkl unstaged caminho\n  1:    unchanged    +2/-1 git-add--interactive.perl\n  2:    unchanged +4226/-3152 po/git.pot\n  3:    unchanged +11542/-10426 po/pt_PT.po\n\n\nFor reference in C locale (my $status_fmt = '%12s %12s %s';)\n\n           staged     unstaged path\n  1:        +4/-4      nothing git-add--interactive.perl\n  2:    unchanged  +4232/-3150 po/git.pot\n  3:    unchanged +11572/-10448 po/pt_PT.po\n\nI did not contemplate this issue before, but I think allowing a\ntranslator to tweak $status_fmt would not be enough to properly align\nthe header if the translation is longer than 12 columns.\n\nMaybe a lazy solution would be to add a TRANSLATOR: comment asking to\nfit the translation of those words in 12 columns, but that would be\nunpractical because 'stage' and 'unstage' can occur alone, like they do\nhere, in other place in the future, without having that length\nrestriction.\n\nI think the real fix would be to find the longer column and use that\nlength for the remaining rows. I will try to do that if I can.\n\n\nI also forgot to mark strings 'unchanged' and 'nothing' that are\ndisplayed on that status. I will mark then in the next re-roll.\n\n> >                       prompt_yesno(\n> > -                             'Your edited hunk does not apply. Edit again '\n> > -                             . '(saying \"no\" discards!) [y/n]? '\n> > +                             # TRANSLATORS: do not translate [y/n]\n> > +                             # The program will only accept that input\n> > +                             # at this point.\n> > +                             __('Your edited hunk does not apply. Edit again '\n> > +                                . '(saying \"no\" discards!) [y/n]? ')\n> \n> Not just [y/n], but \"no\" in \"saying no discards!\" also needs to\n> stay, no?  I wonder if it is a good idea to lose the TRANSLATORS\n> comment by ejecting \"[y/n]\" outside the \"__()\" construct here.\n\nI fear that ejecting \"[y/n]\" would not be good for right-to-left\nlanguages since \"[y/n]\" would be the first thing a user of those\nlanguages would read followed by the actual question. I feel the same\nfor other instances of this in the present patch series.\n"},{"id":"302809","messageId":"CACsJy8BUaJ8sRw2EtgrTe0X4khCsuKFD75ON12oC1FvqdMXr=g@mail.gmail.com","threadId":"43967","inReplyTo":"1475066620.3257.12.camel@sapo.pt","subject":"Re: [PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-09-28T14:29:47Z","receivedAt":"2016-09-28T14:30:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Sep 28, 2016 at 7:43 PM, Vasco Almeida <vascomalmeida@sapo.pt> wrote:\n> A Dom, 25-09-2016 às 15:52 -0700, Junio C Hamano escreveu:\n>> > @@ -252,7 +253,7 @@ sub list_untracked {\n>> >  }\n>> >\n>> >  my $status_fmt = '%12s %12s %s';\n>> > -my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n>> > +my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));\n>>\n>> Wouldn't it make sense to allow translators to tweak $status_fmt if\n>> you are allowing the earlier elements that are formatted with %12s,\n>> as their translation may not fit within that width, in which case\n>> they may want to make these columns wider?\n>\n> As far as I understand, %12s means that the argument printed will have\n> a minimum length of 12 columns. So if the translation of 'stage' is\n> longer than 12 it will be printed fully no matter what. Though in that\n> case, the header will not be align correctly anymore:\n> for other instances of this in the present patch series.\n\nIt's 12 bytes, not columns (unless perl understands input string's\nencoding, which I doubt). Think about multi-byte encodings like utf-8,\nwhere three letters (or \"columns\") do not necessary mean three bytes.\nThe result is most likely unaligned in that case.\n-- \nDuy\n"},{"id":"302812","messageId":"xmqq4m50klk2.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1475066620.3257.12.camel@sapo.pt","subject":"Re: [PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-28T16:59:09Z","receivedAt":"2016-09-28T16:59:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> As far as I understand, %12s means that the argument printed will have\n> a minimum length of 12 columns. So if the translation of 'stage' is\n> longer than 12 it will be printed fully no matter what. Though in that\n> case, the header will not be align correctly anymore:\n\nExactly.  That was where my suggestion comes from.  In such a case\nyou may want to raise these numbers so that the fixed part\n(i.e. header that you are letting the translators insert their\nversion of these words) would fit.\n\nAs Duy points out in his response to your message, that widening\nfurther needs to take into account how many display columns each\ntranslated words and phrases occupies, not just its byte length.\n"},{"id":"302887","messageId":"1475159493.2435.7.camel@sapo.pt","threadId":"43967","inReplyTo":"xmqqmvivy4i9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-09-29T14:31:33Z","receivedAt":"2016-09-29T14:32:07Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Dom, 25-09-2016 às 15:54 -0700, Junio C Hamano escreveu:\n> >  sub status_cmd {\n> > @@ -1573,14 +1573,14 @@ sub quit_cmd {\n> >  }\n> >  \n> >  sub help_cmd {\n> > -     print colored $help_color, <<\\EOF ;\n> > -status        - show paths with changes\n> > +     print colored $help_color, __(\n> > +\"status        - show paths with changes\n> >  update        - add working tree state to the staged set of\n> changes\n> >  revert        - revert staged set of changes back to the HEAD\n> version\n> >  patch         - pick hunks and update selectively\n> >  diff       - view diff between HEAD and index\n> > -add untracked - add contents of untracked files to the staged set\n> of changes\n> > -EOF\n> > +add untracked - add contents of untracked files to the staged set\n> of changes\"),\n> > +\"\\n\";\n> >  }\n> \n> Do we need TRANSLATORS: comment to all of the above not to touch the\n> command words that are explained and translate only the explanation?\n\nYes, it is better to have that comment.\n\nOn the other hand, would it make sense to translate these commands? If\nso, we would mark for translation the commands name of @cmd in\nmain_loop().\n\n sub main_loop {\n-       my @cmd = ([ 'status', \\&status_cmd, ],\n-                  [ 'update', \\&update_cmd, ],\n-                  [ 'revert', \\&revert_cmd, ],\n-                  [ 'add untracked', \\&add_untracked_cmd, ],\n-                  [ 'patch', \\&patch_update_cmd, ],\n-                  [ 'diff', \\&diff_cmd, ],\n-                  [ 'quit', \\&quit_cmd, ],\n-                  [ 'help', \\&help_cmd, ],\n+       my @cmd = ([ __('status'), \\&status_cmd, ],\n+                  [ __('update'), \\&update_cmd, ],\n+                  [ __('revert'), \\&revert_cmd, ],\n+                  [ __('add untracked'), \\&add_untracked_cmd, ],\n+                  [ __('patch'), \\&patch_update_cmd, ],\n+                  [ __('diff'), \\&diff_cmd, ],\n+                  [ __('quit'), \\&quit_cmd, ],\n+                  [ __('help'), \\&help_cmd, ],\n"},{"id":"302894","messageId":"xmqqfuoihc1m.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"1475159493.2435.7.camel@sapo.pt","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-29T17:05:09Z","receivedAt":"2016-09-29T17:05:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> On the other hand, would it make sense to translate these commands? If\n> so, we would mark for translation the commands name of @cmd in\n> main_loop().\n>\n>  sub main_loop {\n> -       my @cmd = ([ 'status', \\&status_cmd, ],\n> -                  [ 'update', \\&update_cmd, ],\n> -                  [ 'revert', \\&revert_cmd, ],\n> -                  [ 'add untracked', \\&add_untracked_cmd, ],\n> -                  [ 'patch', \\&patch_update_cmd, ],\n> -                  [ 'diff', \\&diff_cmd, ],\n> -                  [ 'quit', \\&quit_cmd, ],\n> -                  [ 'help', \\&help_cmd, ],\n> +       my @cmd = ([ __('status'), \\&status_cmd, ],\n> +                  [ __('update'), \\&update_cmd, ],\n> +                  [ __('revert'), \\&revert_cmd, ],\n> +                  [ __('add untracked'), \\&add_untracked_cmd, ],\n> +                  [ __('patch'), \\&patch_update_cmd, ],\n> +                  [ __('diff'), \\&diff_cmd, ],\n> +                  [ __('quit'), \\&quit_cmd, ],\n> +                  [ __('help'), \\&help_cmd, ],\n\nI don't know offhand.  If the code to prompt and accept the command\ngiven by the user can take the translated word (or a prefix of it),\ntheoretically I would say it could be made to work, but to me it is\ndubious the benefit outweighs its downsides.  It would make teaching\nGit and troubleshooting over the phone harder, I would guess.\n\n A: \"Hi, I am in a 'git add -i' session.\"\n B: \"Give 's' at the prompt.\"\n A: \"My Git does not seem to take 's' as a valid command.\"\n B: \"What? I've never seen that problem.\"\n ... back and forth wastes 10 minutes ...\n A: \"By the way, I am running Git in Portuguese.\"\n\n;-)\n"},{"id":"302948","messageId":"906445d8-25df-1b9a-8656-631ce007fc39@gmail.com","threadId":"43967","inReplyTo":"xmqqr387y4le.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 01/11] i18n: add--interactive: mark strings for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-29T21:21:37Z","receivedAt":"2016-09-29T21:22:07Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 26.09.2016 o 00:52, Junio C Hamano pisze:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes: \n\n>>  my $status_fmt = '%12s %12s %s';\n>> -my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');\n>> +my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));\n> \n> Wouldn't it make sense to allow translators to tweak $status_fmt if\n> you are allowing the earlier elements that are formatted with %12s,\n> as their translation may not fit within that width, in which case\n> they may want to make these columns wider?\n\nPerl's printf, sprintf, and format think all codepoints take up 1 print\ncolumn; also, without \"use utf8;\" they all think that one byte is one\ncodepoint (as it is in latin1 encoding).\n\nMany codepoints can take 0 print columns (zero-width joiners), or 2\ncolumns (so called wide characters).\n\nThe proper way to justify Unicode output is described e.g. in\nhttp://www.perl.com/pub/2012/05/perlunicook-unicode-column-width-for-printing.html\n\n  use Unicode::GCString;\n\n  my $gcs  = Unicode::GCString->new($str);  # grapheme cluster string\n  my $cols = $gcs->columns;\n  my $pad  = \" \" x (12 - $cols);\n\n  $status_head .= $str . $pad . \" \";\n\nThough we would need to provide fallback if there is no perl-i18n,\nno extended Unicode support in Perl (also, if we are not using\ngettext).\n\n\nSo it is even more complicated.\n\n>>  \t\t\tprompt_yesno(\n>> -\t\t\t\t'Your edited hunk does not apply. Edit again '\n>> -\t\t\t\t. '(saying \"no\" discards!) [y/n]? '\n>> +\t\t\t\t# TRANSLATORS: do not translate [y/n]\n>> +\t\t\t\t# The program will only accept that input\n>> +\t\t\t\t# at this point.\n>> +\t\t\t\t__('Your edited hunk does not apply. Edit again '\n>> +\t\t\t\t   . '(saying \"no\" discards!) [y/n]? ')\n> \n> Not just [y/n], but \"no\" in \"saying no discards!\" also needs to\n> stay, no?  I wonder if it is a good idea to lose the TRANSLATORS\n> comment by ejecting \"[y/n]\" outside the \"__()\" construct here.\n\nActually the message to translators should also mention that if\nthe translation of \"no\" doesn't begin with 'n', then one needs\nto say something like '(saying \"n\" for \"no\" discards!)'.\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"302950","messageId":"07371844-7fde-5b7f-b9e1-7db1a54fdbb5@gmail.com","threadId":"43967","inReplyTo":"xmqqfuoihc1m.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-29T21:27:24Z","receivedAt":"2016-09-29T21:27:40Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.09.2016 o 19:05, Junio C Hamano pisze:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> \n>> On the other hand, would it make sense to translate these commands? If\n>> so, we would mark for translation the commands name of @cmd in\n>> main_loop().\n>>\n>>  sub main_loop {\n>> -       my @cmd = ([ 'status', \\&status_cmd, ],\n>> -                  [ 'update', \\&update_cmd, ],\n>> -                  [ 'revert', \\&revert_cmd, ],\n>> -                  [ 'add untracked', \\&add_untracked_cmd, ],\n>> -                  [ 'patch', \\&patch_update_cmd, ],\n>> -                  [ 'diff', \\&diff_cmd, ],\n>> -                  [ 'quit', \\&quit_cmd, ],\n>> -                  [ 'help', \\&help_cmd, ],\n>> +       my @cmd = ([ __('status'), \\&status_cmd, ],\n>> +                  [ __('update'), \\&update_cmd, ],\n>> +                  [ __('revert'), \\&revert_cmd, ],\n>> +                  [ __('add untracked'), \\&add_untracked_cmd, ],\n>> +                  [ __('patch'), \\&patch_update_cmd, ],\n>> +                  [ __('diff'), \\&diff_cmd, ],\n>> +                  [ __('quit'), \\&quit_cmd, ],\n>> +                  [ __('help'), \\&help_cmd, ],\n> \n> I don't know offhand.  If the code to prompt and accept the command\n> given by the user can take the translated word (or a prefix of it),\n> theoretically I would say it could be made to work, but to me it is\n> dubious the benefit outweighs its downsides.  It would make teaching\n> Git and troubleshooting over the phone harder, I would guess.\n> \n>  A: \"Hi, I am in a 'git add -i' session.\"\n>  B: \"Give 's' at the prompt.\"\n>  A: \"My Git does not seem to take 's' as a valid command.\"\n>  B: \"What? I've never seen that problem.\"\n>  ... back and forth wastes 10 minutes ...\n>  A: \"By the way, I am running Git in Portuguese.\"\n\nAlso, for one-letter commands to work (there is setting where you\ndon't even need to press enter, IIRC) all those translations would\nhave to be chosen to begin with different letter, isn't it?\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"302951","messageId":"xmqq1t02e6kl.fsf@gitster.mtv.corp.google.com","threadId":"43967","inReplyTo":"07371844-7fde-5b7f-b9e1-7db1a54fdbb5@gmail.com","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-29T21:31:38Z","receivedAt":"2016-09-29T21:31:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> W dniu 29.09.2016 o 19:05, Junio C Hamano pisze:\n>> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n>> \n>>> On the other hand, would it make sense to translate these commands? If\n>>> so, we would mark for translation the commands name of @cmd in\n>>> main_loop().\n>>>\n>>>  sub main_loop {\n>>> -       my @cmd = ([ 'status', \\&status_cmd, ],\n>>> -                  [ 'update', \\&update_cmd, ],\n>>> -                  [ 'revert', \\&revert_cmd, ],\n>>> -                  [ 'add untracked', \\&add_untracked_cmd, ],\n>>> -                  [ 'patch', \\&patch_update_cmd, ],\n>>> -                  [ 'diff', \\&diff_cmd, ],\n>>> -                  [ 'quit', \\&quit_cmd, ],\n>>> -                  [ 'help', \\&help_cmd, ],\n>>> +       my @cmd = ([ __('status'), \\&status_cmd, ],\n>>> +                  [ __('update'), \\&update_cmd, ],\n>>> +                  [ __('revert'), \\&revert_cmd, ],\n>>> +                  [ __('add untracked'), \\&add_untracked_cmd, ],\n>>> +                  [ __('patch'), \\&patch_update_cmd, ],\n>>> +                  [ __('diff'), \\&diff_cmd, ],\n>>> +                  [ __('quit'), \\&quit_cmd, ],\n>>> +                  [ __('help'), \\&help_cmd, ],\n>> \n>> I don't know offhand.  If the code to prompt and accept the command\n>> given by the user can take the translated word (or a prefix of it),\n>> theoretically I would say it could be made to work, but to me it is\n>> dubious the benefit outweighs its downsides.  It would make teaching\n>> Git and troubleshooting over the phone harder, I would guess.\n>> \n>>  A: \"Hi, I am in a 'git add -i' session.\"\n>>  B: \"Give 's' at the prompt.\"\n>>  A: \"My Git does not seem to take 's' as a valid command.\"\n>>  B: \"What? I've never seen that problem.\"\n>>  ... back and forth wastes 10 minutes ...\n>>  A: \"By the way, I am running Git in Portuguese.\"\n>\n> Also, for one-letter commands to work (there is setting where you\n> don't even need to press enter, IIRC) all those translations would\n> have to be chosen to begin with different letter, isn't it?\n\nThe original was written with an explicit expectation that these\ncommand words will not be translated adn chose words that do not\nshare the first letter exactly for that reason.\n\nHaving said that, if somebody is willing to i18n the command words,\nI'd expect that the command line prompt interaction would be updated\nto take the unique prefix instead of the \"first byte\", and if that\nhappens, I think the resulting system would at least be internally\nconsistent.\n\nIt is still dubious to me if the benefit of i18n outweighs its\ndownsides, though.\n\n\n\n"},{"id":"302991","messageId":"e71c5040-8fed-887b-bf35-af4ae28d469f@gmail.com","threadId":"43967","inReplyTo":"1472646690-9699-3-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-30T17:26:34Z","receivedAt":"2016-09-30T17:26:51Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n> Mark messages in here document without interpolation for translation.\n> \n> Marking for translation by removing here documents this way, rather than\n> take advantage of \"print __ << EOF\" way, makes other instances of help\n> messages in clean.c match the first two in this file.  Otherwise,\n> reusing here document would add a trailer newline to the message, making\n> them not match 100%, hence creating two entries in pot template for\n> translation rather than a single entry.\n\nThis is good catch, but I think it goes backwards with the solution.\n\nIf the text to be translated is multi-line, and it must end with newline,\nwhy is this final newline not included in the msgid?  This would involve\nturning printf_ln into printf, and adding trailing newline in final\nentry for builtin/clean.c:295, etc. - I think it is better solution than\nuglyifing git-add--interactive.perl\n\nThough it is not much of uglifying thanks to Perl support for embedded\nnewlines in double-quoted strings.\n\n> \n> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  git-add--interactive.perl | 24 ++++++++++++------------\n>  1 file changed, 12 insertions(+), 12 deletions(-)\n> \n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index fb8e5de..e11a33d 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -636,25 +636,25 @@ sub list_and_choose {\n>  }\n>  \n>  sub singleton_prompt_help_cmd {\n> -\tprint colored $help_color, <<\\EOF ;\n> -Prompt help:\n> +\tprint colored $help_color, __(\n> +\"Prompt help:\n>  1          - select a numbered item\n>  foo        - select item based on unique prefix\n> -           - (empty) select nothing\n> -EOF\n> +           - (empty) select nothing\"),\n> +\"\\n\";\n>  }\n[... enough for information ...]\n\nRegards,\n-- \nJakub Narębski\n\n\n"},{"id":"302992","messageId":"b8c25ae3-143c-3e9b-0c7b-115a9b4756ae@gmail.com","threadId":"43967","inReplyTo":"1472646690-9699-4-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 03/11] i18n: add--interactive: mark strings with interpolation for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-30T17:52:52Z","receivedAt":"2016-09-30T17:53:10Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n\n> Use of sprintf following die or error_msg is necessary for placeholder\n> substitution take place.\n\nNo, it is not.  Though I don't think that we have in out Git::I18N\nthe support for Perl i18n placeholder substitution.\n\nFrom gettext manual:\nhttps://www.gnu.org/software/gettext/manual/gettext.html#perl_002dformat\n\n  15.3.16 Perl Format Strings\n\n  There are two kinds format strings in Perl: those acceptable to the Perl\n  built-in function printf, labelled as ‘perl-format’, and those acceptable\n  to the libintl-perl function __x, labelled as ‘perl-brace-format’.\n\n  Perl printf format strings are described in the sprintf section of\n  ‘man perlfunc’.\n\n  Perl brace format strings are described in the Locale::TextDomain(3pm)\n  manual page of the CPAN package libintl-perl. In brief, Perl format uses\n  placeholders put between braces (‘{’ and ‘}’). The placeholder must have\n  the syntax of simple identifiers.\n \nGit doesn't use Locale::TextDomain, from what I understand, to provide\nfallback in no-gettext case.  Also, Locale::TextDomain is not in core.\n\nThe syntax, with the help of shorthand helper function, looks like this:\nhttp://search.cpan.org/dist/libintl-perl/lib/Locale/TextDomain.pm#EXPORTED_FUNCTIONS\nhttps://metacpan.org/pod/Locale::TextDomain#EXPORTED-FUNCTIONS\n\n  __x MSGID, ID1 => VAL1, ID2 => VAL2, ...\n  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  One of the nicest features in Perl is its capability to interpolate\n  variables into strings:\n\n    print \"This is the $color $thing.\\n\";\n\n  This nice feature might con you into thinking that you could now write\n\n    print __\"This is the $color $thing.\\n\";\n\n  [But this doesn't work...]\n\n  [...] The Perl backend to GNU gettext has defined an alternative format\n  [to using printf / sprintf] for interpolatable strings:\n\n    \"This is the {color} {thing}.\\n\";\n\n  Instead of Perl variables you use place-holders (legal Perl variables\n  are also legal place-holders) in curly braces, and then you call\n\n    print __x (\"This is the {color} {thing}.\\n\", \n               thing => $thang,\n               color => $color);\n\n> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  git-add--interactive.perl | 26 ++++++++++++++------------\n>  1 file changed, 14 insertions(+), 12 deletions(-)\n> \n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index e11a33d..4e1e857 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -612,12 +612,12 @@ sub list_and_choose {\n>  \t\t\telse {\n>  \t\t\t\t$bottom = $top = find_unique($choice, @stuff);\n>  \t\t\t\tif (!defined $bottom) {\n> -\t\t\t\t\terror_msg \"Huh ($choice)?\\n\";\n> +\t\t\t\t\terror_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n\nSo this would be, self explained without need of comment\nfor translators:\n\n  +\t\t\t\t\terror_msg __x (\"Huh ({choice})?\\n\"), choice => $choice);\n\n\n>  \t\t\t\t\tnext TOPLOOP;\n>  \t\t\t\t}\n\nThough this is probably more work that you wanted to do.\nThe __x might be defined like this (borrowing from Locale::TextDomain),\nwhich needs to be put into perl/Git/I18N.pm\n\n  sub __ ($);\n  sub __expand ($%);\n\n  # With interpolation.\n  sub __x ($@)\n  {\n  \tmy ($msgid, %vars) = @_;\n\n  \treturn __expand (__($msgid), %vars);\n  }\n  \n  sub __expand ($%)\n  {\n  \tmy ($translation, %args) = @_;\n    \n  \tmy $re = join '|', map { quotemeta $_ } keys %args;\n  \t$translation =~ s/\\{($re)\\}/defined $args{$1} ? $args{$1} : \"{$1}\"/ge;\n\n  \treturn $translation;\n  }\n\n\n\nBest regards,\n-- \nJakub Narębski\n"},{"id":"303046","messageId":"a46dc5cb-85d9-88f2-865c-734204832101@gmail.com","threadId":"43967","inReplyTo":"1474913721.1035.9.camel@sapo.pt","subject":"Re: [PATCH v2 04/11] i18n: add--interactive: mark plural strings","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T16:49:14Z","receivedAt":"2016-10-01T16:50:47Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 26.09.2016 o 20:15, Vasco Almeida pisze:\n> A Qua, 31-08-2016 às 12:31 +0000, Vasco Almeida escreveu:\n>>\n>> Mark plural strings for translation.  Unfold each action case in one\n>> entire sentence.\n>>\n>> Pass new keyword for xgettext to extract.\n>>\n>> Update test to include new subrotine Q__() for plural strings handling.\n\nWhy use Q__() as the name of the subroutine? [looks further]. Oh, I see\nthat you are following the example of C shortcut functions (_, Q_ and N_).\n\nBut this is Perl, not C.  The standard shortcut functions are those\ndefined in Locale::TextDomain, even if we can't use this module directly.\nThose that deal with plural strings handling are __n and __nx / __xn.\n\nThe Perl equivalent of Q_ shorthand function in C, C++, etc. is __n.\nThere is also a function __nx for combining handling plural strings\ntogether with variable interpolation.\n\n  __n MSGID, MSGID_PLURAL, COUNT\n  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n  That is the reason for the existance of the function ngettext(),\n  that __n() is a short-cut for:\n\n    print __n\"One file has been deleted.\\n\", \n             \"All files have been deleted.\\n\",\n             $files_deleted;\n\n  Alternatively:\n\n    print __n (\"One file has been deleted.\\n\",\n               \"All files have been deleted.\\n\",\n               $files_deleted);\n\n\n  __nx MSGID, MSGID_PLURAL, COUNT, VAR1 => VAL1, VAR2 => VAL2, ...\n  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n  Bringing it all together:\n\n    print __nx (\"One file has been deleted.\\n\",\n                \"{count} files have been deleted.\\n\",\n                $num_files,\n                count => $num_files);\n\n  The function __nx() [and its alias __xn()] picks the correct plural\n  form (also for English!) and it is capable of interpolating variables\n  into strings.\n\n\n>>\n>> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n>> ---\n>>  Makefile                  |  3 ++-\n>>  git-add--interactive.perl | 24 ++++++++++++++++--------\n>>  perl/Git/I18N.pm          |  4 +++-\n>>  t/t0202/test.pl           | 11 ++++++++++-\n>>  4 files changed, 31 insertions(+), 11 deletions(-)\n\n>> diff --git a/Makefile b/Makefile\n>> index de5a030..eedf1fa 100644\n>> --- a/Makefile\n>> +++ b/Makefile\n>> @@ -2061,7 +2061,8 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n>>  \t--keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n>>  XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \\\n>>  \t--keyword=gettextln --keyword=eval_gettextln\n>> -XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl\n>> +XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n>> +\t--keyword=__ --keyword=\"Q__:1,2\"\n\nSo this would be\n\n   +XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n   +\t--keyword=__ --keyword=__x --keyword=__n:1,2 --keyword=__nx:1,2\n\n(assuming that __x was used for interpolation)\n \n>>  LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n>>  LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh\n>>  LOCALIZED_PERL = $(SCRIPT_PERL)\n[...]\n\n>> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n>> index 4e1e857..08badfa 100755\n>> --- a/git-add--interactive.perl\n>> +++ b/git-add--interactive.perl\n>> @@ -666,12 +666,18 @@ sub status_cmd {\n>>  sub say_n_paths {\n>>  \tmy $did = shift @_;\n>>  \tmy $cnt = scalar @_;\n>> -\tprint \"$did \";\n>> -\tif (1 < $cnt) {\n>> -\t\tprint \"$cnt paths\\n\";\n>> -\t}\n>> -\telse {\n>> -\t\tprint \"one path\\n\";\n>> +\tif ($did eq 'added') {\n>> +\t\tprintf(Q__(\"added one path\\n\", \"added %d paths\\n\",\n>> +\t\t\t   $cnt), $cnt);\n>> +\t} elsif ($did eq 'updated') {\n>> +\t\tprintf(Q__(\"updated one path\\n\", \"updated %d paths\\n\",\n>> +\t\t\t   $cnt), $cnt);\n>> +\t} elsif ($did eq 'reverted') {\n>> +\t\tprintf(Q__(\"reverted one path\\n\", \"reverted %d paths\\n\",\n>> +\t\t\t   $cnt), $cnt);\n>> +\t} else {\n>> +\t\tprintf(Q__(\"touched one path\\n\", \"touched %d paths\\n\",\n>> +\t\t\t   $cnt), $cnt);\n>>  \t}\n>>  }\n\nOne one hand side, it is recommended to avoid lego-like construction\nof sentences.\n\n  Translatable strings should be entire sentences. It is often not\n  possible to translate single verbs or adjectives in a substitutable\n  way.\n\nI think however that the action part ($did in original non-i18n code)\nis whole part in any language, so something like the following would\nbe enough:\n\n  \t# this hash is as much for validation, as for translation\n   \tmy %actions = map { $_ => 1 } (N__\"added\", N__\"updated\", N__\"reverted\");\n   \tif (exists $actions{$did}) {\n   \t\tprint __nx(\"{did} one path\\n\", \"{did} {count} paths\\n\", $cnt,\n   \t\t\t   did => __($did), count => $cnt);\n  \t} else {\n   \t\tprint __nx(\"touched one path\\n\", \"touched {count} paths\\n\", $cnt,\n   \t\t\t   count => $cnt);\n   \t}\n\nPlease correct me if I am wrong, and you know language where\n\"added %d paths\", \"updated %d paths\", \"reverted %d paths\" etc. must have\ndifferent word order.\n\n> When $cnt is 1 I get the following warning:\n> Redundant argument in printf at .../libexec/git-core/git-add--interactive line 680.\n\nI wonder what is the case of C code - is similar warning here, or is\ngettext smarter in that case...\n\n> The singular form does not have a %d to consume $cnt argument to\n> printf(). Either we find a way to suppress that warning or we change\n> the singular form to contain %d.\n\nAnyway, with __nx there should be no such problem.\n\n> \n>> @@ -1508,8 +1514,10 @@ sub patch_update_file {\n>> ...\n>> -\t\t\t\t\tprint colored $header_color, \"Split into \",\n>> -\t\t\t\t\tscalar(@split), \" hunks.\\n\";\n>> +\t\t\t\t\tprint colored $header_color, sprintf(\n>> +\t\t\t\t\t\tQ__(\"Split into %d hunk.\\n\",\n>> +\t\t\t\t\t\t    \"Split into %d hunks.\\n\",\n>> +\t\t\t\t\t\t    scalar(@split)), scalar(@split));\n>\n> Like we do with this.\n\nNote that it is a bit of change in behavior: previously Git would\nsay \"Split into 0 hunks.\\n\".\n\n\nThough this is probably more work that you wanted to do.  The __n would\ntake place of Q__, while the __nx function might be defined like this\n(borrowing from Locale::TextDomain), which needs to be put into Git::I18N:\n\n# Plural with interpolation.\nsub __nx ($$$@)\n{\n    my ($msgid, $msgid_plural, $count, %args) = @_;\n    \n    return __expand ((__n $msgid, $msgid_plural, $count),\n\t\t     %args);\n}\n\nBest regards,\n-- \nJakub Narębski\n\n"},{"id":"303047","messageId":"32b8c9ed-82df-0d71-a610-064b6ebf7a4e@gmail.com","threadId":"43967","inReplyTo":"xmqqbmzby3tc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 05/11] i18n: add--interactive: mark message for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T17:09:27Z","receivedAt":"2016-10-01T17:10:44Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 26.09.2016 o 01:09, Junio C Hamano pisze:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> \n>> -\t\tprint colored $prompt_color, $patch_mode_flavour{VERB},\n>> -\t\t  ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' :\n>> -\t\t   $hunk[$ix]{TYPE} eq 'deletion' ? ' deletion' :\n>> -\t\t   ' this hunk'),\n>> -\t\t  $patch_mode_flavour{TARGET},\n>> -\t\t  \" [y,n,q,a,d,/$other,?]? \";\n> \n> I hate to say this but expanding this single-liner into if/elsif/\n> cascade of uncountable number of arms is simply a disaster.\n\nEven if we turn this \"single\"-liner composition of sentence into\ninterpolation (allowing for reordering of parts in translation),\nlike\n\n   print colored $prompt_color, __x(\"{verb} {noun}{maybe_target} [y,n,q,a,d,/{other},?]? \",\n   \tverb => $patch_mode_flavour{VERB}, noun => $patch_mode_noun{$hunk[$ix]{TYPE}},\n   \tmaybe_target => $patch_mode_flavour{TARGET} || \"\", other => $other);\n\nThis would of course require N__() on values of hash, somewhere.\n\nthe problem is that the ordering may need to change depending on\nverb: \"Stage\", \"Stash\", \"Unstage\", \"Apply\", \"Discard\", and/or noun:\n\"mode change\", \"deletion\", \"this hunk\", and/or presence and value\nof maybe_target: \" to index\", \" from worktree\", \" from index and worktree\",\n\" to index and worktree\".\n\n>> +\t\tif ($patch_mode eq 'stage') {\n>> +\t\t\tif ($hunk[$ix]{TYPE} eq 'mode') {\n>> +\t\t\t  print colored $prompt_color,\n>> +\t\t\t    sprintf(__(\"Stage mode change [y,n,q,a,d,/%s,?]? \"), $other);\n>> +\t\t\t} elsif ($hunk[$ix]{TYPE} eq 'deletion') {\n>> +\t\t\t  print colored $prompt_color,\n>> +\t\t\t    sprintf(__(\"Stage deletion [y,n,q,a,d,/%s,?]? \"), $other);\n>> +\t\t\t} else {\n>> +\t\t\t  print colored $prompt_color,\n>> +\t\t\t    sprintf(__(\"Stage this hunk [y,n,q,a,d,/%s,?]? \"), $other);\n>> +\t\t\t}\n>> +\t\t} elsif ($patch_mode eq 'stash') {\n>> + ...\n>> +\t\t\t}\n>> +\t\t}\n> \n> I wonder if you can make a simple helper function so that the caller\n> here can still be a single-liner:\n> \n> \tprint_colored $prompt_color,\n>              sprintf(patch_update_prompt_string($patch_mode, $hunk[$ix]{TYPE}), $other);\n>  \n> where the patch_update_prompt_string helper function would look up\n> these messages from a table that is looked up by patch-mode and TYPE\n> and the run __() on it, or something?\n\nYes, this would be necessary; hide complexity behind helper function.\n\n-- \nJakub Narębski\n\n"},{"id":"303048","messageId":"84857c15-9f46-5e1c-d253-e08a170ff77d@gmail.com","threadId":"43967","inReplyTo":"1472646690-9699-8-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 07/11] i18n: add--interactive: mark edit_hunk_manually message for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T18:48:28Z","receivedAt":"2016-10-01T18:49:45Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n\n> Mark message of edit_hunk_manually displayed in the editing file when\n> user chooses 'e' option.  The message had to be unfolded to allow\n> translation of the $participle verb.\n\nActually you need to unfold the message if exact translation (the ordering\nof words) depends on the $participle verb.\n\nMoreover, because the translation of message of edit_hunk_manually can\ndepend *only* on $participle verb (it cannot depends on $remove_minus\nand $remove_plus, as they are either ('-', '+') or ('+', '-')), with\n\"particular\" (contexted) translation of $participle, if the translation\nwould be different for different $participle, one can simply move whole\ntranslation to $participle.\n\n> \n> Some messages end up being exactly the same for some uses cases, but\n> left it for easier change in the future, e.g., wanting to change wording\n> of one particular use case.\n> \n> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  git-add--interactive.perl | 60 ++++++++++++++++++++++++++++++++++++++---------\n>  1 file changed, 49 insertions(+), 11 deletions(-)\n> \n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index acbfa4e..235142c 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -1057,22 +1057,60 @@ sub edit_hunk_manually {\n>  \tmy $fh;\n>  \topen $fh, '>', $hunkfile\n>  \t\tor die sprintf(__(\"failed to open hunk edit file for writing: %s\"), $!);\n> -\tprint $fh \"# Manual hunk edit mode -- see bottom for a quick guide\\n\";\n> +\tprint $fh __(\"# Manual hunk edit mode -- see bottom for a quick guide\\n\");\n\nThis would be left as is (though you can write __\"...\" instead of __(\"...\")).\n\n>  \tprint $fh @$oldtext;\n> -\tmy $participle = $patch_mode_flavour{PARTICIPLE};\n\nThis would be replaced with\n\n  -\tmy $participle = __($patch_mode_flavour{PARTICIPLE});\n\nAdditionally you would need to mark the text of $participle itself for\ntranslation, with context; for example:\n\n  -                PARTICIPLE => 'staging',\n  +                PARTICIPLE => N__p('Participle for \"stage\" operation, for edit hunk manually message', 'staging'),\n\nThat would require adding \"--keyword=N__p:1c,2\" to Makefile, of course.\nThe entry in the *.pot / *.po translations file would be preceded with \n\"msgctxt <context>\" line.\n\n>  \tmy $is_reverse = $patch_mode_flavour{IS_REVERSE};\n>  \tmy ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');\n> -\tprint $fh <<EOF;\n> -# ---\n> -# To remove '$remove_minus' lines, make them ' ' lines (context).\n> -# To remove '$remove_plus' lines, delete them.\n> +\tprint $fh sprintf(__(\n\n  +\tprint $fh __x(<<'EOF', remove_minus => $remove_minus, remove_plus => $remove_plus,\n  +\t\t      participle => $participle);\n\nor\n\n  +\t\t      participle => __($participle));\n\nassuming that $participle assignment doesn't use __ then.\n\nNote that xgettext supports heredoc syntax for Perl language:\n\n  Here-documents are recognized. If the delimiter is enclosed in\n  single quotes, the string is not interpolated. If it is enclosed\n  in double quotes or has no quotes at all, the string is interpolated.\n\n  Delimiters that start with a digit are not supported!\n\n> +\"# ---\n> +# To remove '%s' lines, make them ' ' lines (context).\n> +# To remove '%s' lines, delete them.\n\n  +# To remove '{remove_minus}' lines, make them ' ' lines (context).\n  +# To remove '{remove_plus}' lines, delete them.\n\n>  # Lines starting with # will be removed.\n> -#\n> -# If the patch applies cleanly, the edited hunk will immediately be\n> -# marked for $participle. If it does not apply cleanly, you will be given\n> +#\"), $remove_minus, $remove_plus),\n\n   # Lines starting with # will be removed.\n  +#\n  +# If the patch applies cleanly, the edited hunk will immediately be\n  +# marked for {participle}. If it does not apply cleanly, you will be given\n\n[...]\n\nHere is definition of relevant subroutines, based on Locale::TextDomain.\n\nsub N__p($$) {\n    return @_;\n}\n\n-- \nJakub Narębski\n"},{"id":"303049","messageId":"a3a74863-f7c4-4c9b-619d-33fbe0c33860@gmail.com","threadId":"43967","inReplyTo":"xmqqy42fwotm.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 08/11] i18n: send-email: mark strings for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T18:55:35Z","receivedAt":"2016-10-01T18:56:57Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 26.09.2016 o 01:18, Junio C Hamano pisze:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> \n>> @@ -1403,7 +1412,7 @@ Message-Id: $message_id\n>>  \tif ($quiet) {\n>>  \t\tprintf (($dry_run ? \"Dry-\" : \"\").\"Sent %s\\n\", $subject);\n>>  \t} else {\n>> -\t\tprint (($dry_run ? \"Dry-\" : \"\").\"OK. Log says:\\n\");\n>> +\t\tprint (($dry_run ? \"Dry-\" : \"\"). __(\"OK. Log says:\\n\"));\n> \n> I am not sure about this change.  We either say Dry-Sent/Dry-OK\n> (under --dry-run) or \"Sent/OK\"; don't you want \"dry-\" part also\n> translated?\n\nActually, we would probably want to unfold it, that is use \n__(\"Dry-OK. Log says:\\n\") and __(\"OK. Log says:\\n\"), etc.\n\n-- \nJakub Narębski\n\n"},{"id":"303051","messageId":"37c2efce-90b1-9415-eb85-64358e43b853@gmail.com","threadId":"43967","inReplyTo":"1472646690-9699-10-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2 09/11] i18n: send-email: mark warnings and errors for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T19:51:38Z","receivedAt":"2016-10-01T19:52:52Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n\n> Mark warnings, errors and other messages for translation.\n>\n\nWhich discovered a few places with questionable code...\n\n(though there is one place with bad handling of translation)\n \n> Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n> ---\n>  git-send-email.perl | 36 ++++++++++++++++++------------------\n>  1 file changed, 18 insertions(+), 18 deletions(-)\n> \n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index 2521832..e7f712e 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -118,20 +118,20 @@ sub format_2822_time {\n>  \tmy $localmin = $localtm[1] + $localtm[2] * 60;\n>  \tmy $gmtmin = $gmttm[1] + $gmttm[2] * 60;\n>  \tif ($localtm[0] != $gmttm[0]) {\n> -\t\tdie \"local zone differs from GMT by a non-minute interval\\n\";\n> +\t\tdie __(\"local zone differs from GMT by a non-minute interval\\n\");\n>  \t}\n>  \tif ((($gmttm[6] + 1) % 7) == $localtm[6]) {\n>  \t\t$localmin += 1440;\n>  \t} elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {\n>  \t\t$localmin -= 1440;\n>  \t} elsif ($gmttm[6] != $localtm[6]) {\n> -\t\tdie \"local time offset greater than or equal to 24 hours\\n\";\n> +\t\tdie __(\"local time offset greater than or equal to 24 hours\\n\");\n\nAs one can see that this is the same message as below, so I wondered\nwhy the same test is repeated... But it is even worse.  This test\nis first, wrongly described: it checks that the day of week is the\nsame in local timezone and in UTC / GMT.  But second, it is WRONG!\n\nFor example if UTC time is just before midnight, then any positive\ntimezone has different day of week (next day); if UTC is just before\nmidnight, then any negative timezone has different day of week (previous\nday).\n\n  $ LC_ALL=C TZ=US/Hawaii date --date=\"2016-10-01 01:00 UTC\"\n  Fri Sep 30 15:00:00 HST 2016\n  $ LC_ALL=C TZ=US/Hawaii date --date=\"2016-10-01 01:00 UTC\" --utc\n  Sat Oct  1 01:00:00 UTC 2016\n\n\n>  \t}\n>  \tmy $offset = $localmin - $gmtmin;\n>  \tmy $offhour = $offset / 60;\n>  \tmy $offmin = abs($offset % 60);\n>  \tif (abs($offhour) >= 24) {\n> -\t\tdie (\"local time offset greater than or equal to 24 hours\\n\");\n> +\t\tdie __(\"local time offset greater than or equal to 24 hours\\n\");\n\nThis is good test.\n\n>  \t}\n>  \n>  \treturn sprintf(\"%s, %2d %s %d %02d:%02d:%02d %s%02d%02d\",\n> @@ -199,13 +199,13 @@ sub do_edit {\n>  \t\tmap {\n>  \t\t\tsystem('sh', '-c', $editor.' \"$@\"', $editor, $_);\n>  \t\t\tif (($? & 127) || ($? >> 8)) {\n> -\t\t\t\tdie(\"the editor exited uncleanly, aborting everything\");\n> +\t\t\t\tdie(__(\"the editor exited uncleanly, aborting everything\"));\n>  \t\t\t}\n>  \t\t} @_;\n>  \t} else {\n>  \t\tsystem('sh', '-c', $editor.' \"$@\"', $editor, @_);\n>  \t\tif (($? & 127) || ($? >> 8)) {\n> -\t\t\tdie(\"the editor exited uncleanly, aborting everything\");\n> +\t\t\tdie(__(\"the editor exited uncleanly, aborting everything\"));\n>  \t\t}\n>  \t}\n\nHere we see some unnecessary code duplication, and thus\nmessage duplication.\n\n\n> @@ -1410,7 +1410,7 @@ Message-Id: $message_id\n>  \t\t$smtp->code =~ /250|200/ or die \"Failed to send $subject\\n\".$smtp->message;\n>  \t}\n>  \tif ($quiet) {\n> -\t\tprintf (($dry_run ? \"Dry-\" : \"\").\"Sent %s\\n\", $subject);\n> +\t\tprintf (($dry_run ? \"Dry-\" : \"\"). __(\"Sent %s\\n\"), $subject);\n>  \t} else {\n>  \t\tprint (($dry_run ? \"Dry-\" : \"\"). __(\"OK. Log says:\\n\"));\n>  \t\tif (!file_name_is_absolute($smtp_server)) {\n\nYou would want to translate Dry-Sent and Dry-OK.\n\n-- \nJakub Narębski\n\n"},{"id":"303052","messageId":"34c793f6-b297-3040-b5fa-29f4a9480cd2@gmail.com","threadId":"43967","inReplyTo":"xmqqtwd3wooa.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 11/11] i18n: difftool: mark warnings for translation","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-01T19:56:04Z","receivedAt":"2016-10-01T19:57:18Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 26.09.2016 o 01:21, Junio C Hamano pisze:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> \n>> -\t\t\twarn << 'EOF';\n>> +\t\t\twarn __ <<'EOF';\n>>  Combined diff formats ('-c' and '--cc') are not supported in\n>>  directory diff mode ('-d' and '--dir-diff').\n>>  EOF\n> \n> Wow, didn't imagine gettext would pick this up.  Nice.\n\nFrom gettext documentation:\nhttps://www.gnu.org/software/gettext/manual/gettext.html\n\n 15 Other Programming Languages\n [...]\n 15.5 Individual Programming Languages\n [...]\n 15.5.18 Perl\n [...]\n 15.5.18.4 What are Strings And Quote-like Expressions?\n\n Perl offers a plethora of different string constructs. Those that\n can be used either as arguments to functions or inside braces for\n hash lookups are generally supported by xgettext.\n\n [...]\n\n * here documents \n\n       print gettext <<'EOF';\n       program not found in $PATH\n       EOF\n\n       print ngettext <<EOF, <<\"EOF\";\n       one file deleted\n       EOF\n       several files deleted\n       EOF\n\n Here-documents are recognized. If the delimiter is enclosed in single\n quotes, the string is not interpolated. If it is enclosed in double\n quotes or has no quotes at all, the string is interpolated.\n\n Delimiters that start with a digit are not supported!\n\n-- \nJakub Narębski\n\n"},{"id":"303083","messageId":"1475498507.1776.15.camel@sapo.pt","threadId":"43967","inReplyTo":"b8c25ae3-143c-3e9b-0c7b-115a9b4756ae@gmail.com","subject":"Re: [PATCH v2 03/11] i18n: add--interactive: mark strings with interpolation for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-10-03T12:41:47Z","receivedAt":"2016-10-03T12:42:08Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"> W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n> > Use of sprintf following die or error_msg is necessary for\n> > placeholder\n> > substitution take place.\n> \n> No, it is not.  Though I don't think that we have in out Git::I18N\n> the support for Perl i18n placeholder substitution.\n\nI will try to change the commit message to better reflect the reality.\n\n> From gettext manual:\n> https://www.gnu.org/software/gettext/manual/gettext.html#perl_002dfor\n> mat\n> \n>   15.3.16 Perl Format Strings\n> \n>   There are two kinds format strings in Perl: those acceptable to the\n> Perl\n>   built-in function printf, labelled as ‘perl-format’, and those\n> acceptable\n>   to the libintl-perl function __x, labelled as ‘perl-brace-format’.\n> \n>   Perl printf format strings are described in the sprintf section of\n>   ‘man perlfunc’.\n> \n>   Perl brace format strings are described in the\n> Locale::TextDomain(3pm)\n>   manual page of the CPAN package libintl-perl. In brief, Perl format\n> uses\n>   placeholders put between braces (‘{’ and ‘}’). The placeholder must\n> have\n>   the syntax of simple identifiers.\n>  \n> Git doesn't use Locale::TextDomain, from what I understand, to\n> provide\n> fallback in no-gettext case.  Also, Locale::TextDomain is not in\n> core.\n\nYes that can be a reason not to use Locale::TextDomain. When Ævar\nArnfjörð Bjarmason added gettext support and i18n stuff, he chose no to\nuse TextDomain because it did more than he wanted it to do, and that\ncould introduce bugs and unnecessary work.\n\n5e9637c (\"i18n: add infrastructure for translating Git with gettext\",\n2011-11-18)\n\nhttps://public-inbox.org/git/AANLkTilYD_NyIZMyj9dHtVk-ylVBfvyxpCC7982LW\nnVd@mail.gmail.com/\n\n\n> > diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> > index e11a33d..4e1e857 100755\n> > --- a/git-add--interactive.perl\n> > +++ b/git-add--interactive.perl\n> > @@ -612,12 +612,12 @@ sub list_and_choose {\n> >                       else {\n> >                               $bottom = $top = find_unique($choice, @stuff);\n> >                               if (!defined $bottom) {\n> > -                                     error_msg \"Huh ($choice)?\\n\";\n> > +                                     error_msg sprintf(__(\"Huh (%s)?\\n\"), $choice);\n> \n> So this would be, self explained without need of comment\n> for translators:\n> \n>   +                                     error_msg __x (\"Huh ({choice})?\\n\"), choice => $choice);\n> \n> \n> >                                       next TOPLOOP;\n> >                               }\n> \n> Though this is probably more work that you wanted to do.\n> The __x might be defined like this (borrowing from Locale::TextDomain),\n> which needs to be put into perl/Git/I18N.pm\n> \n>   sub __ ($);\n>   sub __expand ($%);\n> \n>   # With interpolation.\n>   sub __x ($@)\n>   {\n>         my ($msgid, %vars) = @_;\n> \n>         return __expand (__($msgid), %vars);\n>   }\n>   \n>   sub __expand ($%)\n>   {\n>         my ($translation, %args) = @_;\n>     \n>         my $re = join '|', map { quotemeta $_ } keys %args;\n>         $translation =~ s/\\{($re)\\}/defined $args{$1} ? $args{$1} : \"{$1}\"/ge;\n> \n>         return $translation;\n>   }\n\nI wonder if it is worth the trouble to add and use these functions,\nwhen there is already a way that works and for me looks simpler. One\nreason, if valid, would be that translators already translate strings\nwith %d and %s from C source which is where the majority of the English\ntext comes from. Thus it would make little difference for them.\nIf we use in perl string like in C there is a chance that there will be\na match of some string and would lead to just one msgid instead of two\nin the git.pot template for translation. Actually this happens for the\nstring with \"Huh (%s)?\" in clean.c.\n\nUnfortunately, I do not know if I would add these changes because I\nknow little about perl and hence I am not comfortable to do so.\n\nMaybe if you see it is indeed worth adding these to Git I18N.pm, you\ncould send a follow-up patch or a replacement for this one.\n"},{"id":"303084","messageId":"1475498630.1776.17.camel@sapo.pt","threadId":"43967","inReplyTo":"07371844-7fde-5b7f-b9e1-7db1a54fdbb5@gmail.com","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-10-03T12:43:50Z","receivedAt":"2016-10-03T12:44:02Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Qui, 29-09-2016 às 23:27 +0200, Jakub Narębski escreveu:\n> W dniu 29.09.2016 o 19:05, Junio C Hamano pisze:\n> > \n> > Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> > \n> > > \n> > > On the other hand, would it make sense to translate these\n> > > commands? If\n> > > so, we would mark for translation the commands name of @cmd in\n> > > main_loop().\n> > > \n> > >  sub main_loop {\n> > > -       my @cmd = ([ 'status', \\&status_cmd, ],\n> > > -                  [ 'update', \\&update_cmd, ],\n> > > -                  [ 'revert', \\&revert_cmd, ],\n> > > -                  [ 'add untracked', \\&add_untracked_cmd, ],\n> > > -                  [ 'patch', \\&patch_update_cmd, ],\n> > > -                  [ 'diff', \\&diff_cmd, ],\n> > > -                  [ 'quit', \\&quit_cmd, ],\n> > > -                  [ 'help', \\&help_cmd, ],\n> > > +       my @cmd = ([ __('status'), \\&status_cmd, ],\n> > > +                  [ __('update'), \\&update_cmd, ],\n> > > +                  [ __('revert'), \\&revert_cmd, ],\n> > > +                  [ __('add untracked'), \\&add_untracked_cmd, ],\n> > > +                  [ __('patch'), \\&patch_update_cmd, ],\n> > > +                  [ __('diff'), \\&diff_cmd, ],\n> > > +                  [ __('quit'), \\&quit_cmd, ],\n> > > +                  [ __('help'), \\&help_cmd, ],\n> > \n> > I don't know offhand.  If the code to prompt and accept the command\n> > given by the user can take the translated word (or a prefix of it),\n> > theoretically I would say it could be made to work, but to me it is\n> > dubious the benefit outweighs its downsides.  It would make\n> > teaching\n> > Git and troubleshooting over the phone harder, I would guess.\n> > \n> >  A: \"Hi, I am in a 'git add -i' session.\"\n> >  B: \"Give 's' at the prompt.\"\n> >  A: \"My Git does not seem to take 's' as a valid command.\"\n> >  B: \"What? I've never seen that problem.\"\n> >  ... back and forth wastes 10 minutes ...\n> >  A: \"By the way, I am running Git in Portuguese.\"\n> \n> Also, for one-letter commands to work (there is setting where you\n> don't even need to press enter, IIRC) all those translations would\n> have to be chosen to begin with different letter, isn't it?\n\nI choose not do mark those command names for translation in the next\nre-roll since there is no obvious gain from it.\n"},{"id":"303085","messageId":"1475498788.1776.20.camel@sapo.pt","threadId":"43967","inReplyTo":"a46dc5cb-85d9-88f2-865c-734204832101@gmail.com","subject":"Re: [PATCH v2 04/11] i18n: add--interactive: mark plural strings","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-10-03T12:46:28Z","receivedAt":"2016-10-03T12:46:40Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Sáb, 01-10-2016 às 18:49 +0200, Jakub Narębski escreveu:\n> W dniu 26.09.2016 o 20:15, Vasco Almeida pisze:\n> > \n> > A Qua, 31-08-2016 às 12:31 +0000, Vasco Almeida escreveu:\n> > > \n> > > \n> > > Mark plural strings for translation.  Unfold each action case in\n> > > one\n> > > entire sentence.\n> > > \n> > > Pass new keyword for xgettext to extract.\n> > > \n> > > Update test to include new subrotine Q__() for plural strings\n> > > handling.\n> \n> Why use Q__() as the name of the subroutine? [looks further]. Oh, I\n> see\n> that you are following the example of C shortcut functions (_, Q_ and\n> N_).\n> \n> But this is Perl, not C.  The standard shortcut functions are those\n> defined in Locale::TextDomain, even if we can't use this module\n> directly.\n> Those that deal with plural strings handling are __n and __nx / __xn.\n> \n> The Perl equivalent of Q_ shorthand function in C, C++, etc. is __n.\n> There is also a function __nx for combining handling plural strings\n> together with variable interpolation.\n\nI was trying to follow the same style of C. I will change the name Q__\nto __x for the sake of conformance.\n\n\n> > > diff --git a/git-add--interactive.perl b/git-add\n> > > --interactive.perl\n> > > index 4e1e857..08badfa 100755\n> > > --- a/git-add--interactive.perl\n> > > +++ b/git-add--interactive.perl\n> > > @@ -666,12 +666,18 @@ sub status_cmd {\n> > >  sub say_n_paths {\n> > >  \tmy $did = shift @_;\n> > >  \tmy $cnt = scalar @_;\n> > > -\tprint \"$did \";\n> > > -\tif (1 < $cnt) {\n> > > -\t\tprint \"$cnt paths\\n\";\n> > > -\t}\n> > > -\telse {\n> > > -\t\tprint \"one path\\n\";\n> > > +\tif ($did eq 'added') {\n> > > +\t\tprintf(Q__(\"added one path\\n\", \"added %d\n> > > paths\\n\",\n> > > +\t\t\t   $cnt), $cnt);\n> > > +\t} elsif ($did eq 'updated') {\n> > > +\t\tprintf(Q__(\"updated one path\\n\", \"updated %d\n> > > paths\\n\",\n> > > +\t\t\t   $cnt), $cnt);\n> > > +\t} elsif ($did eq 'reverted') {\n> > > +\t\tprintf(Q__(\"reverted one path\\n\", \"reverted %d\n> > > paths\\n\",\n> > > +\t\t\t   $cnt), $cnt);\n> > > +\t} else {\n> > > +\t\tprintf(Q__(\"touched one path\\n\", \"touched %d\n> > > paths\\n\",\n> > > +\t\t\t   $cnt), $cnt);\n> > >  \t}\n> > >  }\n> \n> One one hand side, it is recommended to avoid lego-like construction\n> of sentences.\n> \n>   Translatable strings should be entire sentences. It is often not\n>   possible to translate single verbs or adjectives in a substitutable\n>   way.\n> \n> I think however that the action part ($did in original non-i18n code)\n> is whole part in any language, so something like the following would\n> be enough:\n> \n>   \t# this hash is as much for validation, as for translation\n>    \tmy %actions = map { $_ => 1 } (N__\"added\", N__\"updated\",\n> N__\"reverted\");\n>    \tif (exists $actions{$did}) {\n>    \t\tprint __nx(\"{did} one path\\n\", \"{did} {count}\n> paths\\n\", $cnt,\n>    \t\t\t   did => __($did), count => $cnt);\n>   \t} else {\n>    \t\tprint __nx(\"touched one path\\n\", \"touched {count}\n> paths\\n\", $cnt,\n>    \t\t\t   count => $cnt);\n>    \t}\n> \n> Please correct me if I am wrong, and you know language where\n> \"added %d paths\", \"updated %d paths\", \"reverted %d paths\" etc. must\n> have\n> different word order.\n\nWe may never know. :-) I prefer not to make assumptions about other\nlanguages and I think there is not much to gain from using this\napproach instead of marking entire sentence as the patch does. I mean\nthe code verbosity is almost the same but maybe it gets harder to\ntranslate.\nOther thing, we want to avoid marking for translation single words\n(when that is avoidable) because those could appear on other sites that\nneed a different translation according to the context. For example:\n'commit' could be a verb or a noun from the context.\n\n> > When $cnt is 1 I get the following warning:\n> > Redundant argument in printf at .../libexec/git-core/git-add\n> > --interactive line 680.\n> \n> I wonder what is the case of C code - is similar warning here, or is\n> gettext smarter in that case...\n\nI do not know but I know there is a few cases like this in C code.\n\n> > The singular form does not have a %d to consume $cnt argument to\n> > printf(). Either we find a way to suppress that warning or we\n> > change\n> > the singular form to contain %d.\n> \n> Anyway, with __nx there should be no such problem.\n> \n> > \n> > \n> > > \n> > > @@ -1508,8 +1514,10 @@ sub patch_update_file {\n> > > ...\n> > > -\t\t\t\t\tprint colored\n> > > $header_color, \"Split into \",\n> > > -\t\t\t\t\tscalar(@split), \"\n> > > hunks.\\n\";\n> > > +\t\t\t\t\tprint colored\n> > > $header_color, sprintf(\n> > > +\t\t\t\t\t\tQ__(\"Split into\n> > > %d hunk.\\n\",\n> > > +\t\t\t\t\t\t    \"Split into\n> > > %d hunks.\\n\",\n> > > +\t\t\t\t\t\t    scalar(@spli\n> > > t)), scalar(@split));\n> > \n> > Like we do with this.\n> \n> Note that it is a bit of change in behavior: previously Git would\n> say \"Split into 0 hunks.\\n\".\n> \n> \n> Though this is probably more work that you wanted to do.  The __n\n> would\n> take place of Q__, while the __nx function might be defined like this\n> (borrowing from Locale::TextDomain), which needs to be put into\n> Git::I18N:\n> \n> # Plural with interpolation.\n> sub __nx ($$$@)\n> {\n>     my ($msgid, $msgid_plural, $count, %args) = @_;\n>     \n>     return __expand ((__n $msgid, $msgid_plural, $count),\n> \t\t     %args);\n> }\n\nI thank you very much for your code suggestion and review but I am not\ncomfortable enough with perl to fiddle much more and add this to the\ni18n work of the perl scripts, as I said before.\n\nSo if you find this a good think do add, please send patches as a\nfollow-up or to replace this patch.\n"},{"id":"303086","messageId":"1475498965.1776.23.camel@sapo.pt","threadId":"43967","inReplyTo":"32b8c9ed-82df-0d71-a610-064b6ebf7a4e@gmail.com","subject":"Re: [PATCH v2 05/11] i18n: add--interactive: mark message for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-10-03T12:49:25Z","receivedAt":"2016-10-03T12:49:46Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Sáb, 01-10-2016 às 19:09 +0200, Jakub Narębski escreveu:\n> W dniu 26.09.2016 o 01:09, Junio C Hamano pisze:\n> > Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> > \n> >> -            print colored $prompt_color,\n> $patch_mode_flavour{VERB},\n> >> -              ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' :\n> >> -               $hunk[$ix]{TYPE} eq 'deletion' ? ' deletion' :\n> >> -               ' this hunk'),\n> >> -              $patch_mode_flavour{TARGET},\n> >> -              \" [y,n,q,a,d,/$other,?]? \";\n> > \n> > I hate to say this but expanding this single-liner into if/elsif/\n> > cascade of uncountable number of arms is simply a disaster.\n> \n> Even if we turn this \"single\"-liner composition of sentence into\n> interpolation (allowing for reordering of parts in translation),\n> like\n> \n>    print colored $prompt_color, __x(\"{verb} {noun}{maybe_target}\n> [y,n,q,a,d,/{other},?]? \",\n>         verb => $patch_mode_flavour{VERB}, noun =>\n> $patch_mode_noun{$hunk[$ix]{TYPE}},\n>         maybe_target => $patch_mode_flavour{TARGET} || \"\", other =>\n> $other);\n> \n> This would of course require N__() on values of hash, somewhere.\n> \n> the problem is that the ordering may need to change depending on\n> verb: \"Stage\", \"Stash\", \"Unstage\", \"Apply\", \"Discard\", and/or noun:\n> \"mode change\", \"deletion\", \"this hunk\", and/or presence and value\n> of maybe_target: \" to index\", \" from worktree\", \" from index and\n> worktree\",\n> \" to index and worktree\".\n\nSo it does not work, unfortunately. The plus side is it would be very\nconcise compared to laying every combination as entire sentences.\nHowever, if it worked, I think it would be a bit difficult to translate\nand translators would be prone to commit some mistake somewhere. It may\nbe harder to translate a sentence by its bits than translate it as a\nwhole.\n"},{"id":"303088","messageId":"1475500908.1776.27.camel@sapo.pt","threadId":"43967","inReplyTo":"e71c5040-8fed-887b-bf35-af4ae28d469f@gmail.com","subject":"Re: [PATCH v2 02/11] i18n: add--interactive: mark simple here documents for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-10-03T13:21:48Z","receivedAt":"2016-10-03T13:22:01Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Sex, 30-09-2016 às 19:26 +0200, Jakub Narębski escreveu:\n> W dniu 31.08.2016 o 14:31, Vasco Almeida pisze:\n> > Mark messages in here document without interpolation for\n> translation.\n> > \n> > Marking for translation by removing here documents this way, rather\n> than\n> > take advantage of \"print __ << EOF\" way, makes other instances of\n> help\n> > messages in clean.c match the first two in this file.  Otherwise,\n> > reusing here document would add a trailer newline to the message,\n> making\n> > them not match 100%, hence creating two entries in pot template for\n> > translation rather than a single entry.\n> \n> This is good catch, but I think it goes backwards with the solution.\n> \n> If the text to be translated is multi-line, and it must end with\n> newline,\n> why is this final newline not included in the msgid?  This would\n> involve\n> turning printf_ln into printf, and adding trailing newline in final\n> entry for builtin/clean.c:295, etc. - I think it is better solution\n> than\n> uglyifing git-add--interactive.perl\n> \n> Though it is not much of uglifying thanks to Perl support for\n> embedded\n> newlines in double-quoted strings.\n\nI will do this for the next re-roll. Thanks\n"}]}