unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Paul Eggert <eggert@cs.ucla.edu>
To: Eli Zaretskii <eliz@gnu.org>, rms@gnu.org
Cc: juri@linkov.net, emacs-devel@gnu.org
Subject: Re: Emacs i18n
Date: Thu, 7 Mar 2019 09:19:35 -0800	[thread overview]
Message-ID: <f85826bb-e85b-1f18-3194-3220675ccfe9@cs.ucla.edu> (raw)
In-Reply-To: <83o96mbv4l.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 3615 bytes --]

On 3/7/19 6:46 AM, Eli Zaretskii wrote:

>> From: Richard Stallman <rms@gnu.org> Cc: eggert@cs.ucla.edu,
>> emacs-devel@gnu.org, juri@linkov.net Date: Wed, 06 Mar 2019 22:42:06
>> -0500 > If we do that, how do we deal with strings that are computed
>> by > concatenation or formatting? Feed them in through %s or
>> something like that.
>>
> But then the strings that are formatted via %s will not be translated,
> they will remain in English.
>
Yes, but the scenario you describe should not occur in a properly
internationalized GNU application. We obviously can't assume that
Emacs's translation subroutine acts like Google Translate and can
translate any English-language string to the user's language. All we can
assume is that the translation subroutine converts one of a fixed set of
English-language strings to a string appropriate for the user's language.

This limitation will cause problems with Elisp code that does extensive
parsing or processing of English syntax (doctor.el, say), and that sort
of Elisp code will remain English-only (unless someone takes the time to
i18nize them specially). However most Elisp code does not parse English
or generate idiomatic English on the fly: instead, it uses a fixed,
stilted style that can routinely be converted to calls like (message
FORMAT ARG1 ARG2 ...) where FORMAT is translated and the ARG values are not.

To get a quick feel for this issue, I did a simple grep for the string
'(message (concat' in the Emacs source code. I found 41 instances of
this string. Of these, 8 were erroneous because the result of the
concatenation could contain an unwanted "%" or '`' that could cause
'message' to go awry, and I fixed them by installing the attached patch
(by the way, it's routine for i18n efforts to find trivial bugs like
this). The other 33 instances could easily be reworded to do proper i18n
when 'message' translates just its first argument and only simple,
xgettext-style static analysis is used to find the message strings. For
example, this code in calc-do-embedded:

  (message (concat
            "Embedded Calc mode enabled; "
            (if calc-embedded-quiet
                "Type `C-x * x'"
              "Give this command again")
            " to return to normal"))

