{"thread":{"id":"44805","subject":"[RFC PATCH 0/5] Localise error headers","startedAt":"2017-01-02T11:15:02Z","lastAt":"2017-04-01T17:38:41Z","messageCount":24,"participants":["Michael J Gruber","Duy Nguyen","Stefan Beller","Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"308614","messageId":"cover.1483354746.git.git@drmicha.warpmail.net","threadId":"44805","inReplyTo":null,"subject":"[RFC PATCH 0/5] Localise error headers","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2017-01-02T11:14:49Z","receivedAt":"2017-01-02T11:15:02Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Currently, the headers \"error: \", \"warning: \" etc. - generated by die(),\nwarning() etc. - are not localized, but we feed many localized error messages\ninto these functions so that we produce error messages with mixed localisation.\n\nThis series introduces variants of die() etc. that use localised variants of\nthe headers, i.e. _(\"error: \") etc., and are to be fed localized messages. So,\ninstead of die(_(\"not workee\")), which would produce a mixed localisation (such\nas \"error: geht ned\"), one should use die_(_(\"not workee\")) (resulting in\n\"Fehler: geht ned\").\n\nIn this implementation, the gettext call for the header and the body are done\nin different places (error function vs. caller) but this call pattern seems to\nbe the easiest variant for the caller, because the message body has to be marked\nfor localisation in any case, and N_() requires more letters than _(), an extra\nargument to die() etc. even more than the extra \"_\" in the function name.\n\n1/5 prepares the error machinery\n2/5 provides new variants error_() etc.\n3/5 has coccinelli rules error(_(E)) -> error_(_(E)) etc.\n4/5 applies the coccinelli patches\n\n5/5 is not to be applied to the main tree, but helps you try out the feature:\nit has changes to de.po and git.pot so that e.g. \"git branch\" has fully localised\nerror messages (see the recipe in the commit message).\n\nMichael J Gruber (5):\n  error/warn framework: prepare for l10n\n  error/warn framework: provide localized variants\n  error/warn framework framework: coccinelli rules\n  error/warn framework: localize\n  WIP: Feature demonstration\n\n advice.c                           |   16 +-\n apply.c                            |   10 +-\n apply.h                            |    4 +-\n archive.c                          |    6 +-\n attr.c                             |    3 +-\n bisect.c                           |    2 +-\n branch.c                           |    4 +-\n builtin/add.c                      |   20 +-\n builtin/am.c                       |   27 +-\n builtin/archive.c                  |   10 +-\n builtin/blame.c                    |   12 +-\n builtin/branch.c                   |   45 +-\n builtin/bundle.c                   |    4 +-\n builtin/check-ignore.c             |   14 +-\n builtin/check-mailmap.c            |    2 +-\n builtin/checkout-index.c           |    2 +-\n builtin/checkout.c                 |   27 +-\n builtin/clean.c                    |   10 +-\n builtin/clone.c                    |   39 +-\n builtin/column.c                   |    2 +-\n builtin/commit.c                   |   87 +-\n builtin/config.c                   |    2 +-\n builtin/describe.c                 |    6 +-\n builtin/diff.c                     |    2 +-\n builtin/fetch.c                    |   21 +-\n builtin/gc.c                       |    3 +-\n builtin/grep.c                     |   14 +-\n builtin/help.c                     |    4 +-\n builtin/index-pack.c               |   42 +-\n builtin/interpret-trailers.c       |    2 +-\n builtin/log.c                      |   48 +-\n builtin/merge-recursive.c          |    2 +-\n builtin/merge.c                    |   53 +-\n builtin/mv.c                       |    6 +-\n builtin/notes.c                    |   40 +-\n builtin/pack-objects.c             |    4 +-\n builtin/prune.c                    |    2 +-\n builtin/pull.c                     |   10 +-\n builtin/push.c                     |   22 +-\n builtin/remote.c                   |   10 +-\n builtin/repack.c                   |    4 +-\n builtin/replace.c                  |    2 +-\n builtin/reset.c                    |   10 +-\n builtin/rev-list.c                 |    2 +-\n builtin/rev-parse.c                |    2 +-\n builtin/revert.c                   |    4 +-\n builtin/rm.c                       |    6 +-\n builtin/shortlog.c                 |    2 +-\n builtin/show-branch.c              |    7 +-\n builtin/submodule--helper.c        |    9 +-\n builtin/tag.c                      |   20 +-\n builtin/unpack-objects.c           |    2 +-\n builtin/update-index.c             |    8 +-\n builtin/worktree.c                 |    6 +-\n bundle.c                           |    4 +-\n config.c                           |    4 +-\n connect.c                          |    6 +-\n connected.c                        |    2 +-\n contrib/coccinelle/errorl10n.cocci |   47 +\n daemon.c                           |    3 +-\n diff.c                             |    8 +-\n dir.c                              |    4 +-\n fast-import.c                      |    4 +-\n fetch-pack.c                       |   26 +-\n git-compat-util.h                  |   18 +-\n help.c                             |    2 +-\n http-backend.c                     |    4 +-\n http.c                             |    4 +-\n merge.c                            |    2 +-\n notes-utils.c                      |    2 +-\n pathspec.c                         |   13 +-\n po/de.po                           | 2922 ++++++++++++++++++++++++------------\n po/git.pot                         | 2781 ++++++++++++++++++++++------------\n pretty.c                           |    2 +-\n ref-filter.c                       |   20 +-\n remote.c                           |    2 +-\n revision.c                         |    4 +-\n run-command.c                      |    6 +-\n send-pack.c                        |   12 +-\n sequencer.c                        |    7 +-\n setup.c                            |    6 +-\n sha1_file.c                        |    2 +-\n submodule.c                        |    8 +-\n trailer.c                          |    4 +-\n transport.c                        |    2 +-\n tree-walk.c                        |    2 +-\n usage.c                            |  122 +-\n wrapper.c                          |    2 +-\n wt-status.c                        |    2 +-\n 89 files changed, 4408 insertions(+), 2374 deletions(-)\n create mode 100644 contrib/coccinelle/errorl10n.cocci\n\n-- \n2.11.0.372.g2fcea0e476\n\n"},{"id":"308615","messageId":"79ba4093dbf26b27e4f0e728ab9362c26558c1b2.1483354746.git.git@drmicha.warpmail.net","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"[RFC PATCH 1/5] error/warning framework: prepare for l10n","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2017-01-02T11:14:50Z","receivedAt":"2017-01-02T11:15:06Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Currently, errors, warnings etc. are output with a fixed prefix \"error: \"\netc. that is not subject to l10n.\n\nChange the call signatures of error_routine() etc. so that they receive\nthe prefix as first argument.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n apply.c           |  2 +-\n apply.h           |  4 ++--\n daemon.c          |  3 ++-\n fast-import.c     |  4 ++--\n git-compat-util.h | 10 +++++-----\n http-backend.c    |  4 ++--\n run-command.c     |  4 ++--\n usage.c           | 48 ++++++++++++++++++++++++------------------------\n 8 files changed, 40 insertions(+), 39 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 2ed808d429..0f93792e1c 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -112,7 +112,7 @@ void clear_apply_state(struct apply_state *state)\n \t/* &state->fn_table is cleared at the end of apply_patch() */\n }\n \n-static void mute_routine(const char *msg, va_list params)\n+static void mute_routine(const char *prefix, const char *msg, va_list params)\n {\n \t/* do nothing */\n }\ndiff --git a/apply.h b/apply.h\nindex b3d6783d55..56b5622868 100644\n--- a/apply.h\n+++ b/apply.h\n@@ -100,8 +100,8 @@ struct apply_state {\n \t * set_error_routine() or set_warn_routine() to install muting\n \t * routines when in verbosity_silent mode.\n \t */\n-\tvoid (*saved_error_routine)(const char *err, va_list params);\n-\tvoid (*saved_warn_routine)(const char *warn, va_list params);\n+\tvoid (*saved_error_routine)(const char *prefix, const char *err, va_list params);\n+\tvoid (*saved_warn_routine)(const char *prefix, const char *warn, va_list params);\n \n \t/* These control whitespace errors */\n \tenum apply_ws_error_action ws_error_action;\ndiff --git a/daemon.c b/daemon.c\nindex 473e6b6b63..cd52a25001 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -114,8 +114,9 @@ static void loginfo(const char *err, ...)\n \tva_end(params);\n }\n \n-static void NORETURN daemon_die(const char *err, va_list params)\n+static void NORETURN daemon_die(const char *prefix, const char *err, va_list params)\n {\n+\t/* no need to pass down prefix */\n \tlogreport(LOG_ERR, err, params);\n \texit(1);\n }\ndiff --git a/fast-import.c b/fast-import.c\nindex f561ba833b..4576f12163 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -496,13 +496,13 @@ static void end_packfile(void);\n static void unkeep_all_packs(void);\n static void dump_marks(void);\n \n-static NORETURN void die_nicely(const char *err, va_list params)\n+static NORETURN void die_nicely(const char *prefix, const char *err, va_list params)\n {\n \tstatic int zombie;\n \tchar message[2 * PATH_MAX];\n \n \tvsnprintf(message, sizeof(message), err, params);\n-\tfputs(\"fatal: \", stderr);\n+\tfputs(prefix, stderr);\n \tfputs(message, stderr);\n \tfputc('\\n', stderr);\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 87237b092b..f1bf0a6749 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -439,11 +439,11 @@ static inline int const_error(void)\n #define error_errno(...) (error_errno(__VA_ARGS__), const_error())\n #endif\n \n-extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));\n-extern void set_error_routine(void (*routine)(const char *err, va_list params));\n-extern void (*get_error_routine(void))(const char *err, va_list params);\n-extern void set_warn_routine(void (*routine)(const char *warn, va_list params));\n-extern void (*get_warn_routine(void))(const char *warn, va_list params);\n+extern void set_die_routine(NORETURN_PTR void (*routine)(const char *prefix, const char *err, va_list params));\n+extern void set_error_routine(void (*routine)(const char *prefix, const char *err, va_list params));\n+extern void (*get_error_routine(void))(const char *prefix, const char *err, va_list params);\n+extern void set_warn_routine(void (*routine)(const char *prefix, const char *warn, va_list params));\n+extern void (*get_warn_routine(void))(const char *prefix, const char *warn, va_list params);\n extern void set_die_is_recursing_routine(int (*routine)(void));\n extern void set_error_handle(FILE *);\n \ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4..5c235e8b52 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -577,12 +577,12 @@ static void service_rpc(struct strbuf *hdr, char *service_name)\n }\n \n static int dead;\n-static NORETURN void die_webcgi(const char *err, va_list params)\n+static NORETURN void die_webcgi(const char *prefix, const char *err, va_list params)\n {\n \tif (dead <= 1) {\n \t\tstruct strbuf hdr = STRBUF_INIT;\n \n-\t\tvreportf(\"fatal: \", err, params);\n+\t\tvreportf(prefix, err, params);\n \n \t\thttp_status(&hdr, 500, \"Internal Server Error\");\n \t\thdr_nocache(&hdr);\ndiff --git a/run-command.c b/run-command.c\nindex ca905a9e80..3133bf5320 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -618,9 +618,9 @@ static void *run_thread(void *data)\n \treturn (void *)ret;\n }\n \n-static NORETURN void die_async(const char *err, va_list params)\n+static NORETURN void die_async(const char *prefix, const char *err, va_list params)\n {\n-\tvreportf(\"fatal: \", err, params);\n+\tvreportf(prefix, err, params);\n \n \tif (in_async()) {\n \t\tstruct async *async = pthread_getspecific(async_key);\ndiff --git a/usage.c b/usage.c\nindex 17f52c1b5c..4270b04bf9 100644\n--- a/usage.c\n+++ b/usage.c\n@@ -24,26 +24,26 @@ void vreportf(const char *prefix, const char *err, va_list params)\n \tfputc('\\n', fh);\n }\n \n-static NORETURN void usage_builtin(const char *err, va_list params)\n+static NORETURN void usage_builtin(const char *prefix, const char *err, va_list params)\n {\n-\tvreportf(\"usage: \", err, params);\n+\tvreportf(prefix, err, params);\n \texit(129);\n }\n \n-static NORETURN void die_builtin(const char *err, va_list params)\n+static NORETURN void die_builtin(const char *prefix, const char *err, va_list params)\n {\n-\tvreportf(\"fatal: \", err, params);\n+\tvreportf(prefix, err, params);\n \texit(128);\n }\n \n-static void error_builtin(const char *err, va_list params)\n+static void error_builtin(const char *prefix, const char *err, va_list params)\n {\n-\tvreportf(\"error: \", err, params);\n+\tvreportf(prefix, err, params);\n }\n \n-static void warn_builtin(const char *warn, va_list params)\n+static void warn_builtin(const char *prefix, const char *warn, va_list params)\n {\n-\tvreportf(\"warning: \", warn, params);\n+\tvreportf(prefix, warn, params);\n }\n \n static int die_is_recursing_builtin(void)\n@@ -54,33 +54,33 @@ static int die_is_recursing_builtin(void)\n \n /* If we are in a dlopen()ed .so write to a global variable would segfault\n  * (ugh), so keep things static. */\n-static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;\n-static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;\n-static void (*error_routine)(const char *err, va_list params) = error_builtin;\n-static void (*warn_routine)(const char *err, va_list params) = warn_builtin;\n+static NORETURN_PTR void (*usage_routine)(const char *prefix, const char *err, va_list params) = usage_builtin;\n+static NORETURN_PTR void (*die_routine)(const char *prefix, const char *err, va_list params) = die_builtin;\n+static void (*error_routine)(const char *prefix, const char *err, va_list params) = error_builtin;\n+static void (*warn_routine)(const char *prefix, const char *err, va_list params) = warn_builtin;\n static int (*die_is_recursing)(void) = die_is_recursing_builtin;\n \n-void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))\n+void set_die_routine(NORETURN_PTR void (*routine)(const char *prefix, const char *err, va_list params))\n {\n \tdie_routine = routine;\n }\n \n-void set_error_routine(void (*routine)(const char *err, va_list params))\n+void set_error_routine(void (*routine)(const char *prefix, const char *err, va_list params))\n {\n \terror_routine = routine;\n }\n \n-void (*get_error_routine(void))(const char *err, va_list params)\n+void (*get_error_routine(void))(const char *prefix, const char *err, va_list params)\n {\n \treturn error_routine;\n }\n \n-void set_warn_routine(void (*routine)(const char *warn, va_list params))\n+void set_warn_routine(void (*routine)(const char *prefix, const char *warn, va_list params))\n {\n \twarn_routine = routine;\n }\n \n-void (*get_warn_routine(void))(const char *warn, va_list params)\n+void (*get_warn_routine(void))(const char *prefix, const char *warn, va_list params)\n {\n \treturn warn_routine;\n }\n@@ -101,7 +101,7 @@ void NORETURN usagef(const char *err, ...)\n \tva_list params;\n \n \tva_start(params, err);\n-\tusage_routine(err, params);\n+\tusage_routine(\"usage: \", err, params);\n \tva_end(params);\n }\n \n@@ -120,7 +120,7 @@ void NORETURN die(const char *err, ...)\n \t}\n \n \tva_start(params, err);\n-\tdie_routine(err, params);\n+\tdie_routine(\"fatal: \", err, params);\n \tva_end(params);\n }\n \n@@ -159,7 +159,7 @@ void NORETURN die_errno(const char *fmt, ...)\n \t}\n \n \tva_start(params, fmt);\n-\tdie_routine(fmt_with_err(buf, sizeof(buf), fmt), params);\n+\tdie_routine(\"fatal: \", fmt_with_err(buf, sizeof(buf), fmt), params);\n \tva_end(params);\n }\n \n@@ -170,7 +170,7 @@ int error_errno(const char *fmt, ...)\n \tva_list params;\n \n \tva_start(params, fmt);\n-\terror_routine(fmt_with_err(buf, sizeof(buf), fmt), params);\n+\terror_routine(\"error: \", fmt_with_err(buf, sizeof(buf), fmt), params);\n \tva_end(params);\n \treturn -1;\n }\n@@ -181,7 +181,7 @@ int error(const char *err, ...)\n \tva_list params;\n \n \tva_start(params, err);\n-\terror_routine(err, params);\n+\terror_routine(\"error: \", err, params);\n \tva_end(params);\n \treturn -1;\n }\n@@ -192,7 +192,7 @@ void warning_errno(const char *warn, ...)\n \tva_list params;\n \n \tva_start(params, warn);\n-\twarn_routine(fmt_with_err(buf, sizeof(buf), warn), params);\n+\twarn_routine(\"warning: \", fmt_with_err(buf, sizeof(buf), warn), params);\n \tva_end(params);\n }\n \n@@ -201,6 +201,6 @@ void warning(const char *warn, ...)\n \tva_list params;\n \n \tva_start(params, warn);\n-\twarn_routine(warn, params);\n+\twarn_routine(\"warning: \", warn, params);\n \tva_end(params);\n }\n-- \n2.11.0.372.g2fcea0e476\n\n"},{"id":"308616","messageId":"732991717d24d92df8e87838cff51a551e263a17.1483354746.git.git@drmicha.warpmail.net","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"[RFC PATCH 2/5] error/warn framework: provide localized variants","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2017-01-02T11:14:51Z","receivedAt":"2017-01-02T11:15:14Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Provide localized variants of error(), warning(), die() etc.\nto go along with localized messages.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n git-compat-util.h |  8 ++++++\n usage.c           | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 82 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex f1bf0a6749..48209a6c67 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -405,13 +405,21 @@ struct strbuf;\n /* General helper functions */\n extern void vreportf(const char *prefix, const char *err, va_list params);\n extern NORETURN void usage(const char *err);\n+extern NORETURN void usage_(const char *err);\n extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern NORETURN void usagef_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern NORETURN void die_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern NORETURN void die_errno_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern int error_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern int error_errno_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern void warning_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern void warning_errno_(const char *err, ...) __attribute__((format (printf, 1, 2)));\n \n #ifndef NO_OPENSSL\n #ifdef APPLE_COMMON_CRYPTO\ndiff --git a/usage.c b/usage.c\nindex 4270b04bf9..d0cfb02a64 100644\n--- a/usage.c\n+++ b/usage.c\n@@ -105,11 +105,25 @@ void NORETURN usagef(const char *err, ...)\n \tva_end(params);\n }\n \n+void NORETURN usagef_(const char *err, ...)\n+{\n+\tva_list params;\n+\n+\tva_start(params, err);\n+\tusage_routine(_(\"usage: \"), err, params);\n+\tva_end(params);\n+}\n+\n void NORETURN usage(const char *err)\n {\n \tusagef(\"%s\", err);\n }\n \n+void NORETURN usage_(const char *err)\n+{\n+\tusagef_(\"%s\", err);\n+}\n+\n void NORETURN die(const char *err, ...)\n {\n \tva_list params;\n@@ -124,6 +138,20 @@ void NORETURN die(const char *err, ...)\n \tva_end(params);\n }\n \n+void NORETURN die_(const char *err, ...)\n+{\n+\tva_list params;\n+\n+\tif (die_is_recursing()) {\n+\t\tfputs(_(\"fatal: recursion detected in die handler\\n\"), stderr);\n+\t\texit(128);\n+\t}\n+\n+\tva_start(params, err);\n+\tdie_routine(_(\"fatal: \"), err, params);\n+\tva_end(params);\n+}\n+\n static const char *fmt_with_err(char *buf, int n, const char *fmt)\n {\n \tchar str_error[256], *err;\n@@ -163,6 +191,22 @@ void NORETURN die_errno(const char *fmt, ...)\n \tva_end(params);\n }\n \n+void NORETURN die_errno_(const char *fmt, ...)\n+{\n+\tchar buf[1024];\n+\tva_list params;\n+\n+\tif (die_is_recursing()) {\n+\t\tfputs(_(\"fatal: recursion detected in die_errno handler\\n\"),\n+\t\t\tstderr);\n+\t\texit(128);\n+\t}\n+\n+\tva_start(params, fmt);\n+\tdie_routine(_(\"fatal: \"), fmt_with_err(buf, sizeof(buf), fmt), params);\n+\tva_end(params);\n+}\n+\n #undef error_errno\n int error_errno(const char *fmt, ...)\n {\n@@ -175,6 +219,17 @@ int error_errno(const char *fmt, ...)\n \treturn -1;\n }\n \n+int error_errno_(const char *fmt, ...)\n+{\n+\tchar buf[1024];\n+\tva_list params;\n+\n+\tva_start(params, fmt);\n+\terror_routine(_(\"error: \"), fmt_with_err(buf, sizeof(buf), fmt), params);\n+\tva_end(params);\n+\treturn -1;\n+}\n+\n #undef error\n int error(const char *err, ...)\n {\n@@ -186,6 +241,16 @@ int error(const char *err, ...)\n \treturn -1;\n }\n \n+int error_(const char *err, ...)\n+{\n+\tva_list params;\n+\n+\tva_start(params, err);\n+\terror_routine(_(\"error: \"), err, params);\n+\tva_end(params);\n+\treturn -1;\n+}\n+\n void warning_errno(const char *warn, ...)\n {\n \tchar buf[1024];\n@@ -204,3 +269,12 @@ void warning(const char *warn, ...)\n \twarn_routine(\"warning: \", warn, params);\n \tva_end(params);\n }\n+\n+void warning_(const char *warn, ...)\n+{\n+\tva_list params;\n+\n+\tva_start(params, warn);\n+\twarn_routine(_(\"warning: \"), warn, params);\n+\tva_end(params);\n+}\n-- \n2.11.0.372.g2fcea0e476\n\n"},{"id":"308617","messageId":"da98fec6fa421be916f169ef62353339c4273e89.1483354746.git.git@drmicha.warpmail.net","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"[RFC PATCH 3/5] error/warning framework framework: coccinelli rules","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2017-01-02T11:14:52Z","receivedAt":"2017-01-02T11:15:17Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Provide coccinelli rules which check for error(), warning() etc. with\nlocalised argument and create a patch to replace them with error_(),\nwarning_() etc. in order to fully localize them.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n contrib/coccinelle/errorl10n.cocci | 47 ++++++++++++++++++++++++++++++++++++++\n 1 file changed, 47 insertions(+)\n create mode 100644 contrib/coccinelle/errorl10n.cocci\n\ndiff --git a/contrib/coccinelle/errorl10n.cocci b/contrib/coccinelle/errorl10n.cocci\nnew file mode 100644\nindex 0000000000..d62a440644\n--- /dev/null\n+++ b/contrib/coccinelle/errorl10n.cocci\n@@ -0,0 +1,47 @@\n+@@\n+expression E;\n+@@\n+- usage(_(E));\n++ usage_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- usagef(_(E));\n++ usagef_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- die(_(E));\n++ die_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- error(_(E));\n++ error_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- warning(_(E));\n++ warning_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- die_errno(_(E));\n++ die_errno_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- error_errno(_(E));\n++ error_errno_(_(E));\n+\n+@@\n+expression E;\n+@@\n+- warning_errno(_(E));\n++ warning_errno_(_(E));\n-- \n2.11.0.372.g2fcea0e476\n\n"},{"id":"308701","messageId":"CACsJy8A123cdEn03p590Hxdg5fujdDAH3BU8s9hZmuOY6ok3sg@mail.gmail.com","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-03T12:26:41Z","receivedAt":"2017-01-03T12:33:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jan 2, 2017 at 6:14 PM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n> Currently, the headers \"error: \", \"warning: \" etc. - generated by die(),\n> warning() etc. - are not localized, but we feed many localized error messages\n> into these functions so that we produce error messages with mixed localisation.\n>\n> This series introduces variants of die() etc. that use localised variants of\n> the headers, i.e. _(\"error: \") etc., and are to be fed localized messages. So,\n> instead of die(_(\"not workee\")), which would produce a mixed localisation (such\n> as \"error: geht ned\"), one should use die_(_(\"not workee\")) (resulting in\n> \"Fehler: geht ned\").\n\nAnother option, not as thorough, but less effort, is changing\ndie/err/warn default routines to the \"porcelain\" versions where we do\n_(\"fatal:\") internally _with_ die(), not die_(). We can set this for\nporcelain commands that we know can be fully i18n-ized. Then maybe\ndie_() will fill in the gap if there's still need for it.\n-- \nDuy\n"},{"id":"308739","messageId":"CAGZ79ka-FXfFN8ZqE6+v06o3nKa7ad0iWttn99Y2wf5m6wfs8A@mail.gmail.com","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-01-03T19:45:10Z","receivedAt":"2017-01-03T19:45:17Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jan 2, 2017 at 3:14 AM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n> Currently, the headers \"error: \", \"warning: \" etc. - generated by die(),\n> warning() etc. - are not localized, but we feed many localized error messages\n> into these functions so that we produce error messages with mixed localisation.\n>\n> This series introduces variants of die() etc. that use localised variants of\n> the headers, i.e. _(\"error: \") etc., and are to be fed localized messages. So,\n> instead of die(_(\"not workee\")), which would produce a mixed localisation (such\n> as \"error: geht ned\"), one should use die_(_(\"not workee\")) (resulting in\n> \"Fehler: geht ned\").\n\nHave you considered\n\n    die_(\"non localized error here\")\n\nto produce:\n\n    \"Fehler: trotzdem uebersetzt hier\"\n    (\"error: here it is translated\")\n\n>\n> In this implementation, the gettext call for the header and the body are done\n> in different places (error function vs. caller) but this call pattern seems to\n> be the easiest variant for the caller, because the message body has to be marked\n> for localisation in any case, and N_() requires more letters than _(), an extra\n> argument to die() etc. even more than the extra \"_\" in the function name.\n\nI see. We have to markup the strings to be translatable such that the .po files\nare complete. It would be really handy if there was a way to say \"anything that\nis fed to this function (die_) needs to be marked for translation.\n\nLooking through\nhttps://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html\nsuch a thing doesn't seem to exist.\n\nSo in that case die_(_(...)) seems to be the easiest way forward.\n\nThanks,\nStefan\n"},{"id":"308762","messageId":"20170104070514.pxdthvilw66ierfz@sigill.intra.peff.net","threadId":"44805","inReplyTo":"cover.1483354746.git.git@drmicha.warpmail.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-04T07:05:14Z","receivedAt":"2017-01-04T07:05:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 02, 2017 at 12:14:49PM +0100, Michael J Gruber wrote:\n\n> Currently, the headers \"error: \", \"warning: \" etc. - generated by die(),\n> warning() etc. - are not localized, but we feed many localized error messages\n> into these functions so that we produce error messages with mixed localisation.\n> \n> This series introduces variants of die() etc. that use localised variants of\n> the headers, i.e. _(\"error: \") etc., and are to be fed localized messages. So,\n> instead of die(_(\"not workee\")), which would produce a mixed localisation (such\n> as \"error: geht ned\"), one should use die_(_(\"not workee\")) (resulting in\n> \"Fehler: geht ned\").\n\nI can't say I'm excited about having matching \"_\" variants for each\nfunction. Are we sure that they are necessary? I.e., would it be\nacceptable to just translate them always?\n\n> 1/5 prepares the error machinery\n> 2/5 provides new variants error_() etc.\n> 3/5 has coccinelli rules error(_(E)) -> error_(_(E)) etc.\n> 4/5 applies the coccinelli patches\n> \n> 5/5 is not to be applied to the main tree, but helps you try out the feature:\n> it has changes to de.po and git.pot so that e.g. \"git branch\" has fully localised\n> error messages (see the recipe in the commit message).\n\nYour patches 4 and 5 don't seem to have made it to the list. Judging\nfrom the diffstat, I'd guess they broke the 100K limit.\n\n-Peff\n"},{"id":"308770","messageId":"CACsJy8B0UT4_CF=qu081ep6nzdBXxnnNbma-wCYeajAuXaKg5w@mail.gmail.com","threadId":"44805","inReplyTo":"CAGZ79ka-FXfFN8ZqE6+v06o3nKa7ad0iWttn99Y2wf5m6wfs8A@mail.gmail.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-04T13:25:25Z","receivedAt":"2017-01-04T13:26:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jan 4, 2017 at 2:45 AM, Stefan Beller <sbeller@google.com> wrote:\n>> In this implementation, the gettext call for the header and the body are done\n>> in different places (error function vs. caller) but this call pattern seems to\n>> be the easiest variant for the caller, because the message body has to be marked\n>> for localisation in any case, and N_() requires more letters than _(), an extra\n>> argument to die() etc. even more than the extra \"_\" in the function name.\n>\n> I see. We have to markup the strings to be translatable such that the .po files\n> are complete. It would be really handy if there was a way to say \"anything that\n> is fed to this function (die_) needs to be marked for translation.\n>\n> Looking through\n> https://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html\n> such a thing doesn't seem to exist.\n\nI think --keyword is exactly for that purpose: marking more text for\ntranslations besides standard markers like _() or N_(). Yes we need to\ncall gettext() explicitly in die_() later on. We already do that for\nparse-options. We just need to N_() the strings, without actually\nspelling it out.\n\n>\n> So in that case die_(_(...)) seems to be the easiest way forward.\n\nI still prefer changing the die_routine though since die() in many\ncases could be used in both plumbing and porcelain contexts. And we\nhave tried to keep plumbing output (and behavior) as stable as\npossible. The approach has some similarity to unpack_trees() which\nshares the same porcelain/plumbing problem.\n-- \nDuy\n"},{"id":"308925","messageId":"CACsJy8ALXkkEnQPvpMx4nrPjD=fpGNDkbC_oqMrj3KRdRr_-eQ@mail.gmail.com","threadId":"44805","inReplyTo":"CACsJy8B0UT4_CF=qu081ep6nzdBXxnnNbma-wCYeajAuXaKg5w@mail.gmail.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-07T09:34:54Z","receivedAt":"2017-01-07T09:35:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jan 4, 2017 at 8:25 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Wed, Jan 4, 2017 at 2:45 AM, Stefan Beller <sbeller@google.com> wrote:\n>>> In this implementation, the gettext call for the header and the body are done\n>>> in different places (error function vs. caller) but this call pattern seems to\n>>> be the easiest variant for the caller, because the message body has to be marked\n>>> for localisation in any case, and N_() requires more letters than _(), an extra\n>>> argument to die() etc. even more than the extra \"_\" in the function name.\n>>\n>> I see. We have to markup the strings to be translatable such that the .po files\n>> are complete. It would be really handy if there was a way to say \"anything that\n>> is fed to this function (die_) needs to be marked for translation.\n>>\n>> Looking through\n>> https://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html\n>> such a thing doesn't seem to exist.\n>\n> I think --keyword is exactly for that purpose: marking more text for\n> translations besides standard markers like _() or N_(). Yes we need to\n> call gettext() explicitly in die_() later on. We already do that for\n> parse-options. We just need to N_() the strings, without actually\n> spelling it out.\n>\n>>\n>> So in that case die_(_(...)) seems to be the easiest way forward.\n>\n> I still prefer changing the die_routine though since die() in many\n> cases could be used in both plumbing and porcelain contexts. And we\n> have tried to keep plumbing output (and behavior) as stable as\n> possible. The approach has some similarity to unpack_trees() which\n> shares the same porcelain/plumbing problem.\n\nOn the other hand, making die(), not die_(), translatable means the\ntranslators will have to translate them _all_ even if only some will\nend up being displayed. That's 2000+ strings according to git-grep.\nAnd some of them, like die(\"BUG:..\") should definitely not be\ntranslated. So +1 to die_(), unless we decide all strings are safe to\ntranslate.\n-- \nDuy\n"},{"id":"309029","messageId":"8d0966d0-1ef1-3d1e-95f5-6e6c1ad50536@drmicha.warpmail.net","threadId":"44805","inReplyTo":"20170104070514.pxdthvilw66ierfz@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2017-01-09T12:43:15Z","receivedAt":"2017-01-09T12:43:25Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jeff King venit, vidit, dixit 04.01.2017 08:05:\n> On Mon, Jan 02, 2017 at 12:14:49PM +0100, Michael J Gruber wrote:\n> \n>> Currently, the headers \"error: \", \"warning: \" etc. - generated by die(),\n>> warning() etc. - are not localized, but we feed many localized error messages\n>> into these functions so that we produce error messages with mixed localisation.\n>>\n>> This series introduces variants of die() etc. that use localised variants of\n>> the headers, i.e. _(\"error: \") etc., and are to be fed localized messages. So,\n>> instead of die(_(\"not workee\")), which would produce a mixed localisation (such\n>> as \"error: geht ned\"), one should use die_(_(\"not workee\")) (resulting in\n>> \"Fehler: geht ned\").\n> \n> I can't say I'm excited about having matching \"_\" variants for each\n> function. Are we sure that they are necessary? I.e., would it be\n> acceptable to just translate them always?\n\nWe would still need to mark the strings, e.g.\n\ndie(N_(\"oopsie\"));\n\nand would not be able to opt out of translating in the code (only in the\npo file, by not providing a translation).\n\n\n>> 1/5 prepares the error machinery\n>> 2/5 provides new variants error_() etc.\n>> 3/5 has coccinelli rules error(_(E)) -> error_(_(E)) etc.\n>> 4/5 applies the coccinelli patches\n>>\n>> 5/5 is not to be applied to the main tree, but helps you try out the feature:\n>> it has changes to de.po and git.pot so that e.g. \"git branch\" has fully localised\n>> error messages (see the recipe in the commit message).\n> \n> Your patches 4 and 5 don't seem to have made it to the list. Judging\n> from the diffstat, I'd guess they broke the 100K limit.\n\nHmmpf, I didn't know about the limit. In any case, they were simple\nresults of applying the \"make cocci\" patches (4/5) resp. providing some\n\"de\" strings to try this out.\n\nIn any case, the question is whether we want to tell the user\n\nA: B\n\nwhere A is in English and B is localised, or rather localise both A and\nB (for A in \"error\", \"fatal\", \"warning\"...).\n\nFor localising A and B, we'd need this series or something similar. For\nkeeping the mix, we don't need to do anything ;)\n\nMichael\n\n"},{"id":"309130","messageId":"20170110090418.4egk4oflblshmjon@sigill.intra.peff.net","threadId":"44805","inReplyTo":"8d0966d0-1ef1-3d1e-95f5-6e6c1ad50536@drmicha.warpmail.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-10T09:04:18Z","receivedAt":"2017-01-10T09:04:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 09, 2017 at 01:43:15PM +0100, Michael J Gruber wrote:\n\n> > I can't say I'm excited about having matching \"_\" variants for each\n> > function. Are we sure that they are necessary? I.e., would it be\n> > acceptable to just translate them always?\n> \n> We would still need to mark the strings, e.g.\n> \n> die(N_(\"oopsie\"));\n> \n> and would not be able to opt out of translating in the code (only in the\n> po file, by not providing a translation).\n\nI meant more along the lines of: would it be OK to just always translate\nthe prefix, even if the message itself is not translated? I.e.,\n\ndiff --git a/usage.c b/usage.c\nindex 82ff13163..8e5400f57 100644\n--- a/usage.c\n+++ b/usage.c\n@@ -32,7 +32,7 @@ static NORETURN void usage_builtin(const char *err, va_list params)\n \n static NORETURN void die_builtin(const char *err, va_list params)\n {\n-\tvreportf(\"fatal: \", err, params);\n+\tvreportf(_(\"fatal: \"), err, params);\n \texit(128);\n }\n\n> In any case, the question is whether we want to tell the user\n> \n> A: B\n> \n> where A is in English and B is localised, or rather localise both A and\n> B (for A in \"error\", \"fatal\", \"warning\"...).\n> \n> For localising A and B, we'd need this series or something similar. For\n> keeping the mix, we don't need to do anything ;)\n\nWhat I wrote above would keep the mix, but switch it in the other\ndirection.\n\nAnd then presumably that mix would gradually move to 100% consistency as\nmore messages are translated. But the implicit question is: are there\ndie() messages that should never be translated? I'm not sure.\n\n-Peff\n"},{"id":"309149","messageId":"CAGZ79kYVc0YQ4okrTHGiYQzPqfiVAm_f7orXdkhwgf5kMPXj-w@mail.gmail.com","threadId":"44805","inReplyTo":"20170110090418.4egk4oflblshmjon@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-01-10T18:28:42Z","receivedAt":"2017-01-10T18:32:29Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Jan 10, 2017 at 1:04 AM, Jeff King <peff@peff.net> wrote:\n> On Mon, Jan 09, 2017 at 01:43:15PM +0100, Michael J Gruber wrote:\n>\n>> > I can't say I'm excited about having matching \"_\" variants for each\n>> > function. Are we sure that they are necessary? I.e., would it be\n>> > acceptable to just translate them always?\n>>\n>> We would still need to mark the strings, e.g.\n>>\n>> die(N_(\"oopsie\"));\n>>\n>> and would not be able to opt out of translating in the code (only in the\n>> po file, by not providing a translation).\n>\n> I meant more along the lines of: would it be OK to just always translate\n> the prefix, even if the message itself is not translated? I.e.,\n>\n> diff --git a/usage.c b/usage.c\n> index 82ff13163..8e5400f57 100644\n> --- a/usage.c\n> +++ b/usage.c\n> @@ -32,7 +32,7 @@ static NORETURN void usage_builtin(const char *err, va_list params)\n>\n>  static NORETURN void die_builtin(const char *err, va_list params)\n>  {\n> -       vreportf(\"fatal: \", err, params);\n> +       vreportf(_(\"fatal: \"), err, params);\n>         exit(128);\n>  }\n>\n>> In any case, the question is whether we want to tell the user\n>>\n>> A: B\n>>\n>> where A is in English and B is localised, or rather localise both A and\n>> B (for A in \"error\", \"fatal\", \"warning\"...).\n>>\n>> For localising A and B, we'd need this series or something similar. For\n>> keeping the mix, we don't need to do anything ;)\n>\n> What I wrote above would keep the mix, but switch it in the other\n> direction.\n>\n> And then presumably that mix would gradually move to 100% consistency as\n> more messages are translated. But the implicit question is: are there\n> die() messages that should never be translated? I'm not sure.\n\nI would assume any plumbing command is not localizing?\nBecause in plumbing land, (easily scriptable) you may find\na grep on the output/stderr for a certain condition?\n\nTo find a good example, \"git grep die\" giving me some food of though:\n\ndie_errno(..) should always take a string marked up for translation,\nbecause the errno string is translated?\n(-> we'd have to fix up any occurrence of git grep \"die_errno(\\\"\")\n\n    apply.c:                die(_(\"internal error\"));\n\nThat is funny, too. I think we should substitute that with\n\n    die(\"BUG: untranslated, but what went wrong instead\")\n\n\n>\n> -Peff\n"},{"id":"309209","messageId":"20170111113725.avl3wetwrfezdni2@sigill.intra.peff.net","threadId":"44805","inReplyTo":"CAGZ79kYVc0YQ4okrTHGiYQzPqfiVAm_f7orXdkhwgf5kMPXj-w@mail.gmail.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-11T11:37:25Z","receivedAt":"2017-01-11T11:37:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jan 10, 2017 at 10:28:42AM -0800, Stefan Beller wrote:\n\n> > And then presumably that mix would gradually move to 100% consistency as\n> > more messages are translated. But the implicit question is: are there\n> > die() messages that should never be translated? I'm not sure.\n> \n> I would assume any plumbing command is not localizing?\n> Because in plumbing land, (easily scriptable) you may find\n> a grep on the output/stderr for a certain condition?\n\nThat's the assumption I'm challenging. Certainly the behavior and\ncertain aspects of the output of a plumbing command should remain the\nsame over time. But error messages to stderr?\n\nIt seems like they should be translated, because plumbing invoked on\nbehalf of porcelain scripts is going to send its stderr directly to the\nuser.\n\n> To find a good example, \"git grep die\" giving me some food of though:\n> \n> die_errno(..) should always take a string marked up for translation,\n> because the errno string is translated?\n\nYes, I would think die_errno() is a no-brainer for translation, since\nthe strerror() will be translated.\n\n>     apply.c:                die(_(\"internal error\"));\n> \n> That is funny, too. I think we should substitute that with\n> \n>     die(\"BUG: untranslated, but what went wrong instead\")\n\nYep. We did not consistently use \"BUG:\" in the early days. I would say\nthat \"BUG\" lines do not need to be translated. The point is that nobody\nshould ever see them, so it seems like there is little point in giving\nextra work to translators.\n\n-Peff\n"},{"id":"309218","messageId":"CAGZ79kYVFbaMy1_-6qqe9zYQyktE2-7xu1Zz_qyeLWK=scgFKQ@mail.gmail.com","threadId":"44805","inReplyTo":"20170111113725.avl3wetwrfezdni2@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-01-11T17:15:22Z","receivedAt":"2017-01-11T17:15:34Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Jan 11, 2017 at 3:37 AM, Jeff King <peff@peff.net> wrote:\n> On Tue, Jan 10, 2017 at 10:28:42AM -0800, Stefan Beller wrote:\n>\n>> > And then presumably that mix would gradually move to 100% consistency as\n>> > more messages are translated. But the implicit question is: are there\n>> > die() messages that should never be translated? I'm not sure.\n>>\n>> I would assume any plumbing command is not localizing?\n>> Because in plumbing land, (easily scriptable) you may find\n>> a grep on the output/stderr for a certain condition?\n>\n> That's the assumption I'm challenging. Certainly the behavior and\n> certain aspects of the output of a plumbing command should remain the\n> same over time. But error messages to stderr?\n\nIn an ideal world that assumption would hold true and any machine\nreadable information from the plumbing commands are on stdout and\nnobody in their sane mind would ever try to parse stderr.\n\nThere is no easy way to check though except auditing all the code.\nHaving pointed out some string handling mistakes in the prior email,\nmy confidence is not high that plumbing commands are that strict about\nseparating useful machine output and errors for human consumption.\n\n>\n> It seems like they should be translated, because plumbing invoked on\n> behalf of porcelain scripts is going to send its stderr directly to the\n> user.\n\nWell that could be solved, c.f. unpack-trees.c lines 15-55.\n\nAs another data point (coming from that area of strings):\nIf you grep for these plumbing strings in the project,\ni.e.\n$ git grep \"would be overwritten by merge. Cannot merge\"\n$ git grep \"not uptodate. Cannot merge.\"\n...\n\nyou only find the occurrence in the  unpack-trees.c lines 15-55,\nwhich means our test suite at least doesn't grep for error messages\nbut relies on the exit code of plumbing commands(?!)\n\n>\n>> To find a good example, \"git grep die\" giving me some food of though:\n>>\n>> die_errno(..) should always take a string marked up for translation,\n>> because the errno string is translated?\n>\n> Yes, I would think die_errno() is a no-brainer for translation, since\n> the strerror() will be translated.\n>\n>>     apply.c:                die(_(\"internal error\"));\n>>\n>> That is funny, too. I think we should substitute that with\n>>\n>>     die(\"BUG: untranslated, but what went wrong instead\")\n>\n> Yep. We did not consistently use \"BUG:\" in the early days. I would say\n> that \"BUG\" lines do not need to be translated. The point is that nobody\n> should ever see them, so it seems like there is little point in giving\n> extra work to translators.\n>\n> -Peff\n"},{"id":"309221","messageId":"xmqq1sw9piz5.fsf@gitster.mtv.corp.google.com","threadId":"44805","inReplyTo":"20170111113725.avl3wetwrfezdni2@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-01-11T18:08:46Z","receivedAt":"2017-01-11T18:08:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Yes, I would think die_errno() is a no-brainer for translation, since\n> the strerror() will be translated.\n>\n>>     apply.c:                die(_(\"internal error\"));\n>> \n>> That is funny, too. I think we should substitute that with\n>> \n>>     die(\"BUG: untranslated, but what went wrong instead\")\n>\n> Yep. We did not consistently use \"BUG:\" in the early days. I would say\n> that \"BUG\" lines do not need to be translated. The point is that nobody\n> should ever see them, so it seems like there is little point in giving\n> extra work to translators.\n\nIn addition, \"BUG: \" is relatively recent introduction to our\ncodebase.  Perhaps having a separate BUG(<string>) function help the\ndistinction further?\n"},{"id":"309824","messageId":"CACsJy8BRdd4f7f7+7XyN8jd69GS6tnkEGhw05F=7c96eViRVQg@mail.gmail.com","threadId":"44805","inReplyTo":"xmqq1sw9piz5.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-20T13:08:43Z","receivedAt":"2017-01-20T13:09:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jan 12, 2017 at 1:08 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jeff King <peff@peff.net> writes:\n>\n>> Yes, I would think die_errno() is a no-brainer for translation, since\n>> the strerror() will be translated.\n>>\n>>>     apply.c:                die(_(\"internal error\"));\n>>>\n>>> That is funny, too. I think we should substitute that with\n>>>\n>>>     die(\"BUG: untranslated, but what went wrong instead\")\n>>\n>> Yep. We did not consistently use \"BUG:\" in the early days. I would say\n>> that \"BUG\" lines do not need to be translated. The point is that nobody\n>> should ever see them, so it seems like there is little point in giving\n>> extra work to translators.\n>\n> In addition, \"BUG: \" is relatively recent introduction to our\n> codebase.  Perhaps having a separate BUG(<string>) function help the\n> distinction further?\n\nI was going to write the same thing. On top of that I wonder if have\nenough \"if (something) die(\"BUG:\")\" to justify stealing BUG_ON() from\nkernel (better than assert since the condition will always be\nevaluated).\n-- \nDuy\n"},{"id":"309825","messageId":"20170120132322.GA23030@ash","threadId":"44805","inReplyTo":"20170111113725.avl3wetwrfezdni2@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-20T13:23:22Z","receivedAt":"2017-01-20T13:23:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jan 11, 2017 at 06:37:25AM -0500, Jeff King wrote:\n> > To find a good example, \"git grep die\" giving me some food of though:\n> > \n> > die_errno(..) should always take a string marked up for translation,\n> > because the errno string is translated?\n> \n> Yes, I would think die_errno() is a no-brainer for translation, since\n> the strerror() will be translated.\n\nI agree. And the main (*) changes are relative simple too. I've tested\nit a bit. Seems to work ok.\n\n-- 8< --\ndiff --git a/Makefile b/Makefile\nindex d861bd9985..6f88c6cac5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2102,7 +2102,7 @@ XGETTEXT_FLAGS = \\\n \t--msgid-bugs-address=\"Git Mailing List <git@vger.kernel.org>\" \\\n \t--from-code=UTF-8\n XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n-\t--keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n+\t--keyword=_ --keyword=N_ --keyword=\"Q_:1,2\" --keyword=die_errno\n XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \\\n \t--keyword=gettextln --keyword=eval_gettextln\n XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\ndiff --git a/usage.c b/usage.c\nindex 17f52c1b5c..c022726f9c 100644\n--- a/usage.c\n+++ b/usage.c\n@@ -159,7 +159,7 @@ void NORETURN die_errno(const char *fmt, ...)\n \t}\n \n \tva_start(params, fmt);\n-\tdie_routine(fmt_with_err(buf, sizeof(buf), fmt), params);\n+\tdie_routine(fmt_with_err(buf, sizeof(buf), _(fmt)), params);\n \tva_end(params);\n }\n \n-- 8< --\n\n(*) We would need another patch to remove _() from die_errno(_(..)).\nBut that's something I expect coccinelle to be excel at.\n--\nDuy\n"},{"id":"309827","messageId":"CACsJy8BacMqxfN=LO-LV+tJy39or8U0w_trwLOnZy+hZpkya-Q@mail.gmail.com","threadId":"44805","inReplyTo":"20170120132322.GA23030@ash","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-20T13:31:31Z","receivedAt":"2017-01-20T13:41:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jan 20, 2017 at 8:23 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> I've tested it a bit. Seems to work ok.\n\nOops. Didn't notice that the \"fatal:\" bit is still untranslated but\nMicheal's patch can handle that.\n-- \nDuy\n"},{"id":"309894","messageId":"20170121141942.lc4pw3ck3nzxbozv@sigill.intra.peff.net","threadId":"44805","inReplyTo":"CACsJy8BRdd4f7f7+7XyN8jd69GS6tnkEGhw05F=7c96eViRVQg@mail.gmail.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-21T14:19:43Z","receivedAt":"2017-01-21T14:19:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 20, 2017 at 08:08:43PM +0700, Duy Nguyen wrote:\n\n> > In addition, \"BUG: \" is relatively recent introduction to our\n> > codebase.  Perhaps having a separate BUG(<string>) function help the\n> > distinction further?\n> \n> I was going to write the same thing. On top of that I wonder if have\n> enough \"if (something) die(\"BUG:\")\" to justify stealing BUG_ON() from\n> kernel (better than assert since the condition will always be\n> evaluated).\n\nI don't mind BUG_ON() as an improvement over assert(). However, one of\nthe things I really like about our current die(\"BUG\") is that you\nactually write a human-readable message. Quite often that serves as a\ncomment to the reader of the code as to what is going on, or you can\ngive additional context in the error message (e.g., which sha1 triggered\nthe bug).\n\nStill, there are many cases where there's not much to say in the\nmessage. Doing:\n\n  if (!foo)\n\tBUG(\"foo is NULL in this function\");\n\nis just wasting everybody's time. Something like:\n\n  #define BUG_ON(code) do {\n\tif (code)\n\t\tBUG(\"%s\", #code);\n  while(0)\n\nis probably fine. One complication is that BUG() would ideally show the\nfile/line number. That has to happen in a macro, but we don't assume\nvariadic macros work everywhere, which we need for the printf-like\nbehavior. So either we have to loosen that restriction[1], or we end up\nwith two \"tiers\": a BUG(fmt, ...) for human-readable messages, and a\nmore boring version for BUG_ON() which just prints \"file:line: BUG:\n<code>\".\n\n-Peff\n\n[1] I think avoiding variadic macros was reasonable in 2005; C99 was\n    only 6 years old then. Now it's turning 18. Maybe it's time?\n"},{"id":"309895","messageId":"20170121142048.ygbwc65un4whhtwn@sigill.intra.peff.net","threadId":"44805","inReplyTo":"xmqq1sw9piz5.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-21T14:20:48Z","receivedAt":"2017-01-21T14:21:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 11, 2017 at 10:08:46AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > Yes, I would think die_errno() is a no-brainer for translation, since\n> > the strerror() will be translated.\n> >\n> >>     apply.c:                die(_(\"internal error\"));\n> >> \n> >> That is funny, too. I think we should substitute that with\n> >> \n> >>     die(\"BUG: untranslated, but what went wrong instead\")\n> >\n> > Yep. We did not consistently use \"BUG:\" in the early days. I would say\n> > that \"BUG\" lines do not need to be translated. The point is that nobody\n> > should ever see them, so it seems like there is little point in giving\n> > extra work to translators.\n> \n> In addition, \"BUG: \" is relatively recent introduction to our\n> codebase.  Perhaps having a separate BUG(<string>) function help the\n> distinction further?\n\nYes, I think so. I have often been tempted to dump core on BUGs for\nfurther analysis. You can do that by string-matching \"BUG:\" from the\nbeginning of a die message, but it's kind of gross. :)\n\n-Peff\n"},{"id":"309896","messageId":"20170121142455.qoyqagaw4atic5n6@sigill.intra.peff.net","threadId":"44805","inReplyTo":"CAGZ79kYVFbaMy1_-6qqe9zYQyktE2-7xu1Zz_qyeLWK=scgFKQ@mail.gmail.com","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-21T14:24:56Z","receivedAt":"2017-01-21T14:25:02Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 11, 2017 at 09:15:22AM -0800, Stefan Beller wrote:\n\n> > That's the assumption I'm challenging. Certainly the behavior and\n> > certain aspects of the output of a plumbing command should remain the\n> > same over time. But error messages to stderr?\n> \n> In an ideal world that assumption would hold true and any machine\n> readable information from the plumbing commands are on stdout and\n> nobody in their sane mind would ever try to parse stderr.\n> \n> There is no easy way to check though except auditing all the code.\n> Having pointed out some string handling mistakes in the prior email,\n> my confidence is not high that plumbing commands are that strict about\n> separating useful machine output and errors for human consumption.\n\nI think it's impossible to audit all the code, because \"all the code\"\nincludes things not in git itself. It would really take a willingness to\ndeclare \"if you are parsing stderr you're doing it wrong\".\n\nI suppose the unpack-trees example speaks against that. I'm not sure\nthat is sane overall, but it is something we tried to account for in the\npast.\n\nIf we are just talking about translation, though, it seems like the\nright action for a script that really wants to parse stderr is to run\nthe sub-command with LC_MESSAGES=C. I know that's a breaking change, but\nI wonder if it's a reasonable path forward.\n\n-Peff\n"},{"id":"315775","messageId":"76f61fea-3d24-ec55-0cbc-64ee3d030dcf@grubix.eu","threadId":"44805","inReplyTo":"20170121142048.ygbwc65un4whhtwn@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Michael J Gruber","fromEmail":"git@grubix.eu","sentAt":"2017-03-30T15:18:59Z","receivedAt":"2017-03-30T15:19:14Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jeff King venit, vidit, dixit 21.01.2017 15:20:\n> On Wed, Jan 11, 2017 at 10:08:46AM -0800, Junio C Hamano wrote:\n> \n>> Jeff King <peff@peff.net> writes:\n>>\n>>> Yes, I would think die_errno() is a no-brainer for translation, since\n>>> the strerror() will be translated.\n>>>\n>>>>     apply.c:                die(_(\"internal error\"));\n>>>>\n>>>> That is funny, too. I think we should substitute that with\n>>>>\n>>>>     die(\"BUG: untranslated, but what went wrong instead\")\n>>>\n>>> Yep. We did not consistently use \"BUG:\" in the early days. I would say\n>>> that \"BUG\" lines do not need to be translated. The point is that nobody\n>>> should ever see them, so it seems like there is little point in giving\n>>> extra work to translators.\n>>\n>> In addition, \"BUG: \" is relatively recent introduction to our\n>> codebase.  Perhaps having a separate BUG(<string>) function help the\n>> distinction further?\n> \n> Yes, I think so. I have often been tempted to dump core on BUGs for\n> further analysis. You can do that by string-matching \"BUG:\" from the\n> beginning of a die message, but it's kind of gross. :)\n> \n> -Peff\n\nI read back the whole thread, and I'm still not sure if there's\nconsensus and how to go forward. Should we let the topic die? I don't\ncare too much personally, I just thought the mixed tranlations look\n\"unprofessional\".\n\nMichael\n\n"},{"id":"315999","messageId":"20170401081256.fupby6oo5yf7wqdz@sigill.intra.peff.net","threadId":"44805","inReplyTo":"76f61fea-3d24-ec55-0cbc-64ee3d030dcf@grubix.eu","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-04-01T08:12:56Z","receivedAt":"2017-04-01T08:13:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 30, 2017 at 05:18:59PM +0200, Michael J Gruber wrote:\n\n> Jeff King venit, vidit, dixit 21.01.2017 15:20:\n> > On Wed, Jan 11, 2017 at 10:08:46AM -0800, Junio C Hamano wrote:\n> > \n> >> Jeff King <peff@peff.net> writes:\n> >>\n> >>> Yes, I would think die_errno() is a no-brainer for translation, since\n> >>> the strerror() will be translated.\n> >>>\n> >>>>     apply.c:                die(_(\"internal error\"));\n> >>>>\n> >>>> That is funny, too. I think we should substitute that with\n> >>>>\n> >>>>     die(\"BUG: untranslated, but what went wrong instead\")\n> >>>\n> >>> Yep. We did not consistently use \"BUG:\" in the early days. I would say\n> >>> that \"BUG\" lines do not need to be translated. The point is that nobody\n> >>> should ever see them, so it seems like there is little point in giving\n> >>> extra work to translators.\n> >>\n> >> In addition, \"BUG: \" is relatively recent introduction to our\n> >> codebase.  Perhaps having a separate BUG(<string>) function help the\n> >> distinction further?\n> > \n> > Yes, I think so. I have often been tempted to dump core on BUGs for\n> > further analysis. You can do that by string-matching \"BUG:\" from the\n> > beginning of a die message, but it's kind of gross. :)\n> > \n> > -Peff\n> \n> I read back the whole thread, and I'm still not sure if there's\n> consensus and how to go forward. Should we let the topic die? I don't\n> care too much personally, I just thought the mixed tranlations look\n> \"unprofessional\".\n\nI don't have a strong preference either way. I also don't care\npersonally about the output (as I do not localize at all). My main\nconcern was keeping the code simple for developers. But if consistent\ntranslation is important for people in other languages, I'm OK with\nwhatever we need to do.\n\n-Peff\n"},{"id":"316012","messageId":"xmqq1stcvxih.fsf@gitster.mtv.corp.google.com","threadId":"44805","inReplyTo":"20170401081256.fupby6oo5yf7wqdz@sigill.intra.peff.net","subject":"Re: [RFC PATCH 0/5] Localise error headers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-01T17:38:30Z","receivedAt":"2017-04-01T17:38:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Mar 30, 2017 at 05:18:59PM +0200, Michael J Gruber wrote:\n>\n>> I read back the whole thread, and I'm still not sure if there's\n>> consensus and how to go forward. Should we let the topic die? I don't\n>> care too much personally, I just thought the mixed tranlations look\n>> \"unprofessional\".\n>\n> I don't have a strong preference either way. I also don't care\n> personally about the output (as I do not localize at all). My main\n> concern was keeping the code simple for developers. But if consistent\n> translation is important for people in other languages, I'm OK with\n> whatever we need to do.\n\n (0) I do not mind the status quo, and I do not mind telling an end\n     user who comes here with a translated message from die() to try\n     running it again in C locale, either.\n\n (1) I do not think messages (including prefix) from die(),\n     warning(), and error() are sacred, even when they are given by\n     plumbing commands.  If the list concensus is that we want to\n     see all translated in the ideal endgame, I think it is OK not\n     to special case the plumbing.\n\n (2) I found your\n\n         vreportf(_(\"fatal: \"), err, params);\n\n     a reasonable approach, if the we all agree with (1) as our\n     goal, and want a way to gradually get us closer to the\n     \"everything translated\" endgame.\n\nI do not know what is professional and what is not in this context,\nthough ;-).\n\nMichael, thanks for pinging the thread.\n"}]}