diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index c0ecb0447f..c493d95fba 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -468,13 +468,13 @@ This is, approximately, the inverse of `version-to-list'.
           (push (int-to-string num) str-list)
           (push "." str-list))
          ((< num -4)
-          (error "Invalid version list `%s'" vlist))
+          (error "Invalid version list `%s'." vlist))
          (t
           ;; pre, or beta, or alpha
           (cond ((equal "." (car str-list))
                  (pop str-list))
                 ((not (string-match "[0-9]+" (car str-list)))
-                 (error "Invalid version list `%s'" vlist)))
+                 (error "Invalid version list `%s'." vlist)))
           (push (cond ((= num -1) "pre")
                       ((= num -2) "beta")
                       ((= num -3) "alpha")
@@ -494,7 +494,7 @@ This is, approximately, the inverse of `version-to-list'.
     (`single ".el")
     (`tar ".tar")
     (`dir "")
-    (kind (error "Unknown package kind: %s" kind))))
+    (kind (error "Unknown package kind: %s." kind))))
 
 (defun package-desc--keywords (pkg-desc)
   (let ((keywords (cdr (assoc :keywords (package-desc-extras pkg-desc)))))
@@ -581,7 +581,7 @@ loaded and/or activated, customize `package-load-list'.")
         (goto-char (point-min))
         (let ((pkg-desc (or (package-process-define-package
                              (read (current-buffer)))
-                            (error "Can't find define-package in %s" pkg-file))))
+                            (error "Can't find define-package in %s." pkg-file))))
           (setf (package-desc-dir pkg-desc) pkg-dir)
           (if (file-exists-p signed-file)
               (setf (package-desc-signed pkg-desc) t))
@@ -635,7 +635,7 @@ Return the max version (as a string) if the package is held at a lower version."
           ((stringp force)              ; held
            (unless (version-list-= version (version-to-list force))
              force))
-          (t (error "Invalid element in `package-load-list'")))))
+          (t (error "Invalid element in `package-load-list'.")))))
 
 (defun package-built-in-p (package &optional min-version)
   "Return true if PACKAGE is built-in to Emacs.
@@ -664,7 +664,7 @@ PKG-DESC is a `package-desc' object."
   (let* ((old-lp load-path)
          (pkg-dir (package-desc-dir pkg-desc))
          (pkg-dir-dir (file-name-as-directory pkg-dir)))
-    (with-demoted-errors "Error loading autoloads: %s"
+    (with-demoted-errors "Error loading autoloads: %s."
       (load (package--autoloads-file-name pkg-desc) nil t))
     (when (and (eq old-lp load-path)
                (not (or (member pkg-dir load-path)
@@ -706,7 +706,7 @@ correspond to previously loaded files (those returned by
   (let* ((name (package-desc-name pkg-desc))
          (pkg-dir (package-desc-dir pkg-desc)))
     (unless pkg-dir
-      (error "Internal error: unable to find directory for `%s'"
+      (error "Internal error: unable to find directory for `%s'."
              (package-desc-full-name pkg-desc)))
     ;; Activate its dependencies recursively.
     ;; FIXME: This doesn't check whether the activated version is the
@@ -714,7 +714,7 @@ correspond to previously loaded files (those returned by
     (when deps
       (dolist (req (package-desc-reqs pkg-desc))
         (unless (package-activate (car req))
-          (error "Unable to activate package `%s'.\nRequired package `%s-%s' is unavailable"
+          (error "Unable to activate package `%s'.\nRequired package `%s-%s' is unavailable."
                  name (car req) (package-version-join (cadr req))))))
     (package--load-files-for-activation pkg-desc reload)
     ;; Add info node.
@@ -819,7 +819,7 @@ untar into a directory named DIR; otherwise, signal an error."
             ;; directories with a trailing slash (Bug#13136).
             (and (string-equal dir name)
                  (eq (tar-header-link-type tar-data) 5))
-            (error "Package does not untar cleanly into directory %s/" dir)))))
+            (error "Package does not untar cleanly into directory %s/." dir)))))
   (tar-untar-buffer))
 
 (defun package--alist-to-plist-args (alist)
@@ -855,13 +855,13 @@ untar into a directory named DIR; otherwise, signal an error."
        (let ((el-file (expand-file-name (format "%s.el" name) pkg-dir)))
          (make-directory pkg-dir t)
          (package--write-file-no-coding el-file)))
