unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Juri Linkov <juri@linkov.net>
To: Eli Zaretskii <eliz@gnu.org>
Cc: rms@gnu.org, emacs-devel@gnu.org
Subject: Re: Emacs i18n
Date: Sun, 03 Mar 2019 22:57:51 +0200	[thread overview]
Message-ID: <87h8cjspc0.fsf@mail.linkov.net> (raw)
In-Reply-To: <83h8ckezyt.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 03 Mar 2019 17:31:54 +0200")

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

>> It seems pretty good.  When installing it, it should not use
>> `advice-add'.  Rather, `message' should call a list of functions.
>
> Unfortunately, past discussions didn't lead to any significant
> progress wrt this.

My intention was to fix the bug which manifests itself in
grammatically incorrect sentences displayed by ‘message’ like

  Deleted 1 matching lines
  1 matches found
  ...

After searching for available packages I found only this page
https://savannah.nongnu.org/projects/emacs-i18n
that shows no progress for many years.

So here is a patch that fixes the bug by translating currently
invalid messages into grammatically correct English.  It also
opens the gate towards translation of messages in many languages.
Currently this feature is activated by (require 'i18n-message):

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: i18n-message.patch --]
[-- Type: text/x-diff, Size: 10283 bytes --]

diff --git a/lisp/replace.el b/lisp/replace.el
index 59ad1a375b..b05bb51353 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -986,6 +986,12 @@ flush-lines
     (when interactive (message "Deleted %d matching lines" count))
     count))
 
+(eval-after-load "i18n-message"
+  '(i18n-add-translation "English"
+                         "Deleted %d matching lines"
+                         '("Deleted %d matching line"
+                           "Deleted %d matching lines")))
+
 (defun how-many (regexp &optional rstart rend interactive)
   "Print and return number of matches for REGEXP following point.
 When called from Lisp and INTERACTIVE is omitted or nil, just return
@@ -1032,11 +1038,15 @@ how-many
 	(if (= opoint (point))
 	    (forward-char 1)
 	  (setq count (1+ count))))
-      (when interactive (message "%d occurrence%s"
-				 count
-				 (if (= count 1) "" "s")))
+      (when interactive (message "%d occurrences" count))
       count)))
 
+(eval-after-load "i18n-message"
+  '(i18n-add-translation "English"
+                         "%d occurrences"
+                         '("%d occurrence"
+                           "%d occurrences")))
+
 \f
 (defvar occur-menu-map
   (let ((map (make-sparse-keymap)))
@@ -2730,10 +2740,7 @@ perform-replace
                                            (1+ num-replacements))))))
                              (when (and (eq def 'undo-all)
                                         (null (zerop num-replacements)))
-                               (message "Undid %d %s" num-replacements
-                                        (if (= num-replacements 1)
-                                            "replacement"
-                                          "replacements"))
+                               (message "Undid %d replacements" num-replacements)
                                (ding 'no-terminate)
                                (sit-for 1)))
 			   (setq replaced nil last-was-undo t last-was-act-and-show nil)))
@@ -2859,9 +2866,8 @@ perform-replace
                       last-was-act-and-show     nil))))))
       (replace-dehighlight))
     (or unread-command-events
-	(message "Replaced %d occurrence%s%s"
+	(message "Replaced %d occurrences%s"
 		 replace-count
-		 (if (= replace-count 1) "" "s")
 		 (if (> (+ skip-read-only-count
 			   skip-filtered-count
 			   skip-invisible-count)
@@ -2883,6 +2889,16 @@ perform-replace
 		   "")))
     (or (and keep-going stack) multi-buffer)))
 