can easily be rewritten to this:

   (if calc-embedded-quiet
       "Embedded Calc mode enabled; Type `C-x * x' to return to normal"
     "Embedded Calc mode enabled; Give this command again to return to
normal"))

which is easier for translators to grok, and is arguably clearer even if
we don't want to translate at all.Obviously my '(message (concat'
exercises only a small part of the problem, but the results of this
little sample are encouraging.

So this problem is solvable. Sure, it'll require substantial work, but
the work is routine and this sort of thing has been done for other packages.

The main argument against doing all this is that it's too much work
overall and nobody will have the time to do it all, so let's not even
bother. I have some sympathy for this argument, as i18n is clearly too
much work for any single contributor and the work will distract us from
other things. On the other hand, there's no pressing need to do all the
work quickly, it's a low-level task that can be farmed out to non-expert
volunteers that could conceivably grow the volunteer population, and if
we never even start the work then it will never get done and Emacs will
remain unfriendly to users who don't grok English.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Be-safer-about-in-message-formats.patch --]
[-- Type: text/x-patch; name="0001-Be-safer-about-in-message-formats.patch", Size: 7751 bytes --]

From f15d0d0247ffe7bc3bbd5fbe10271c93b2e2fb1c Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 7 Mar 2019 09:02:15 -0800
Subject: [PATCH] Be safer about "%" in message formats
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lisp/calc/calc-store.el (calc-copy-special-constant):
* lisp/net/rcirc.el (rcirc-handler-PART, rcirc-handler-KICK):
* lisp/org/org-agenda.el (org-agenda):
* lisp/org/org-clock.el (org-clock-out, org-clock-display):
* lisp/org/org.el (org-refile):
* lisp/progmodes/ada-xref.el (ada-goto-declaration):
* lisp/progmodes/idlwave.el (idlwave-scan-library-catalogs):
Don’t trust arbitrary strings to not contain "%" or "`" in
(message (concat STRING1 STRING2 ...)).
---
 lisp/calc/calc-store.el    |  4 ++--
 lisp/net/rcirc.el          |  4 ++--
 lisp/org/org-agenda.el     | 13 ++++++-------
 lisp/org/org-clock.el      | 22 ++++++++++++----------
 lisp/org/org.el            |  3 ++-
 lisp/progmodes/ada-xref.el |  3 +--
 lisp/progmodes/idlwave.el  |  7 +++----
 7 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/lisp/calc/calc-store.el b/lisp/calc/calc-store.el
index 589a776c41..3987c129c2 100644
--- a/lisp/calc/calc-store.el
+++ b/lisp/calc/calc-store.el
@@ -405,8 +405,8 @@ calc-copy-special-constant
                                     sconst))))
        (if var
            (let ((msg (calc-store-value var value "")))
-             (message (concat "Special constant \"%s\" copied to \"%s\"" msg)
-                      sconst (calc-var-name var)))))))))
+	     (message "Special constant \"%s\" copied to \"%s\"%s"
+		      sconst (calc-var-name var) msg))))))))
 
 (defun calc-copy-variable (&optional var1 var2)
   (interactive)
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index b1a6c1ce8d..9d53cd4436 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -2685,7 +2685,7 @@ rcirc-handler-PART-or-KICK
 (defun rcirc-handler-PART (process sender args _text)
   (let* ((channel (car args))
 	 (reason (cadr args))
-	 (message (concat channel " " reason)))
+	 (message "%s %s" channel reason))
     (rcirc-print process sender "PART" channel message)
     ;; print in private chat buffer if it exists
     (when (rcirc-get-buffer (rcirc-buffer-process) sender)
@@ -2697,7 +2697,7 @@ rcirc-handler-KICK
   (let* ((channel (car args))
 	 (nick (cadr args))
 	 (reason (nth 2 args))
-	 (message (concat nick " " channel " " reason)))
+	 (message "%s %s %s" nick channel reason))
     (rcirc-print process sender "KICK" channel message t)
     ;; print in private chat buffer if it exists
     (when (rcirc-get-buffer (rcirc-buffer-process) nick)
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index e416f5f062..23ee8d71e6 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -2882,13 +2882,12 @@ org-agenda
 	     (let* ((m (org-agenda-get-any-marker))
 		    (note (and m (org-entry-get m "THEFLAGGINGNOTE"))))
 	       (when note
-		 (message (concat
-			   "FLAGGING-NOTE ([?] for more info): "
-			   (org-add-props
-			       (replace-regexp-in-string
-				"\\\\n" "//"
-				(copy-sequence note))
-			       nil 'face 'org-warning)))))))
+		 (message "FLAGGING-NOTE ([?] for more info): %s"
+			  (org-add-props
+			   (replace-regexp-in-string
+			    "\\\\n" "//"
+			    (copy-sequence note))
+			   nil 'face 'org-warning))))))
 	 t t))
        ((equal org-keys "#") (call-interactively 'org-agenda-list-stuck-projects))
        ((equal org-keys "/") (call-interactively 'org-occur-in-agenda-files))
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index 34b694d487..62c7cd92d1 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -1622,9 +1622,10 @@ org-clock-out
 						"\\>"))))
 		  (org-todo org-clock-out-switch-to-state))))))
 	  (force-mode-line-update)