-      (kind (error "Unknown package kind: %S" kind)))
+      (kind (error "Unknown package kind: %S." kind)))
     (package--make-autoloads-and-stuff pkg-desc pkg-dir)
     ;; Update package-alist.
     (let ((new-desc (package-load-descriptor pkg-dir)))
       (unless (equal (package-desc-full-name new-desc)
                      (package-desc-full-name pkg-desc))
-        (error "The retrieved package (`%s') doesn't match what the archive offered (`%s')"
+        (error "The retrieved package (`%s') doesn't match what the archive offered (`%s')."
                (package-desc-full-name new-desc) (package-desc-full-name pkg-desc)))
       ;; Activation has to be done before compilation, so that if we're
       ;; upgrading and macros have changed we load the new definitions
@@ -968,7 +968,7 @@ Signal an error if the entire string was not used."
                      t)
             (end-of-file nil))))
     (if more-left
-        (error "Can't read whole string")
+        (error "Can't read whole string.")
       (car read-data))))
 
 (defun package--prepare-dependencies (deps)
@@ -979,12 +979,12 @@ of \"0\" (meaning any version) and an appropriate level of lists
 is wrapped around any parts requiring it."
   (cond
    ((not (listp deps))
-    (error "Invalid requirement specifier: %S" deps))
+    (error "Invalid requirement specifier: %S." deps))
    (t (mapcar (lambda (dep)
                 (cond
                  ((symbolp dep) `(,dep "0"))
                  ((stringp dep)
-                  (error "Invalid requirement specifier: %S" dep))
+                  (error "Invalid requirement specifier: %S." dep))
                  ((and (listp dep) (null (cdr dep)))
                   (list (car dep) "0"))
                  (t dep)))
@@ -1003,12 +1003,12 @@ error.  If there is a package, narrow the buffer to the file's
 boundaries."
   (goto-char (point-min))
   (unless (re-search-forward "^;;; \\([^ ]*\\)\\.el ---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ \t]*\\)?$" nil t)
-    (error "Package lacks a file header"))
+    (error "Package lacks a file header."))
   (let ((file-name (match-string-no-properties 1))
         (desc      (match-string-no-properties 2))
         (start     (line-beginning-position)))
     (unless (search-forward (concat ";;; " file-name ".el ends here"))
-      (error "Package lacks a terminating comment"))
+      (error "Package lacks a terminating comment."))
     ;; Try to include a trailing newline.
     (forward-line)
     (narrow-to-region start (point))
@@ -1023,7 +1023,7 @@ boundaries."
            (homepage (lm-homepage)))
       (unless pkg-version
         (error
-            "Package lacks a \"Version\" or \"Package-Version\" header"))
+            "Package lacks a \"Version\" or \"Package-Version\" header."))
       (package-desc-from-define
        file-name pkg-version desc
        (if requires-str
@@ -1060,11 +1060,11 @@ The return result is a `package-desc'."
          (desc-file (package--description-file dir-name))
          (tar-desc (tar-get-file-descriptor (concat dir-name desc-file))))
     (unless tar-desc
-      (error "No package descriptor file found"))
+      (error "No package descriptor file found."))
     (with-current-buffer (tar--extract tar-desc)
       (unwind-protect
           (or (package--read-pkg-desc 'tar)
-              (error "Can't find define-package in %s"
+              (error "Can't find define-package in %s."
                 (tar-header-name tar-desc)))
         (kill-buffer (current-buffer))))))
 
@@ -1089,7 +1089,7 @@ The return result is a `package-desc'."
               ;; set the 'dir kind,
               (setf (package-desc-kind info) 'dir))))
         (unless info
-          (error "No .el files with package headers in `%s'" default-directory))
+          (error "No .el files with package headers in `%s'." default-directory))
         ;; and return the info.
         info))))
 