+(eval-after-load "i18n-message"
+  '(i18n-add-translations
+    "English"
+    '(("Undid %d replacements"
+       ("Undid %d replacement"
+        "Undid %d replacements"))
+      ("Replaced %d occurrences%s"
+       ("Replaced %d occurrence%s"
+        "Replaced %d occurrences%s")))))
+
 (provide 'replace)
 
 ;;; replace.el ends here
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 3fd2a7e701..d2d748fca3 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -459,7 +459,7 @@ grep-mode-font-lock-keywords
      ;; remove match from grep-regexp-alist before fontifying
      ("^Grep[/a-zA-z]* started.*"
       (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
-     ("^Grep[/a-zA-z]* finished with \\(?:\\(\\(?:[0-9]+ \\)?matches found\\)\\|\\(no matches found\\)\\).*"
+     ("^Grep[/a-zA-z]* finished with \\(?:\\(\\(?:[0-9]+ \\)?match\\(?:es\\)? found\\)\\|\\(no matches found\\)\\).*"
       (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
       (1 compilation-info-face nil t)
       (2 compilation-warning-face nil t))
@@ -561,6 +561,12 @@ grep-exit-message
 	     (cons msg code)))
     (cons msg code)))
 
+(eval-after-load "i18n-message"
+  '(i18n-add-translation "English"
+                         "finished with %d matches found\n"
+                         '("finished with %d match found\n"
+                           "finished with %d matches found\n")))
+
 (defun grep-filter ()
   "Handle match highlighting escape sequences inserted by the grep process.
 This function is called from `compilation-filter-hook'."
diff --git a/lisp/international/i18n-message.el b/lisp/international/i18n-message.el
new file mode 100644
index 0000000000..14755966e0
--- /dev/null
+++ b/lisp/international/i18n-message.el
@@ -0,0 +1,118 @@
+;;; i18n-message.el --- internationalization of messages  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; Author: Juri Linkov <juri@linkov.net>
+;; Maintainer: emacs-devel@gnu.org
+;; Keywords: i18n, multilingual
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(defcustom i18n-fallbacks
+  '(("en" "English"))
+  "An alist mapping the current language to possible fallbacks.
+Each element should look like (\"LANG\" . FALLBACK-LIST), where
+FALLBACK-LIST is a list of languages to try to find a translation."
+  :type '(alist :key-type (string :tag "Current language")
+                :value-type (repeat :tag "A list of fallbacks" string))
+  :group 'i18n
+  :version "27.1")
+
+(defvar i18n-dictionaries (make-hash-table :test 'equal))
+
+(defun i18n-add-dictionary (lang)
+  (unless (gethash lang i18n-dictionaries)
+    (puthash lang (make-hash-table :test 'equal) i18n-dictionaries)))
+
+;;;###autoload
+(defun i18n-add-translation (lang from to)
+  (let ((dict (gethash lang i18n-dictionaries)))
+    (unless dict
+      (setq dict (i18n-add-dictionary lang)))
+    (puthash from to dict)))
+
+;;;###autoload
+(defun i18n-add-translations (lang translations)
+  (dolist (translation translations)
+    (i18n-add-translation lang (nth 0 translation) (nth 1 translation))))
+
+(defun i18n-get-plural (lang n)
+  ;; Source: (info "(gettext) Plural forms")
+  (pcase lang
+    ((or "Japanese" "Vietnamese" "Korean" "Thai")
+     0)
+    ((or "English" "German" "Dutch" "Swedish" "Danish" "Norwegian"
+         "Faroese" "Spanish" "Portuguese" "Italian" "Bulgarian" "Greek"
+         "Finnish" "Estonian" "Hebrew" "Bahasa Indonesian" "Esperanto"
+         "Hungarian" "Turkish")
+     (if (/= n 1) 1 0))
+    ((or "Brazilian Portuguese" "French")
+     (if (> n 1) 1 0))
+    ((or "Latvian")
+     (if (and (= (% n 10) 1) (/= (% n 100) 11)) 0 (if (/= n 0) 1 2)))
+    ((or "Gaeilge" "Irish")
+     (if (= n 1) 0 (if (= n 2) 1 2)))
+    ((or "Romanian")
+     (if (= n 1) 0 (if (or (= n 0) (and (> (% n 100) 0) (< (% n 100) 20))) 1 2)))
+    ((or "Lithuanian")
+     (if (and (= (% n 10) 1) (/= (% n 100) 11)) 0
+       (if (and (>= (% n 10) 2) (or (< (% n 100) 10) (>= (% n 100) 20))) 1 2)))
+    ((or "Russian" "Ukrainian" "Belarusian" "Serbian" "Croatian")
+     (if (and (= (% n 10) 1) (/= (% n 100) 11)) 0
+       (if (and (>= (% n 10) 2) (<= (% n 10) 4) (or (< (% n 100) 10) (>= (% n 100) 20))) 1 2)))
+    ((or "Czech" "Slovak")
+     (if (= n 1) 0 (if (and (>= n 2) (<= n 4)) 1 2)))
+    ((or "Polish")
+     (if (= n 1) 0
+       (if (and (>= (% n 10) 2) (<= (% n 10) 4) (or (< (% n 100) 10) (>= (% n 100) 20))) 1 2)))
+    ((or "Slovenian")
+     (if (= (% n 100) 1) 0 (if (= (% n 100) 2) 1 (if (or (= (% n 100) 3) (= (% n 100) 4)) 2 3))))
+    ((or "Arabic")
+     (if (= n 0) 0 (if (= n 1) 1 (if (= n 2) 2 (if (and (>= (% n 100) 3) (<= (% n 100) 10)) 3
+                                                 (if (>= (% n 100) 11) 4 5))))))))
+
+(defun i18n-get-translation (format-string &rest args)
+  (let* ((lang current-language-environment)
+	 (fallbacks (cdr (assoc lang i18n-fallbacks)))
+	 dict found)
+    (while (and (not found) lang)
+      (when (setq dict (gethash lang i18n-dictionaries))
+	(setq found
+              (pcase (gethash format-string dict)
+		((and (pred functionp) f) (apply f format-string args))
+		((and (pred stringp) s) s)
+		((and (pred consp) l)
+		 (let ((n (i18n-get-plural lang (car args))))
+		   (when n (nth n l)))))))
+      (unless found
+	(setq lang (pop fallbacks))))
+    (or found format-string)))
+
+(defun i18n-message-translate (&rest args)
+  (apply 'i18n-get-translation args))
+
+(defvar message-translate-function)
+
+(setq message-translate-function 'i18n-message-translate)
+
+(provide 'i18n-message)
+;;; i18n-message.el ends here
diff --git a/src/editfns.c b/src/editfns.c
index bffb5db43e..f517679576 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3050,6 +3050,14 @@ produced text.
 usage: (format STRING &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
+  if (!NILP (Vmessage_translate_function) && nargs > 0)
+    {
+      Lisp_Object format = apply1 (Vmessage_translate_function,
+				   Flist (nargs, args));
+      if (STRINGP (format))
+	args[0] = format;
+    }
+
   return styled_format (nargs, args, false);
 }
 
@@ -3066,6 +3074,14 @@ and right quote replacement characters are specified by
 usage: (format-message STRING &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
+  if (!NILP (Vmessage_translate_function) && nargs > 0)
+    {
+      Lisp_Object format = apply1 (Vmessage_translate_function,
+				   Flist (nargs, args));
+      if (STRINGP (format))
+	args[0] = format;
+    }
+
   return styled_format (nargs, args, true);
 }
 
@@ -4462,6 +4478,11 @@ of the buffer being accessed.  */);
 functions if all the text being accessed has this property.  */);
   Vbuffer_access_fontified_property = Qnil;
 
+  DEFVAR_LISP ("message-translate-function",
+	       Vmessage_translate_function,
+	       doc: /* Function that translates messages.  */);
+  Vmessage_translate_function = Qnil;
+
   DEFVAR_LISP ("system-name", Vsystem_name,
 	       doc: /* The host name of the machine Emacs is running on.  */);
   Vsystem_name = cached_system_name = Qnil;

  reply	other threads:[~2019-03-03 20:57 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               ` Juri Linkov [this message]
2019-03-04  1:46                 ` Emacs i18n 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
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=87h8cjspc0.fsf@mail.linkov.net \
    --to=juri@linkov.net \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --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).