-	  (message (concat "Clock stopped at %s after "
-			   (org-duration-from-minutes (+ (* 60 h) m)) "%s")
-		   te (if remove " => LINE REMOVED" ""))
+	  (message (if remove
+		       "Clock stopped at %s after %s => LINE REMOVED"
+		     "Clock stopped at %s after %s")
+		   te (org-duration-from-minutes (+ (* 60 h) m)))
 	  (run-hooks 'org-clock-out-hook)
 	  (unless (org-clocking-p)
 	    (setq org-clock-current-task nil)))))))
@@ -1925,13 +1926,14 @@ org-clock-display
 		    nil 'local))))
     (let* ((h (/ org-clock-file-total-minutes 60))
 	   (m (- org-clock-file-total-minutes (* 60 h))))
-      (message (concat (format "Total file time%s: "
-			       (cond (todayp " for today")
-				     (customp " (custom)")
-				     (t "")))
-		       (org-duration-from-minutes
-			org-clock-file-total-minutes)
-		       " (%d hours and %d minutes)")
+      (message (cond
+		(todayp
+		 "Total file time for today: %s (%d hours and %d minutes)")
+		(customp
+		 "Total file time (custom): %s (%d hours and %d minutes)")
+		(t
+		 "Total file time: %s (%d hours and %d minutes)"))
+	       (org-duration-from-minutes org-clock-file-total-minutes)
 	       h m))))
 
 (defvar-local org-clock-overlays nil)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 3a434d12df..e3c78ae90d 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -11878,7 +11878,8 @@ org-refile
 	    (when (featurep 'org-inlinetask)
 	      (org-inlinetask-remove-END-maybe))
 	    (setq org-markers-to-move nil)
-	    (message (concat actionmsg " to \"%s\" in file %s: done") (car it) file)))))))
+	    (message "%s to \"%s\" in file %s: done" actionmsg
+		     (car it) file)))))))
 
 (defun org-refile-goto-last-stored ()
   "Go to the location where the last refile was stored."
diff --git a/lisp/progmodes/ada-xref.el b/lisp/progmodes/ada-xref.el
index 28c52b0653..c9c923e1d6 100644
--- a/lisp/progmodes/ada-xref.el
+++ b/lisp/progmodes/ada-xref.el
@@ -1133,8 +1133,7 @@ ada-goto-declaration
 	(ada-find-in-ali identlist other-frame)
       ;; File not found: print explicit error message
       (ada-error-file-not-found
-       (message (concat (error-message-string err)
-			(nthcdr 1 err))))
+       (message "%s%s" (error-message-string err) (nthcdr 1 err)))
 
       (error
        (let ((ali-file (ada-get-ali-file-name (ada-file-of identlist))))
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index 476d935e8a..25bc788ffc 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -5588,7 +5588,7 @@ idlwave-scan-library-catalogs
 	     (mapcar 'car idlwave-path-alist)))
 	  (old-libname "")
 	  dir-entry dir catalog all-routines)
-      (if message-base (message message-base))
+      (if message-base (message "%s" message-base))
       (while (setq dir (pop dirs))
 	(catch 'continue
 	  (when (file-readable-p
@@ -5603,8 +5603,7 @@ idlwave-scan-library-catalogs
 		     message-base
 		     (not (string= idlwave-library-catalog-libname
 				   old-libname)))
-		(message "%s" (concat message-base
-				      idlwave-library-catalog-libname))
+		(message "%s%s" message-base idlwave-library-catalog-libname)
 		(setq old-libname idlwave-library-catalog-libname))
 	      (when idlwave-library-catalog-routines
 		(setq all-routines
@@ -5618,7 +5617,7 @@ idlwave-scan-library-catalogs
 		       (setq dir-entry (assoc dir idlwave-path-alist)))
 	      (idlwave-path-alist-add-flag dir-entry 'lib)))))
       (unless no-load (setq idlwave-library-catalog-routines all-routines))
-      (if message-base (message (concat message-base "done"))))))
+      (if message-base (message "%sdone" message-base)))))
 
 ;;----- Communicating with the Shell -------------------
 