@@ -1149,7 +1149,7 @@ buffer is killed afterwards.  Return the last value in BODY."
      (if (string-match-p "\\`https?:" ,location)
          (url-insert-file-contents (concat ,location ,file))
        (unless (file-name-absolute-p ,location)
-         (error "Archive location %s is not an absolute file name"
+         (error "Archive location %s is not an absolute file name."
            ,location))
        (insert-file-contents (expand-file-name ,file ,location)))
      ,@body))
@@ -1191,11 +1191,11 @@ errors signaled by ERROR-FORM or by BODY).
                                                    (require 'url-handlers)
                                                    (unless-error ,body
                                                                  (when-let ((er (plist-get status :error)))
-                                                                   (error "Error retrieving: %s %S" ,url-sym er))
+                                                                   (error "Error retrieving: %s %S." ,url-sym er))
                                                                  (with-current-buffer ,b-sym
                                                                    (goto-char (point-min))
                                                                    (unless (search-forward-regexp "^\r?\n\r?" nil 'noerror)
-                                                                     (error "Error retrieving: %s %S" ,url-sym "incomprehensible buffer")))
+                                                                     (error "Error retrieving: %s %S." ,url-sym "incomprehensible buffer")))
                                                                  (url-insert-buffer-contents ,b-sym ,url-sym)
                                                                  (kill-buffer ,b-sym)
                                                                  (goto-char (point-min)))))
@@ -1205,7 +1205,7 @@ errors signaled by ERROR-FORM or by BODY).
            (unless-error ,body
                          (let ((url (expand-file-name ,file ,url-1)))
                            (unless (file-name-absolute-p url)
-                             (error "Location %s is not a url nor an absolute file name" url))
+                             (error "Location %s is not a url nor an absolute file name." url))
                            (insert-file-contents url))))))))
 
 (define-error 'bad-signature "Failed to verify signature")
@@ -1268,7 +1268,7 @@ else, even if an error is signaled."
                       (funcall callback nil))
                     (when unwind (funcall unwind))
                     (unless allow-unsigned
-                      (error "Unsigned file `%s' at %s" file location)))
+                      (error "Unsigned file `%s' at %s." file location)))
       ;; OTOH, an error here means "bad signature", which we never
       ;; suppress.  (Bug#22089)
       (unwind-protect
@@ -1397,7 +1397,7 @@ Will throw an error if the archive version is too new."
           (insert-file-contents filename))
         (let ((contents (read (current-buffer))))
           (if (> (car contents) package-archive-version)
-              (error "Package archive version %d is higher than %d"
+              (error "Package archive version %d is higher than %d."
                 (car contents) package-archive-version))
           (cdr contents))))))
 
@@ -1510,7 +1510,7 @@ Once it's empty, run `package--post-download-archives-hook'."
     (package--build-compatibility-table)
     ;; We message before running the hook, so the hook can give
     ;; messages as well.
-    (message "Package refresh done")
+    (message "Package refresh done.")
     (run-hooks 'package--post-download-archives-hook)))
 
 (defun package--download-one-archive (archive file &optional async)
@@ -1578,7 +1578,7 @@ downloads in the background."
     (when (and package-check-signature (file-exists-p default-keyring))
       (condition-case-unless-debug error
           (package-import-keyring default-keyring)
-        (error (message "Cannot import default keyring: %S" (cdr error))))))
+        (error (message "Cannot import default keyring: %S." (cdr error))))))
   (package--download-and-read-archives async))
 
 
