"
  (with-temp-buffer
    (or
     ;; Don't bother checking again.
     po-msgfmt-version-checked

     (and
      ;; Make sure 'msgfmt' is available.
      (condition-case nil
          (call-process po-msgfmt-program
                        nil t nil "--verbose" "--version")
        (file-error nil))

      ;; Make sure there's a version number in the output:
      ;; 0.11 or 0.10.36 or 0.19.5.1 or 0.11-pre1 or 0.16.2-pre1
      (progn (goto-char (point-min))
             (or (looking-at ".* \\([0-9]+\\)\\.\\([0-9]+\\)$")
                 (looking-at ".* \\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)$")
                 (looking-at ".* \\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)$")
                 (looking-at ".* \\([0-9]+\\)\\.\\([0-9]+\\)[-_A-Za-z0-9]+$")
                 (looking-at ".* \\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)[-_A-Za-z0-9]+$")))

      ;; Make sure the version is recent enough.
      (>= (string-to-number
           (format "%d%03d%03d"
                   (string-to-number (match-string 1))
                   (string-to-number (match-string 2))
                   (string-to-number (or (match-string 3) "0"))))
          010036)

      ;; Remember the outcome.
      (setq po-msgfmt-version-checked t))

     (error (_"'msgfmt' from GNU gettext 0.10.36 or greater is required")))))

(defun po-guess-archive-name ()
  "Return the ideal file name for this PO file in the central archives."
  (let ((filename (file-name-nondirectory buffer-file-name))
        start-of-header end-of-header package version team)
    (save-excursion
      ;; Find the PO file header entry.
      (goto-char (point-min))
      (re-search-forward po-any-msgstr-block-regexp)
      (setq start-of-header (match-beginning 0)
            end-of-header (match-end 0))
      ;; Get the package and version.
      (goto-char start-of-header)
      (if (re-search-forward "\n\
\"Project-Id-Version: \\(GNU \\|Free \\)?\\([^\n ]+\\) \\([^\n ]+\\)\\\\n\"$"
           end-of-header t)
          (setq package (match-string-no-properties 2)
                version (match-string-no-properties 3)))
      (if (or (not package) (string-equal package "PACKAGE")
              (not version) (string-equal version "VERSION"))
          (error (_"Project-Id-Version field does not have a proper value")))
      ;; File name version and Project-Id-Version must match
      (cond (;; A `filename' w/o package and version info at all
             (string-match "^[^\\.]*\\.po\\'" filename))
            (;; TP Robot compatible `filename': PACKAGE-VERSION.LL.po
             (string-match (concat (regexp-quote package)
                                   "-\\(.*\\)\\.[^\\.]*\\.po\\'") filename)
             (if (not (equal version (match-string-no-properties 1 filename)))
                 (error (_"\
Version mismatch: file name: %s; header: %s.\n\
Adjust Project-Id-Version field to match file name and try again")
                        (match-string-no-properties 1 filename) version))))
      ;; Get the team.
      (if (stringp po-team-name-to-code)
          (setq team po-team-name-to-code)
        (goto-char start-of-header)
        (if (re-search-forward "\n\
\"Language-Team: \\([^ ].*[^ ]\\) <.+@.+>\\\\n\"$"
                               end-of-header t)
            (let ((name (match-string-no-properties 1)))
              (if name
                  (let ((pair (assoc name po-team-name-to-code)))
                    (if pair
                        (setq team (cdr pair))
                      (setq team (read-string (format "\
Team name '%s' unknown.  What is the team code? "
                                                      name)))))))))
      (if (or (not team) (string-equal team "LL"))
          (error (_"Language-Team field does not have a proper value")))
      ;; Compose the name.
      (concat package "-" version "." team ".po"))))

(defun po-guess-team-address ()
  "Return the team address related to this PO file."
  (let (team)
    (save-excursion
      (goto-char (point-min))
      (re-search-forward po-any-msgstr-block-regexp)
      (goto-char (match-beginning 0))
      (if (re-search-forward
           "\n\"Language-Team: +\\(.*<\\(.*\\)@.*>\\)\\\\n\"$"
           (match-end 0) t)
          (setq team (match-string-no-properties 2)))
      (if (or (not team) (string-equal team "LL"))
          (error (_"Language-Team field does not have a proper value")))
      (match-string-no-properties 1))))