-- 
2.20.1


  reply	other threads:[~2019-03-07 17:19 UTC|newest]

Thread overview: 161+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <87o97aq6gz.fsf@jidanni.org>
     [not found] ` <87tvgoud56.fsf@mail.linkov.net>
     [not found]   ` <83o96wk2mi.fsf@gnu.org>
     [not found]     ` <87k1hjfvjd.fsf@mail.linkov.net>
     [not found]       ` <E1gzZKP-0000kS-Iw@fencepost.gnu.org>
     [not found]         ` <871s3p0zdz.fsf@mail.linkov.net>
2019-03-03  3:04           ` bug#34520: delete-matching-lines should report how many lines it deleted Richard Stallman
2019-03-03 15:31             ` Emacs i18n (was: bug#34520: delete-matching-lines should report how many lines it deleted) Eli Zaretskii
2019-03-03 20:57               ` Emacs i18n Juri Linkov
2019-03-04  1:46                 ` Jean-Christophe Helary
2019-03-06  9:38                   ` Elias Mårtenson
2019-03-06 11:23                     ` Jean-Christophe Helary
2019-03-21 20:33                   ` Clément Pit-Claudel
2019-03-21 20:50                     ` Eli Zaretskii
2019-03-21 21:03                       ` Clément Pit-Claudel
2019-03-21 21:21                         ` Jean-Christophe Helary
2019-03-21 21:34                           ` Clément Pit-Claudel
2019-03-21 21:56                             ` Jean-Christophe Helary
2019-03-21 22:05                               ` Clément Pit-Claudel
2019-03-21 23:46                                 ` Jean-Christophe Helary
2019-03-22  8:22                         ` Eli Zaretskii
2019-03-22 16:10                           ` Clément Pit-Claudel
2019-03-22 16:35                             ` Eli Zaretskii
2019-03-22 17:16                               ` Clément Pit-Claudel
2019-03-22 17:35                                 ` Eli Zaretskii
2019-03-22 23:17                                   ` Clément Pit-Claudel
2019-03-21 21:17                     ` Jean-Christophe Helary
2019-03-21 21:59                     ` Juri Linkov
2019-03-22  8:22                       ` Eli Zaretskii
2019-03-23 21:50                         ` Juri Linkov
2019-03-24  3:36                           ` Eli Zaretskii
2019-03-24 21:55                             ` Juri Linkov
2019-03-24 23:31                               ` Jean-Christophe Helary
2019-03-25 21:32                                 ` Juri Linkov
2019-03-25 22:31                                   ` Paul Eggert
2019-03-26 16:11                                     ` Eli Zaretskii
2019-03-26 16:22                                       ` Stefan Monnier
2019-03-26 16:55                                         ` Eli Zaretskii
2019-03-26 22:35                                       ` Paul Eggert
2019-03-27  3:43                                         ` Eli Zaretskii
2019-03-28 14:56                                           ` Clément Pit-Claudel
2019-03-28 15:52                                             ` Eli Zaretskii
2019-03-27  2:34                                       ` Jean-Christophe Helary
2019-03-26 23:16                                     ` Juri Linkov
2019-03-27  1:35                                       ` Paul Eggert
2019-04-24  6:39                                       ` Jean-Christophe Helary
2019-04-24 20:18                                         ` Juri Linkov
2019-03-25  3:35                               ` Eli Zaretskii
2019-03-25  9:04                                 ` Jean-Christophe Helary
2019-03-25 21:02                                 ` Juri Linkov
2019-03-26  3:27                                   ` Eli Zaretskii
2019-03-27 23:06                                     ` Richard Stallman
2019-03-25 10:52                               ` Mattias Engdegård
2019-03-25 15:37                                 ` Eli Zaretskii
2019-03-25 21:11                                 ` Juri Linkov
2019-03-25 22:05                                   ` Mattias Engdegård
2019-03-27 21:22                                     ` Juri Linkov
2019-03-28 11:03                                       ` Mattias Engdegård
2019-03-04  3:27               ` Emacs i18n (was: bug#34520: delete-matching-lines should report how many lines it deleted) Richard Stallman
2019-03-04 16:36                 ` Eli Zaretskii
2019-03-04 18:37                   ` Paul Eggert
2019-03-04 19:07                     ` Eli Zaretskii
2019-03-05  2:09                       ` Paul Eggert
2019-03-05 21:58                         ` Emacs i18n Juri Linkov
2019-03-06  2:16                           ` Richard Stallman
2019-03-06 18:15                             ` Eli Zaretskii
2019-03-06 19:47                               ` Paul Eggert
2019-03-06 20:19                                 ` Eli Zaretskii
2019-03-07  1:52                                   ` Paul Eggert
2019-03-07  3:37                                     ` Eli Zaretskii
2019-03-08  4:07                                       ` Richard Stallman
2019-03-08  8:16                                         ` Eli Zaretskii
2019-03-08  4:07                                 ` Richard Stallman
2019-03-08  4:33                                   ` Elias Mårtenson
2019-03-08  8:22                                     ` Eli Zaretskii
2019-03-09  3:11                                     ` Richard Stallman
2019-03-09  7:54                                       ` Paul Eggert
2019-03-09 10:30                                         ` Eli Zaretskii
2019-03-10  3:05                                         ` Richard Stallman
2019-03-10  6:07                                           ` Paul Eggert
2019-03-11  1:20                                             ` Richard Stallman
2019-03-11  3:52                                               ` Paul Eggert
2019-03-12  3:31                                                 ` Richard Stallman
2019-03-12  3:31                                                 ` Richard Stallman
2019-03-10  8:45                                           ` Yuri Khan
2019-03-10  3:05                                         ` Richard Stallman
2019-03-10  6:14                                           ` Paul Eggert
2019-03-10  3:05                                         ` Richard Stallman
2019-03-07  3:42                               ` Richard Stallman
2019-03-07 14:46                                 ` Eli Zaretskii
2019-03-07 17:19                                   ` Paul Eggert [this message]
2019-03-07 18:24                                     ` martin rudalics
2019-03-07 18:44                                       ` Paul Eggert
2019-03-07 20:22                                     ` Eli Zaretskii
2019-03-07 22:25                                       ` Paul Eggert
2019-03-08  7:29                                         ` Eli Zaretskii
2019-03-08  4:18                                       ` Richard Stallman
2019-03-08  4:11                                   ` Richard Stallman
2019-03-06 17:30                           ` Eli Zaretskii
2019-03-06 18:09                           ` Eli Zaretskii
2019-03-06 19:39                             ` Paul Eggert
2019-03-06 19:49                               ` Eli Zaretskii
2019-03-07  1:33                                 ` Paul Eggert
2019-03-07  3:30                                   ` Eli Zaretskii
2019-03-07 16:06                                     ` Paul Eggert
2019-03-07  4:35                                   ` Jean-Christophe Helary
2019-03-07 16:04                                     ` Paul Eggert
2019-03-08  4:09                                     ` Richard Stallman
2019-03-11 21:48                                     ` Juri Linkov
2019-03-11 22:51                                       ` Paul Eggert
2019-03-12 21:45                                         ` Juri Linkov
2019-03-17 21:23                                           ` Juri Linkov
2019-03-18 21:20                                             ` Juri Linkov
2019-03-18 21:55                                               ` Paul Eggert
2019-03-19 20:40                                                 ` Juri Linkov
2019-03-11 23:59                                       ` Jean-Christophe Helary
2019-03-12  9:16                                       ` Michael Albinus
2019-03-06 19:47                             ` Paul Eggert
2019-03-06 20:21                               ` Eli Zaretskii
2019-03-07  1:43                                 ` Paul Eggert
2019-03-07  3:31                                   ` Eli Zaretskii
2019-03-07  3:44                             ` Richard Stallman
2019-03-07 14:48                               ` Eli Zaretskii
2019-03-07 22:29                                 ` Juri Linkov
2019-03-08  1:48                                   ` Jean-Christophe Helary
2019-03-08  8:08                                     ` Eli Zaretskii
2019-03-08 15:11                                       ` Jean-Christophe Helary
2019-03-08 20:11                                         ` Eli Zaretskii
2019-03-09  2:44                                           ` Jean-Christophe Helary
2019-03-09  6:40                                             ` Eli Zaretskii
2019-03-09  8:37                                               ` Michael Albinus
2019-03-09 10:45                                                 ` Eli Zaretskii
2019-03-09 11:27                                                   ` Michael Albinus
2019-03-09 17:23                                                     ` Eli Zaretskii
2019-03-09 19:55                                                       ` Paul Eggert
2019-03-09 20:07                                                         ` Eli Zaretskii
2019-03-09 20:47                                                           ` Paul Eggert
2019-03-09 20:04                                                       ` Michael Albinus
2019-03-09 20:14                                                         ` Eli Zaretskii
2019-03-09 19:22                                                     ` Paul Eggert
2019-03-09 19:39                                                       ` Eli Zaretskii
2019-03-09 20:48                                                         ` Paul Eggert
2019-03-09 20:08                                                       ` Michael Albinus
2019-03-10  3:09                                                       ` Richard Stallman
2019-03-10 13:38                                                         ` Eli Zaretskii
2019-03-08  7:37                                   ` Eli Zaretskii
2019-03-09  3:12                                     ` Richard Stallman
2019-03-08  4:11                                 ` Richard Stallman
2019-03-06  2:09                         ` Emacs i18n (was: bug#34520: delete-matching-lines should report how many lines it deleted) Richard Stallman
2019-03-05  2:49                       ` Richard Stallman
2019-03-05  3:31                         ` Eli Zaretskii
2019-03-20 11:59 Emacs i18n Bruno Haible
2019-03-20 16:36 ` Paul Eggert
2019-03-20 21:32 ` Juri Linkov
2019-03-21  2:14   ` Richard Stallman
     [not found]     ` <E1h6nE3-0000bt-SW-iW7gFb+/I3LZHJUXO5efmti2O/JbrIOy@public.gmane.org>
2019-03-21 21:45       ` Juri Linkov
2019-03-23  2:28         ` Richard Stallman
2019-03-23  7:55           ` Yuri Khan
     [not found]             ` <CAP_d_8WjQwAtcWCfkjXHtc-dqYyBfnaP0+9L8KK6eCp4r_ZsPQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2019-03-23 17:50               ` Ineiev
2019-03-24  1:43               ` Richard Stallman
     [not found]           ` <E1h7WOF-0006T8-Be-iW7gFb+/I3LZHJUXO5efmti2O/JbrIOy@public.gmane.org>
2019-03-23 21:48             ` Juri Linkov
2019-03-24  1:47               ` Richard Stallman
2019-03-22 20:50       ` Chusslove Illich
     [not found]   ` <87h8bx5ijn.fsf-i9wRM+HIrmlRTR8OWt4JRw@public.gmane.org>
2019-03-21  2:55     ` Bruno Haible
2019-03-21  2:14 ` Richard Stallman
2019-03-22  1:26   ` Bruno Haible
2019-03-23  2:29     ` Richard Stallman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f85826bb-e85b-1f18-3194-3220675ccfe9@cs.ucla.edu \
    --to=eggert@cs.ucla.edu \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=juri@linkov.net \
    --cc=rms@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).