@@ -1621,11 +1621,11 @@ SEEN is used internally to detect infinite recursion."
             ;; we re-add it (along with its dependencies) at an earlier place
             ;; below (bug#16994).
             (if (memq already seen)     ;Avoid inf-loop on dependency cycles.
-                (message "Dependency cycle going through %S"
+                (message "Dependency cycle going through %S."
                          (package-desc-full-name already))
               (setq packages (delq already packages))
               (setq already nil))
-          (error "Need package `%s-%s', but only %s is being installed"
+          (error "Need package `%s-%s', but only %s is being installed."
                  next-pkg (package-version-join next-version)
                  (package-version-join (package-desc-version already)))))
       (cond
@@ -1654,20 +1654,20 @@ SEEN is used internally to detect infinite recursion."
                   (setq problem
                         (if (stringp disabled)
                             (format-message
-                             "Package `%s' held at version %s, but version %s required"
+                             "Package `%s' held at version %s, but version %s required."
                              next-pkg disabled
                              (package-version-join next-version))
-                          (format-message "Required package `%s' is disabled"
+                          (format-message "Required package `%s' is disabled."
                                           next-pkg)))))
                (t (setq found pkg-desc)))))
           (unless found
             (cond
              (problem (error "%s" problem))
              (found-something
-              (error "Need package `%s-%s', but only %s is available"
+              (error "Need package `%s-%s', but only %s is available."
                      next-pkg (package-version-join next-version)
                      found-something))
-             (t (error "Package `%s-%s' is unavailable"
+             (t (error "Package `%s-%s' is unavailable."
                        next-pkg (package-version-join next-version)))))
           (setq packages
                 (package-compute-transaction (cons found packages)
@@ -1806,7 +1806,7 @@ if all the in-between dependencies are also in PACKAGE-LIST."
   "Download and install a tar package."
   ;; This won't happen, unless the archive is doing something wrong.
   (when (eq (package-desc-kind pkg-desc) 'dir)
-    (error "Can't install directory package from archive"))
+    (error "Can't install directory package from archive."))
   (let* ((location (package-archive-base pkg-desc))
          (file (concat (package-desc-full-name pkg-desc)
                        (package-desc-suffix pkg-desc))))
@@ -1971,7 +1971,7 @@ to install it but still mark it as selected."
                                                  (package-desc-reqs pkg)))
                 (package-compute-transaction () (list (list pkg))))))
         (package-download-transaction transaction)
-      (message "`%s' is already installed" name))))
+      (message "`%s' is already installed." name))))
 
 (defun package-strip-rcs-id (str)
   "Strip RCS version ID from the version string STR.
@@ -2047,22 +2047,22 @@ If some packages are not installed propose to install them."
   ;; using here, because the outcome is the same either way (nothing
   ;; gets installed).
   (if (not package-selected-packages)
-      (message "`package-selected-packages' is empty, nothing to install")
+      (message "`package-selected-packages' is empty, nothing to install.")
     (let* ((not-installed (seq-remove #'package-installed-p package-selected-packages))
            (available (seq-filter (lambda (p) (assq p package-archive-contents)) not-installed))
            (difference (- (length not-installed) (length available))))
       (cond
        (available
         (when (y-or-n-p
-               (format "%s packages will be installed:\n%s, proceed?"
+               (format "Number of packages that will be installed: %s.\n%s, proceed?"
                        (length available)
                        (mapconcat #'symbol-name available ", ")))
           (mapc (lambda (p) (package-install p 'dont-select)) available)))
        ((> difference 0)
-        (message "%s packages are not available (the rest already installed), maybe you need to `M-x package-refresh-contents'"
+        (message "Number of packages that are not available: %s. The rest is already installed. Consider `M-x package-refresh-contents'."
                  difference))
        (t
-        (message "All your packages are already installed"))))))
+        (message "All your packages are already installed."))))))
 
 
 ;;; Package Deletion
@@ -2116,13 +2116,13 @@ If NOSAVE is non-nil, the package is not removed from
                                   (expand-file-name package-user-dir))
                                  (expand-file-name dir)))
            ;; Don't delete "system" packages.
-           (error "Package `%s' is a system package, not deleting"
+           (error "Package `%s' is a system package, not deleting."
                   (package-desc-full-name pkg-desc)))
           ((and (null force)
                 (setq pkg-used-elsewhere-by
                       (package--used-elsewhere-p pkg-desc)))
            ;; Don't delete packages used as dependency elsewhere.
-           (error "Package `%s' is used by `%s' as dependency, not deleting"
+           (error "Package `%s' is used by `%s' as dependency, not deleting."
                   (package-desc-full-name pkg-desc)
                   (package-desc-name pkg-used-elsewhere-by)))
           (t
@@ -2171,13 +2171,13 @@ will be deleted."
     (let ((removable (package--removable-packages)))
       (if removable
           (when (y-or-n-p
-                 (format "%s packages will be deleted:\n%s, proceed? "
+                 (format "Number of packages that will be deleted: %s.\n%s, proceed? "
                    (length removable)
                    (mapconcat #'symbol-name removable ", ")))
             (mapc (lambda (p)
                     (package-delete (cadr (assq p package-alist)) t))
                   removable))
-        (message "Nothing to autoremove")))))
+        (message "Nothing to autoremove.")))))
 
 
 ;;;; Package description buffer.
@@ -2207,7 +2207,7 @@ will be deleted."
                                                         (symbol-name guess)))))
          (list (intern val))))))
   (if (not (or (package-desc-p package) (and package (symbolp package))))
-      (message "No package specified")
+      (message "No packages specified.")
     (help-setup-xref (list #'describe-package package)
                      (called-interactively-p 'interactive))
     (with-help-window (help-buffer)
@@ -2232,6 +2232,7 @@ Otherwise no newline is inserted."
 
 (declare-function lm-commentary "lisp-mnt" (&optional file))
 
+;; TODO -> prin1 / princ
 (defun describe-package-1 (pkg)
   (require 'lisp-mnt)
   (let* ((desc (or
@@ -2265,6 +2266,7 @@ Otherwise no newline is inserted."
     (princ status)
     (princ " package.\n\n")
 
+    ;; TODO -> insert
     (package--print-help-section "Status")
     (cond (built-in
            (insert (propertize (capitalize status)
@@ -2641,12 +2643,12 @@ Installed obsolete packages are always displayed.")
   "Toggle visibility of obsolete available packages."
   (interactive)
   (unless (derived-mode-p 'package-menu-mode)
-    (user-error "The current buffer is not a Package Menu"))
+    (user-error "The current buffer is not a Package Menu."))
   (setq package-menu--hide-packages
         (not package-menu--hide-packages))
-  (message "%s packages" (if package-menu--hide-packages
-                             "Hiding obsolete or unwanted"
-                           "Displaying all"))
+  (if package-menu--hide-packages
+      (message "Hiding obsolete or unwanted packages.")
+                  (message "Displaying all packages."))
   (revert-buffer nil 'no-confirm))
 
 (defun package--remove-hidden (pkg-list)
@@ -2947,7 +2949,7 @@ This fetches the contents of each archive specified in
 `package-archives', and then refreshes the package menu."
   (interactive)
   (unless (derived-mode-p 'package-menu-mode)
-    (user-error "The current buffer is not a Package Menu"))
+    (user-error "The current buffer is not a Package Menu."))
   (setq package-menu--old-archive-contents package-archive-contents)
   (setq package-menu--new-package-list nil)
   (package-refresh-contents package-menu-async))
@@ -2969,11 +2971,10 @@ If optional arg BUTTON is non-nil, describe its associated package."
     (let ((hidden
            (cl-remove-if-not (lambda (e) (string-match re (symbol-name (car e))))
                              package-archive-contents)))
-      (message (substitute-command-keys
-                (concat "Hiding %s packages, type `\\[package-menu-toggle-hiding]'"
-                        " to toggle or `\\[customize-variable] RET package-hidden-regexps'"
-                        " to customize it"))
-        (length hidden)))))
+      (message "Number of packages to hide: %s, type %s to toggle or %s to customize it."
+               (length hidden)
+               (substitute-command-key "`\\[package-menu-toggle-hiding]'")
+               (substitute-command-key "`\\[customize-variable] RET package-hidden-regexps'" )))))
 
 (defun package-menu-describe-package (&optional button)
   "Describe the current package.
@@ -2983,7 +2984,7 @@ If optional arg BUTTON is non-nil, describe its associated package."
                     (tabulated-list-get-id))))
     (if pkg-desc
         (describe-package pkg-desc)
-      (user-error "No package here"))))
+      (user-error "No package here."))))
 
 ;; fixme numeric argument
 (defun package-menu-mark-delete (&optional _num)
@@ -3104,7 +3105,7 @@ consideration."
   "Mark all upgradable packages in the Package Menu.
 Implementation of `package-menu-mark-upgrades'."
   (unless (derived-mode-p 'package-menu-mode)
-    (error "The current buffer is not a Package Menu"))
+    (error "The current buffer is not a Package Menu."))
   (setq package-menu--mark-upgrades-pending nil)
   (let ((upgrades (package-menu--find-upgrades)))
     (if (null upgrades)
@@ -3121,9 +3122,8 @@ Implementation of `package-menu-mark-upgrades'."
                    (package-menu-mark-install))
                   (t
                    (package-menu-mark-delete))))))