(defun po-send-mail ()
  "Start composing a letter, possibly including the current PO file."
  (interactive)
  (let* ((team-flag (y-or-n-p
                     (_"\
Write to your team?  ('n' if writing to the Translation Project robot) ")))
         (address (if team-flag
                      (po-guess-team-address)
                    po-translation-project-address)))
    (if (not (y-or-n-p (_"Include current PO file in mail? ")))
        (apply po-compose-mail-function address
               (read-string (_"Subject? ")) nil)
      (if (buffer-modified-p)
          (error (_"The file is not even saved, you did not validate it.")))
      (if (and (y-or-n-p (_"You validated ('V') this file, didn't you? "))
               (or (zerop po-untranslated-counter)
                   (y-or-n-p
                    (format (_"%d entries are untranslated, include anyway? ")
                            po-untranslated-counter)))
               (or (zerop po-fuzzy-counter)
                   (y-or-n-p
                    (format (_"%d entries are still fuzzy, include anyway? ")
                            po-fuzzy-counter)))
               (or (zerop po-obsolete-counter)
                   (y-or-n-p
                    (format (_"%d entries are obsolete, include anyway? ")
                            po-obsolete-counter))))
          (let ((buffer (current-buffer))
                (name (po-guess-archive-name))
                (transient-mark-mode nil)
                (coding-system-for-read buffer-file-coding-system)
                (coding-system-for-write buffer-file-coding-system))
            (apply po-compose-mail-function address
                   (if team-flag
                       (read-string (_"Subject? "))
                     (format "%s %s" po-translation-project-mail-label name))
                   nil)
            (goto-char (point-min))
            (re-search-forward
             (concat "^" (regexp-quote mail-header-separator) "\n"))
            (save-excursion
              (save-restriction
                (narrow-to-region (point) (point))
                (insert-buffer-substring buffer)
                (shell-command-on-region
                 (point-min) (point-max)
                 (concat po-gzip-uuencode-command " " name ".gz") t t)))))))
  (message ""))

(defun po-confirm-and-quit ()
  "Confirm if quit should be attempted and then, do it.
This is a failsafe.  Confirmation is asked if only the real quit would not."
  (interactive)
  (if (po-check-all-pending-edits)
      (progn
        (if (or (buffer-modified-p)
                (> po-untranslated-counter 0)
                (> po-fuzzy-counter 0)
                (> po-obsolete-counter 0)
                (y-or-n-p (_"Really quit editing this PO file? ")))
            (po-quit))
        (message ""))))

(defun po-quit ()
  "Save the PO file and kill buffer.
However, offer validation if appropriate and ask confirmation if untranslated
strings remain."
  (interactive)
  (if (po-check-all-pending-edits)
      (let ((quit t))
        ;; Offer validation of newly modified entries.
        (if (and (buffer-modified-p)
                 (not (y-or-n-p
                       (_"File was modified; skip validation step? "))))
            (progn
              (message "")
              (po-validate)
              ;; If we knew that the validation was all successful, we should
              ;; just quit.  But since we do not know yet, as the validation
              ;; might be asynchronous with PO mode commands, the safest is to
              ;; stay within PO mode, even if this implies that another
              ;; 'po-quit' command will be later required to exit for true.
              (setq quit nil)))
        ;; Offer to work on untranslated entries.
        (if (and quit
                 (or (> po-untranslated-counter 0)
                     (> po-fuzzy-counter 0)
                     (> po-obsolete-counter 0))
                 (not (y-or-n-p
                       (_"Unprocessed entries remain; quit anyway? "))))
            (progn
              (setq quit nil)
              (po-auto-select-entry)))
        ;; Clear message area.
        (message "")
        ;; Or else, kill buffers and quit for true.
        (if quit
            (progn
              (save-buffer)
              (kill-buffer (current-buffer)))))))

;;;###autoload (add-to-list 'auto-mode-alist '("\\.po[tx]?\\'\\|\\.po\\." . po-mode))
;;;###autoload (modify-coding-system-alist 'file "\\.po[tx]?\\'\\|\\.po\\." 'po-find-file-coding-system)

(provide 'po-mode)

;; Hey Emacs!
;; Local Variables:
;; indent-tabs-mode: nil
;; coding: utf-8
;; End:

;;; po-mode.el ends here