-      (message "%d package%s marked for upgrading."
-        (length upgrades)
-        (if (= (length upgrades) 1) "" "s")))))
+      (message "Number of packages marked for upgrading: %d."
+        (length upgrades)))))
 
 (defun package-menu-mark-upgrades ()
   "Mark all upgradable packages in the Package Menu.
@@ -3141,22 +3141,6 @@ immediately."
     (setq package-menu--mark-upgrades-pending t)
     (message "Waiting for refresh to finish...")))
 
-(defun package-menu--list-to-prompt (packages)
-  "Return a string listing PACKAGES that's usable in a prompt.
-PACKAGES is a list of `package-desc' objects.
-Formats the returned string to be usable in a minibuffer
-prompt (see `package-menu--prompt-transaction-p')."
-  (cond
-   ;; None
-   ((not packages) "")
-   ;; More than 1
-   ((cdr packages)
-    (format "these %d packages (%s)"
-      (length packages)
-      (mapconcat #'package-desc-full-name packages ", ")))
-   ;; Exactly 1
-   (t (format-message "package `%s'"
-                      (package-desc-full-name (car packages))))))
 
 (defun package-menu--prompt-transaction-p (delete install upgrade)
   "Prompt the user about DELETE, INSTALL, and UPGRADE.
@@ -3164,16 +3148,19 @@ DELETE, INSTALL, and UPGRADE are lists of `package-desc' objects.
 Either may be nil, but not all."
   (y-or-n-p
    (concat
-    (when delete "Delete ")
-    (package-menu--list-to-prompt delete)
-    (when (and delete install)
-      (if upgrade "; " "; and "))
-    (when install "Install ")
-    (package-menu--list-to-prompt install)
-    (when (and upgrade (or install delete)) "; and ")
-    (when upgrade "Upgrade ")
-    (package-menu--list-to-prompt upgrade)
-    "? ")))
+    (when delete
+    (format-message "Number of packages to delete: %d (%s).\n"
+      (length delete)
+      (mapconcat #'package-desc-full-name delete ", ")))
+    (when install
+    (format-message "Number of packages to install: %d (%s).\n"
+      (length install)
+      (mapconcat #'package-desc-full-name install ", ")))
+    (when upgrade
+    (format-message "Number of packages to upgrade: %d (%s).\n"
+      (length upgrade)
+      (mapconcat #'package-desc-full-name upgrade ", ")))
+    "Do you want to proceed? ")))
 
 (defun package-menu--partition-transaction (install delete)
   "Return an alist describing an INSTALL DELETE transaction.
@@ -3211,7 +3198,7 @@ objects removed."
       (condition-case-unless-debug err
           (let ((inhibit-message package-menu-async))
             (package-delete elt nil 'nosave))
-        (error (message "Error trying to delete `%s': %S"
+        (error (message "Error trying to delete `%s': %S."
                  (package-desc-full-name elt)
                  err))))))
 
@@ -3237,7 +3224,7 @@ packages marked for deletion are removed.
 Optional argument NOQUERY non-nil means do not ask the user to confirm."
   (interactive)
   (unless (derived-mode-p 'package-menu-mode)
-    (error "The current buffer is not in Package Menu mode"))
+    (error "The current buffer is not in Package Menu mode."))
   (let (install-list delete-list cmd pkg-desc)
     (save-excursion
       (goto-char (point-min))
@@ -3252,30 +3239,26 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm."
                  (push pkg-desc install-list))))
         (forward-line)))
     (unless (or delete-list install-list)
-      (user-error "No operations specified"))
+      (user-error "No operations specified."))
     (let-alist (package-menu--partition-transaction install-list delete-list)
       (when (or noquery
                 (package-menu--prompt-transaction-p .delete .install .upgrade))
-        (let ((message-template
-               (concat "Package menu: Operation %s ["
-                       (when .delete  (format "Delet__ %s" (length .delete)))
-                       (when (and .delete .install) "; ")
-                       (when .install (format "Install__ %s" (length .install)))
-                       (when (and .upgrade (or .install .delete)) "; ")
-                       (when .upgrade (format "Upgrad__ %s" (length .upgrade)))
-                       "]")))
-          (message (replace-regexp-in-string "__" "ing" message-template) "started")
+          (message "Package menu operation started: [deleting %s; installing %s; upgrading %s]. "
+	       (length .delete)
+	       (length .install)
+	       (length .upgrade))
           ;; Packages being upgraded are not marked as selected.
           (package--update-selected-packages .install .delete)
           (package-menu--perform-transaction install-list delete-list)
           (when package-selected-packages
             (if-let ((removable (package--removable-packages)))
-                (message "Package menu: Operation finished.  %d packages %s"
+                (message "Package menu operation completed. Number of packages no longer needed: %d. Type %s for removal."
                   (length removable)
-                  (substitute-command-keys
-                   "are no longer needed, type `\\[package-autoremove]' to remove them"))
-              (message (replace-regexp-in-string "__" "ed" message-template)
-                "finished"))))))))
+                  (substitute-command-keys "`\\[package-autoremove]'"))
+              (message "Package menu operation completed: [deleted %s; installed %s; upgraded %s]. "
+	       (length .delete)
+	       (length .install)
+	       (length .upgrade))))))))
 
 (defun package-menu--version-predicate (A B)
   (let ((vA (or (aref (cadr A) 1)  '(0)))
@@ -3342,11 +3325,9 @@ Store this list in `package-menu--new-package-list'."
 (defun package-menu--find-and-notify-upgrades ()
   "Notify the user of upgradable packages."
   (when-let ((upgrades (package-menu--find-upgrades)))
-    (message "%d package%s can be upgraded; type `%s' to mark %s for upgrading."
+    (message "Number of packages that can be upgraded: %d. Type `%s' to mark for upgrading."
       (length upgrades)
-      (if (= (length upgrades) 1) "" "s")
-      (substitute-command-keys "\\[package-menu-mark-upgrades]")
-      (if (= (length upgrades) 1) "it" "them"))))
+      (substitute-command-keys "\\[package-menu-mark-upgrades]"))))
 
 (defun package-menu--post-refresh ()
   "If there's a *Packages* buffer, revert it and check for new packages and upgrades.
